Metadata-Version: 2.5
Name: huaweicloud-opentelemetry-instrumentation-opencode
Version: 1.0.0
Summary: Huawei Cloud OpenCode Metrics instrumentation (TypeScript probe)
License-Expression: Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# OpenCode Metrics 插件部署指南（新节点）

> **适用场景**：将构建好的插件部署到一台**没有插件源码**的全新 OpenCode 节点。
> 只需复制构建产物 + 配置文件即可，新节点不需要 TypeScript 源码、不需要 npm 构建。
>
> **两种部署路径**（任选其一）：
> - **路径 A（推荐）**：获取 whl 包 → `pip install` → `install.py` 一键部署
> - **路径 B**：直接获取 `plugin.mjs` + `package.json` + `config.json` → 手动放置到对应目录

---

## 1. 部署文件清单

部署只需 **4 类文件**：

| #  | 文件 | 位置（新节点） | 说明 | 是否必需 |
|----|------|--------------|------|---------|
| 1  | `plugin.mjs` | `~/.opencode/plugins/opencode-metrics/` | 插件主程序（esbuild 打包，**零外部依赖**） | ✅ 必需 |
| 2  | `package.json` | 同上，与 plugin.mjs 必须在同一个目录下 | 插件元数据（name / main / type） | ✅ 必需 |
| 3  | `config.json` | `~/.opencode-metrics/` | 插件配置（含 OTel 上报参数）。若获取到的是 `config.example.json`，改完配置后改名为 `config.json` | ✅ 必需（否则用默认值，但不含 token） |
| 4  | `opencode.json` 注册 | `~/.config/opencode/opencode.json`（Windows：`<用户主目录>\.config\opencode\opencode.json`） | OpenCode 加载插件入口（OpenCode 安装后自动生成，只需追加 plugin 配置） | ✅ 必需（配置引用） |

> **关键点**：`plugin.mjs` 是 esbuild 单文件打包产物，OpenTelemetry SDK 等所有依赖都已内嵌，新节点**无需安装任何 npm 包**。

---

## 2. 目录结构（新节点部署后）

```
~/.config/opencode/
└── opencode.json                     ← OpenCode 主配置（OpenCode 安装后自动生成，此处追加插件注册）

~/.opencode/
└── plugins/
    └── opencode-metrics/
        ├── plugin.mjs                ← 插件主程序（自包含）
        └── package.json              ← 插件元数据

~/.opencode-metrics/                  ← 插件数据/配置根目录
├── config.json                       ← 插件配置（含 OTel 上报参数）
└── data/
    └── logs/
        └── plugin-YYYY-MM-DD.log     ← 插件运行日志（自动创建，按天滚动）
```

---

## 3. 部署路径 A：whl 包 + pip install（推荐）

### 3.1 获取 whl 并安装

```bash
# 将构建好的 whl 包复制到新节点，然后：
pip install huaweicloud-opentelemetry-instrumentation-opencode-<版本>.whl
```

> `pip install` 后，`plugin.mjs`、`config.example.json`、`scripts/install.py` 等部署文件会出现在 site-packages 的 `opencode_metrics/` 目录下。

### 3.2 运行 install.py 一键部署

`pip install` 后 install.py 位于 site-packages 的 `opencode_metrics/scripts/install.py`，直接运行：

```bash
python <site-packages路径>/opencode_metrics/scripts/install.py \
  --agent-id {{agent_id}} \
  --domain-id {{domain_id}} \
  --project-id {{project_id}} \
  --endpoint {{trace_endpoint}} \
  --token {{trace_token}} \
  --aom-endpoint {{metric_endpoint}} \
  --aom-access-code {{metric_token}} \
  --aom-prometheus-id {{prom_id}} \
  --resource-type {{agent|multiagents|workflow}}
```

> 也可从仓库源码目录直接运行 `python scripts/install.py`（构建产物 `dist/plugin.mjs` 存在时）。

> `install.py` 自动完成：
> - 定位 `plugin.mjs`（site-packages/opencode_metrics/packages/plugin/dist/）
> - 复制 `plugin.mjs` → `~/.opencode/plugins/opencode-metrics/plugin.mjs`
> - 生成插件元数据 `package.json`（name/main/type 字段）
> - 用携带的参数值生成 `config.json`（覆盖已有）→ `~/.opencode-metrics/config.json`
> - 打印 `opencode.json` 需要追加的 plugin 配置（file:// URL 自动适配 Windows/Linux）
>
> 参数说明：`--endpoint` / `--aom-endpoint` 未带端口时自动补 `:4317`（gRPC）；`--resource-type` 必填（`agent` / `multiagents` / `workflow`，对应 `otel.resource_type`）。

