更新时间:2026-04-17 GMT+08:00
分享

Hooks

通过Hook(钩子),您可以在华为云码道IDE及插件的关键生命周期节点中插入自定义逻辑,实现功能扩展,而无需更改任何现有代码。

与依赖模型理解的Prompt指令不同,Hooks的执行是确定性的,即一旦事件被触发,绑定的脚本将稳定、可靠地执行,不受模型理解偏差的影响。

约束与限制

表1 约束限制

限制类别

具体限制

功能限制

当前Hook脚本不支持实时加载,需要重新加载才可使用。

语言限制

Hook脚本仅支持JavaScript/TypeScript语言。

外部依赖

如果使用外部依赖包,您需要在Hook所在的配置目录创建package.json文件,并声明需要使用的依赖。

支持的Hook事件

表2 支持的Hook事件

事件分类

事件名称

触发时机

可阻断

典型使用场景

说明

聊天消息

chat.message

用户发送消息后、进入处理流程前

聊天消息处理

收到新消息时触发,可修改消息内容和parts

聊天参数

chat.params

每次调用LLM前,修改请求参数(temperature、topP、topK等)

聊天参数修改

调用LLM前修改参数(temperature、topP、topK等)

聊天请求头

chat.headers

每次调用LLM前,修改HTTP请求头

聊天请求头修改

调用LLM前修改请求头

聊天响应

chat.response

LLM返回响应后,记录响应详情(tokens、cost、duration等)

聊天压缩记录

记录聊天压缩事件,记录压缩前后的tokens

聊天错误

chat.error

LLM调用发生错误时

聊天结束记录

记录聊天结束事件,包含运行ID、tokens消耗等

聊天压缩

chat.compression

上下文压缩时,记录压缩前后的tokens数量

用户审批记录

记录用户是否同意某操作

聊天结束

chat.finished

聊天会话结束时,记录本次运行的tokens消耗和运行信息

Turn结束记录

记录每个turn结束日志,包含持续时间、终止原因等

用户审批

user.approval

需要用户确认/审批操作时

聊天响应记录

记录LLM响应日志,包含finishReason、tokens、cost等

Turn结束

turn.end

每个对话轮次结束时,记录持续时间、终止原因等

聊天错误记录

记录调用LLM错误日志

命令执行

command.execute.before

命令执行前,可修改命令的parts

权限请求处理

处理权限请求,可设置允许、拒绝、询问

工具执行

tool.execute.before

工具执行前,可修改工具参数args

命令执行前

命令执行前触发,可修改parts

工具执行

tool.execute.after

工具执行后,可修改返回的title、output、metadata

工具执行前

工具执行前触发,可修改参数args

工具定义

tool.definition

工具定义发送给LLM前,可修改描述和参数

工具执行后

工具执行后触发,可修改返回的title、output、metadata

Shell环境

shell.env

获取Shell环境变量时,可添加或修改环境变量

Shell环境变量

获取或修改Shell环境变量

权限请求

permission.ask

需要权限验证时,可设置allow/deny/ask

消息转换

转换聊天消息列表

消息转换

experimental.chat.messages.transform

消息列表发送给LLM前,可自定义转换

系统消息转换

转换系统消息

系统消息转换

experimental.chat.system.transform

系统提示词发送前,可自定义转换

会话压缩

会话压缩前触发,可自定义压缩提示词

会话压缩

experimental.session.compacting

上下文压缩开始前,可自定义压缩提示词

文本完成

文本补全完成时触发

文本补全

experimental.text.complete

文本补全完成时,可修改输出文本

工具定义修改

修改工具定义(描述和参数)

配置加载

config

应用启动配置加载时

配置加载

配置加载时触发

通用事件

event

订阅所有Bus事件时触发

事件处理

通用事件处理

插件及依赖文件存放路径