### 3.3 注册插件并重启

按 `install.py` 打印的提示，将 plugin 配置追加到 `~/.config/opencode/opencode.json`（见第 5 节 5.3），然后重启 OpenCode。

---

## 4. 部署路径 B：直接放置 plugin.mjs + package.json + config.json

适用于已获取到构建产物（plugin.mjs + package.json + config.json）的情况，无需 pip install。

### 4.1 创建目录

```bash
# 插件安装目录（存放 plugin.mjs + package.json）
mkdir -p ~/.opencode/plugins/opencode-metrics
# 插件数据目录（运行时日志输出到 data/logs/plugin-YYYY-MM-DD.log）
mkdir -p ~/.opencode-metrics/data/logs
```

### 4.2 放置文件

```bash
# 插件主程序（esbuild 单文件，自包含全部依赖）
cp plugin.mjs ~/.opencode/plugins/opencode-metrics/
# 插件元数据（OpenCode 通过它识别插件，main 字段必须与 plugin.mjs 同名）
cp package.json ~/.opencode/plugins/opencode-metrics/

# 插件配置（含 OTel 上报参数，见第 6 节；需按实际环境修改 resource_id/token 等）
cp config.json ~/.opencode-metrics/
```

> 若获取到的是 `config.example.json`，改完配置后改名为 `config.json` 再放置。

### 4.3 在 opencode.json 中注册插件

**opencode.json 的位置**：OpenCode 安装后会自动生成，位于用户配置目录：

| 系统 | 路径 |
|------|------|
| Windows | `<用户主目录>\.config\opencode\opencode.json` |
| macOS/Linux | `~/.config/opencode/opencode.json` |

> 注意：这是 **`~/.config/opencode/`**（OpenCode 的全局配置目录），不是 `~/.opencode/`（插件目录）。

**步骤 1**：确认 opencode.json 是否存在
```bash
# Windows：列出该文件（存在则显示路径，不存在报错）
dir C:\Users\<用户名>\.config\opencode\opencode.json
# macOS/Linux：同上（ls 列出文件，找不到则无输出）
ls ~/.config/opencode/opencode.json
```

**步骤 2**：若文件不存在，创建目录和空文件：
```bash
mkdir -p ~/.config/opencode
```

**步骤 3**：编辑 opencode.json，加入 `plugin` 数组（追加到已有配置中，不要覆盖其他字段）：

```json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    "file://C:/Users/<用户名>/.opencode/plugins/opencode-metrics/plugin.mjs"
  ]
}
```

**路径格式说明**：
- **Windows**：`file://C:/Users/...`（正斜杠，盘符后无额外斜杠）
- **macOS/Linux**：`file:///Users/<用户名>/.opencode/plugins/opencode-metrics/plugin.mjs`（三个斜杠）

### 4.4 重启 OpenCode

重启后插件自动加载。验证方式见第 7 节。

---

## 5. 两条路径的部署产物一致性

无论走路径 A（whl + install.py）还是路径 B（直接放置），**最终新节点上的文件布局完全一致**（见第 2 节目录结构）：

- `~/.opencode/plugins/opencode-metrics/plugin.mjs` + `package.json`
- `~/.opencode-metrics/config.json`
- `~/.config/opencode/opencode.json` 中追加 plugin 注册

路径 A 的 `install.py` 本质是自动完成路径 B 的复制 + config 生成 + 注册提示；路径 B 适合手动控制文件来源的场景。

---

## 6. 配置文件说明（config.json）

### 6.1 完整配置模板

> 本模板与仓库中的 `config.example.json` 一致，支持 `//` 注释（JSONC 格式，插件会自动剥离注释后解析）。部署时复制此模板，把占位符替换为实际值。

```json
{
  "version": "3.0.0",
  // 插件总开关
  "enabled": true,
  // 日志输出目录。 目录路径兼容多种写法：/d/data/example（Git Bash 风格）、D:/data/example、D:\\data\\example 均可识别
  "outputDir": "/d/codezone",
  // 用户 ID（注入 user.id）：为空/不设置则兜底主机名上报
  "user.id": "",
  // 采集周期（毫秒）：每隔多久从内存缓冲采集并上报一次事件（默认 30000 = 30 秒）
  "collectInterval": 30000,
  "features": {
    "debug": false,                 // debug 日志开关：false=关闭（默认），true=开启（打印 AOM 上报属性明细）
    "captureMessageContent": true   // 是否采集 trace 输入/输出消息内容：true=展示（默认），false=不展示
  },
  // ============ OTel 上报配置（AgentArts） ============
  "otel": {
    // APM（Trace 上报）开关：true 开启，false 关闭
    "agentarts_agentops_otel_agent_apm_enable": true,
    // AOM（Metrics 上报）开关：true 开启，false 关闭
    "agentarts_agentops_otel_agent_aom_enable": true,
    // 账号/租户 ID（Wiki 必填维度 domain.id）
    "agent_domain_id": "<AGENT_DOMAIN_ID>",
    // AgentArts 项目 ID
    "agentarts_project_id": "<AGENTARTS_PROJECT_ID>",
    // 智能体 ID（AgentArts 创建接入时分配，页面图表必须绑定此值才能看到数据）
    "agent_resource_id": "<AGENT_RESOURCE_ID>",
    // 资源类型：单智能体填 "agent"，多智能体 "multiagents"，工作流 "workflow"
    "resource_type": "<AGENT_TYPE>",
    // 智能体版本（对齐调用链规范 1.1；不配置则兜底 "default"）
    "resource_version": "<AGENT_VERSION>",
    // APM 上报认证 token（敏感信息，勿外泄）
    "agentarts_agentops_apm_token": "<APM_TOKEN>",
    // APM 上报端点（gRPC，端口 4317）
    "agentarts_agentops_apm_exporter_endpoint": "<APM_ENDPOINT>:4317",
    // AOM 上报认证 access code（敏感信息，勿外泄）
    "agentarts_agentops_aom_access_code": "<AOM_ACCESS_CODE>",
    // AOM 上报端点（gRPC，端口 4317）
    "agentarts_agentops_aom_exporter_endpoint": "<AOM_ENDPOINT>:4317",
    // AOM Prometheus 实例 ID
    "agentarts_agentops_aom_prometheus_id": "<AOM_PROMETHEUS_ID>"
  }
}
```

### 6.2 各字段说明

| 字段 | 必填 | 说明 |
|------|------|------|
| `version` | 是 | 配置版本号，固定 `3.0.0` |
| `enabled` | 是 | 插件总开关（false 时插件完全休眠，不采集不上报） |
| `outputDir` | 否 | 日志输出目录（日志文件 `logs/plugin-YYYY-MM-DD.log`），默认 `~/.opencode-metrics/data`。路径兼容 `~/xxx`、`/d/codezone`（Git Bash 风格）、`D:/codezone`、`D:\codezone` 多种写法 |
| `user.id` | 否 | 用户 ID（注入 `user.id`，span 与 metrics 均生效）。为空/不设置则兜底主机名（对齐 Hermes `AGENTARTS_AGENTOPS_USER_ID`） |
| `collectInterval` | 否 | 采集上报周期（ms），默认 30000（30 秒） |
| `features.debug` | 否 | debug 日志开关，默认 false；true 时打印 AOM 上报属性明细等 DEBUG 日志（排查用） |
| `features.captureMessageContent` | 否 | 是否采集 trace 输入/输出消息内容，默认 true。false 时 trace 各 span（根/LLM/工具/skill）不携带 `input.value` / `output.value` / `gen_ai.input.messages` / `gen_ai.output.messages` / `gen_ai.tool.call.arguments` / `gen_ai.tool.call.result` 等内容属性（对齐 Hermes `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=false`），其他 trace 属性与 metrics 上报不受影响 |
| `otel.agentarts_agentops_otel_agent_apm_enable` | 是 | APM（Trace）上报开关 |
| `otel.agentarts_agentops_otel_agent_aom_enable` | 是 | AOM（Metrics）上报开关 |
| `otel.agent_domain_id` | 是 | 账号 ID（租户隔离） |
| `otel.agent_resource_id` | 是 | 智能体 ID（**页面查询以此为准**） |
| `otel.resource_type` | 是 | 资源类型：`agent` / `multiagents` / `workflow` |
| `otel.resource_version` | 否 | 智能体版本（对齐调用链规范 1.1 必填属性；不配置则兜底 `default`） |
| `otel.agentarts_agentops_apm_token` | 是（APM 开时） | APM 认证 token |
| `otel.agentarts_agentops_apm_exporter_endpoint` | 是 | APM 端点（gRPC，端口 4317） |
| `otel.agentarts_agentops_aom_access_code` | 是（AOM 开时） | AOM 认证 access code |
| `otel.agentarts_agentops_aom_exporter_endpoint` | 是 | AOM 端点（gRPC，端口 4317） |
| `otel.agentarts_agentops_aom_prometheus_id` | 是（AOM 开时） | AOM Prometheus 实例 ID |
| `otel.agentarts_project_id` | 是 | AgentArts 项目 ID |