插件是一个JavaScript/TypeScript模块,通过导出插件函数来工作。每个函数接收一个上下文对象,并返回对应的Hook对象。如果插件文件中需要使用外部包,必须在配置目录中创建package.json文件并配置所需的依赖项。华为云码道在启动时会自动安装这些依赖项。

表3 插件文件加载路径

插件类型

插件文件存放路径

插件依赖文件存放路径

说明

项目级

当前项目根目录./.codeartsdoer/plugin或./.codeartsdoer/plugins

当前项目根目录./.codeartsdoer/

仅对当前项目有效。

个人级

本地~/.codeartsdoer/plugin或

./.codeartsdoer/plugins

本地~/.codeartsdoer/

对当前用户下所有项目均有效。

快速入门

以下通过一个简单示例,演示如何对用户输入中的密码、密钥等敏感信息进行过滤,有效防止数据泄露。

  1. 创建插件文件存放目录。项目根目录“./.codeartsdoer”下新建一个目录plugin。

    图1 新建plugin目录

  2. 创建脚本。在plugin目录下,新建文件sensitiveInfoFilteringPlugin.ts,在插件文件中编写Hook逻辑代码,并保存文件。

    //导入Plugin类型,用于定义插件
    import type { Plugin } from "@opencode-ai/plugin"
    
    //导出插件实现,Plugin是一个异步函数,接收插件输入参数并返回Hooks对象
    export const SensitiveInfoFilteringPlugin: Plugin = async ({}) => {
      //返回一个Hooks对象,包含各种钩子函数
      return {
        //监听工具执行后的钩子,在工具执行完成后触发
        "tool.execute.after": async (
          //输入参数:包含工具名称、会话ID、调用ID、推理ID等信息
          input: { tool: string; sessionID: string; callID: string; args: any },
          //输出参数:包含工具执行结果的标题、输出内容、元数据
          output: {
            title: string
            output: string
            metadata: any
          },
        ) => {
          //判断是否为读取文件操作(tool 名称为 "read")且输出内容存在
          if (input.tool === "read" && output.output) {
            //敏感信息匹配模式(支持JSON和其他常见格式)
            //匹配"password": "value"或password: value格式
            //第一个正则:匹配JSON 格式,如 "password": "123456"
            //第二个正则:匹配普通键值对格式,如password=123456或password:123456
            const sensitivePatterns = [
              //匹配JSON格式的敏感字段:双引号包裹的键名 + 冒号 + 双引号包裹的值
              /"(password|passwd|pwd|api[_-]?key|secret|token|密钥|密码)"\s*:\s*"([^"]+)"/g,
              //匹配普通格式的敏感字段:键名 + 冒号或等号 + 不带引号的值
              /(password|passwd|pwd|api[_-]?key|secret|token)\s*[:=]\s*([^"'\\\s]+)/gi,
            ]
            //将工具输出的内容赋值给局部变量content,方便后续处理
            let content = output.output
    
            //遍历所有敏感信息匹配模式,逐一进行替换处理
            for (const pattern of sensitivePatterns) {
              //使用replace方法进行替换,传入回调函数处理匹配结果
              //match:完整匹配的字符串
              //key:捕获组1,即敏感字段名(password、api_key等)
              //value:捕获组2,即敏感字段的值(如密码、密钥的實際内容)
              content = content.replace(pattern, (match, key, value) => {
                //如果匹配到敏感信息,将实际值替换为[敏感信息]占位符
                return match.replace(value, "[敏感信息]")
              })
            }
            //更新output对象中的output字段,将过滤后的内容写回
            output.output = content
          }
        }
      }
    }

  3. 重启IDE。

    在华为云码道IDE工具左上角,单击“文件(F)”,选择“重启IDE”。因为当前Hook脚本不支持实时加载,所以需要重新启动IDE,脚本才可以正常使用。

  4. 验证效果。

    在输入框中输入指令后,模型返回的结果中敏感信息已自动脱敏。

    图2 模型返回效果