> **已废弃参数**（v3.0.0 移除 JSONL 写入与本地聚合后不再生效，配置中无需再包含）：`outputFormat`、`metrics` 块、`validation` 块、`recovery` 块、`features.integrityCheck` / `features.autoRecovery` / `features.statePersistence`。

### 6.3 重要注意事项

1. **部署时注入实际值**：`agent_resource_id`、`agent_domain_id`、`agentarts_project_id`、`apm_token`、`aom_access_code`、`aom_prometheus_id` 等均为**各环境实际分配的值**（从 AgentArts 平台接入信息获取），**不是代码/模板写死的**。`install.py` 的 9 个必填参数即注入这些实际值；若手动复制模板，需按实际环境替换占位符后重启生效。
2. **敏感信息**：`apm_token`、`aom_access_code` 只存在于 config.json 中，不会写入日志或上报数据。
3. **`agent_resource_id` 必须与 AgentArts 页面绑定的智能体 ID 一致**，否则页面查不到数据（HISTORY 中多次遇到此问题）。
4. **`outputDir` 中的用户名路径要改为新节点的实际用户名**。
5. 上报协议：APM 与 AOM 均使用 **OTLP gRPC**（端口 4317），gRPC exporter 通过 Metadata 传认证（不支持 headers）。

---

## 7. 部署验证

### 7.1 验证插件加载

重启 OpenCode 后检查：

```bash
# 列出插件日志文件（按天滚动：plugin-2026-09-23.log 等），确认日志目录已生成
ls -la ~/.opencode-metrics/data/logs/plugin-*.log
# 查看最近 20 行日志，确认插件初始化成功（无报错）
tail -20 ~/.opencode-metrics/data/logs/plugin-*.log
```

正常时日志应包含：
- `[opencode-metrics] OTel init config: {...}`（初始化）
- `[opencode-metrics] AsyncLocalStorageContextManager registered`
- `[opencode-metrics] APM (Traces) initialized`
- `[opencode-metrics] AOM (Metrics) initialized`

### 7.2 验证上报（做一轮问答后）

```bash
# 查看最近 50 行日志，确认一轮问答后事件已采集并上报
tail -50 ~/.opencode-metrics/data/logs/plugin-*.log
```

正常时日志应包含：
- `OTel processTurn: <turnId> events: N`（事件采集）
- `AOM (Metrics) export SUCCESS {totalDataPoints: N, ...}`（AOM 上报成功，**按 collectInterval，默认每 30 秒一次**）
- `APM (Traces) export SUCCESS {spanCount: N, ...}`（APM 上报成功）
- `AOM All Metric Details: {...}`（上报属性明细，**仅 debug 开启时打印**，需 `features.debug: true`）

### 7.3 常见问题

| 现象 | 可能原因 | 处理 |
|------|---------|------|
| 日志无任何输出 | 插件未加载 | 检查 opencode.json 注册路径、重启 |
| `AOM export FAILED` | token/endpoint 错误 | 核对 config.json 的 token 与端点 |
| 页面指标为 0 但日志 SUCCESS | 页面绑定 resource_id 与上报不一致 | 核对 `agent_resource_id` 与页面智能体 ID |
| 页面 Skill 数为 0 | 本次未调用 skill，或 skill 走 command 路径未采集 | 确认调用了 skill 且日志有 `skillCallCount.add(1)` |