创建Hooks

  1. 选择对应的事件请根据实际业务需求,从支持的Hook事件中匹配并选择对应的事件名称。
  2. 编写Hook脚本。

    1. 创建插件文件。

      插件及依赖文件存放路径目录下,新建“.ts”“.js”文件。

    2. 编写Hook逻辑。

      Hook事件参考内容中,找到“// Hook implementations go here”注释位置,并在此处根据实际需求编写具体的Hook实现代码。

  3. (可选)配置依赖。如果插件文件中需要使用外部包,必须在插件及依赖文件存放路径的配置目录中创建package.json文件并配置所需的依赖项。

    {
      "dependencies": {
        "依赖包名1": "版本号",
        "依赖包名2": "版本号"
      }
    }

    package.json文件具体示例如下:

    {
      "dependencies": {
        "@opencode-ai/plugin": "*",
        "@aws-sdk/client-s3": "3.933.0",
        "@babel/core": "7.29.0",
        "@langfuse/otel": "4.5.1"
      }
    }

  4. 重启IDE验证效果。

Hook事件参考

支持的Hook事件示例如下。请在“// Hook implementations go here”注释处编写具体的实现逻辑,代码编写完成后即可直接使用。

场景示例

“删除文件前弹窗进行高危操作提示”为例,向您详细介绍如何使用Hook。本示例以创建级plugin目录为例。

  1. 根据支持的Hook事件中场景描述,选择对应的事件。

    删除文件会调用工具,一般是deleteFile工具,要在删除文件前弹窗,所以此处选择事件“tool.execute.before”

  2. 编写hook脚本。

    1. 项目根目录“./.codeartsdoer”下,新建一个目录plugin。
      图3 创建plugin目录
    2. 在plugin目录下,新建文件deleteFileHintPlugin.ts。
      图4 新建deleteFileHintPlugin.ts文件
    3. 编写脚本,并保存文件。
      //导入OpenCode插件类型定义
      import type {Plugin} from "@opencode-ai/plugin";
      //导入Node.js子进程模块,用于执行系统命令
      import { exec } from "child_process";
      //导入util模块的promisify函数,用于将回调式函数转为Promise
      import { promisify } from "util";
      //将exec回调函数转换为Promise形式的异步函数
      const execAsync = promisify(exec);
      //定义并导出插件,接收client参数(用于与OpenCode交互)
      export const DeleteFileHintPlugin: Plugin = async ({ client }) => {
        //返回插件的hook集合
        return {
          //监听工具执行前的钩子
          "tool.execute.before": async (
            //输入参数:工具名称、会话ID、调用ID、推理ID
            input: { tool: string; sessionID: string; callID: string; inferenceID?: string },
            //输出参数:工具调用时的参数
            output: { args: any }
          ) => {
            // 判断是否为删除文件操作
            if (input.tool === "deleteFile") {
              //定义弹出警告框的消息内容
              const message = `删除文件是高危操作,请谨慎执行!`
              //根据不同操作系统执行不同的命令
              if (process.platform === "win32") {
                //Windows系统:使用PowerShell调用系统MessageBox
                const cmd = `powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${message}', '警告', 'OK', 'Warning')"`
                await execAsync(cmd)
              } else if (process.platform === "darwin") {
                //macOS系统:使用osascript调用系统弹窗
                const cmd = `osascript -e 'display alert "警告" message "${message}"'`
                await execAsync(cmd)
              } else if (process.platform === "linux") {
                //Linux系统:使用notify-send发送桌面通知
                const cmd = `notify-send "警告" "${message}"`
                await execAsync(cmd)
              }
            }
          }
        }
      }

  3. 重启IDE验证效果。

    1. 在华为云码道IDE工具左上角,单击“文件(F)”,选择“重启IDE”。因为当前Hook脚本不支持实时加载,所以需要重新启动IDE,脚本才可以正常使用。
    2. 在输入框中输入“删除文件***,客户端会弹出预警窗口。
      其中,***为待删除文件的名称。
      图5 出现预警窗口

相关文档