OpenClaw ACP 集成 Cursor-Agent:解决 session/load 兼容性问题

本文摘要

# OpenClaw ACP 集成 Cursor-Agent:解决 session/load 兼...

# OpenClaw ACP 集成 Cursor-Agent:解决 session/load 兼容性问题

> 环境:OpenClaw + acpx + cursor-agent(Trae IDE 内置)

## 问题背景

OpenClaw 通过 acpx 运行时与各类 Coding Agent(Codex、Claude Code、Cursor-Agent 等)集成。当尝试集成 cursor-agent(Trae IDE 内置的编码助手)时,遇到了一个兼容性问题:

**现象:** acpx 的 `sessions ensure` 流程执行后立即失败,cursor-agent 返回 “Session not found”,acpx 以 exit code 1 退出。

## 根因分析

### acpx 的正常流程

acpx sessions ensure
    ↓
1. 启动 agent 进程
    ↓
2. 发送 initialize (JSON-RPC)
    ↓
3. 发送 session/load(传入 acpx 自己的 record ID 作为 sessionId)
    ↓
4. 开始工作...

### 问题出在第 3 步

acpx 会传入**自己管理的 session ID**,期望 agent 能加载这个 session。但 cursor-agent 的 `session/load` 只接受**自己创建的** session ID,不接受外部指定的 ID。

虽然 cursor-agent 声明支持 `loadSession`(`agentCapabilities.loadSession: true`),但它只支持加载自己创建的 session,不支持外部指定 ID 加载。

acpx: "请加载 session abc-123"
cursor-agent: "Session not found"(因为 abc-123 不是我创建的)

## 解决方案:JSON-RPC 代理

核心思路:在 acpx 和 cursor-agent 之间插入一个代理层,拦截并转换 `session/load` 请求。

### 设计原理

acpx → proxy → cursor-agent

proxy 拦截 session/load:
  - 首次调用:转为 session/new,让 cursor-agent 创建新 session,建立 ID 映射
  - 后续调用:用映射后的真实 session ID 发送真正的 session/load

### 核心实现

// cursor-agent-proxy.mjs - JSON-RPC 代理核心逻辑
import { spawn } from '\'child_process'\';
import fs from '\'fs'\';
import path from '\'path'\';

const MAP_DIR = '\'/tmp/acpx-cursor-session-map'\';

// 启动真正的 cursor-agent 进程
const agent = spawn('\'cursor-agent'\', ['\'--stdio'\'], { stdio: ['\'pipe'\', '\'pipe'\', '\'pipe'\'] });

// ID 映射管理
function loadMapping(acpxId) {
  const file = path.join(MAP_DIR, `${acpxId}.json`);
  if (fs.existsSync(file)) return JSON.parse(fs.readFileSync(file));
  return null;
}

function saveMapping(acpxId, realId) {
  fs.mkdirSync(MAP_DIR, { recursive: true });
  fs.writeFileSync(path.join(MAP_DIR, `${acpxId}.json`), JSON.stringify({ realSessionId: realId }));
}

// 拦截并转发 JSON-RPC 消息
function handleMessage(request) {
  if (request.method === '\'session/load'\') {
    const acpxSessionId = request.params.sessionId;
    const mapping = loadMapping(acpxSessionId);

    if (mapping) {
      // 已有映射:替换为真实 ID 后转发
      request.params.sessionId = mapping.realSessionId;
      return forwardToAgent(request);
    } else {
      // 首次:转为 session/new 创建新 session
      const newRequest = { ...request, method: '\'session/new'\', params: {} };
      const response = await sendToAgent(newRequest);
      if (response.result?.sessionId) {
        saveMapping(acpxSessionId, response.result.sessionId);
      }
      return response;
    }
  }
  return forwardToAgent(request);
}

### 配置方式

在 acpx 配置中,将 cursor-agent 的启动命令指向代理脚本:

{
  "agents": {
    "cursor-agent": {
      "command": "node /path/to/cursor-agent-proxy.mjs",
      "args": []
    }
  }
}

OpenClaw 的 `openclaw.json` 中也需要将 cursor-agent 加入 `acp.allowedAgents`:

{
  "acp": {
    "enabled": true,
    "backend": "acpx",
    "allowedAgents": ["codex", "claude", "gemini", "cursor-agent"]
  }
}

## Session 映射机制

映射存储在本地文件系统中:

/tmp/acpx-cursor-session-map/
├── abc-123-def.json    # acpx session ID → cursor-agent 真实 session ID
├── xyz-456-uvw.json
└── ...

每个映射文件格式:

{
  "realSessionId": "cursor-agent-generated-session-id"
}

这种设计确保:
– **重启安全**:映射持久化在磁盘上,进程重启不丢失
– **并发安全**:每个 session 独立文件,无锁竞争
– **调试友好**:直接查看 JSON 文件即可排查问题

## 支持的模型

从 cursor-agent 的 `initialize` 响应中获取到的模型列表:

| 模型 | 提供商 |
|——|——–|
| composer-2, composer-1.5 | Cursor 自研 |
| gpt-5.3-codex, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano, gpt-5.2 | OpenAI |
| claude-sonnet-4-6, claude-opus-4-6, claude-opus-4-5, claude-haiku-4-5 | Anthropic |
| gemini-3.1-pro | Google |
| grok-4-20 | xAI |
| kimi-k2.5 | Moonshot |

## 当前状态与已知问题

| 测试项 | 结果 |
|——–|——|
| JSON-RPC 直接测试 proxy | ✅ 成功 |
| acpx sessions ensure 通过 proxy | ⚠️ 超时(排查中) |
| OpenClaw sessions_spawn | ⏳ 待完成 |

### 已知问题

1. **acpx sessions ensure 超时**:可能是代理的 stdin 关闭时机不对,或 ensure 流程中 prompt 子命令的交互问题。需要进一步排查代理与 acpx 的交互协议。

2. **替代方案**:直接修改 acpx 源码,在检测到 cursor-agent 时自动将 `session/load` 转为 `session/new`(侵入性更大,但更可靠)。

## 总结

| 要点 | 说明 |
|——|——|
| 问题本质 | acpx 与 cursor-agent 对 session/load 的 ID 来源理解不一致 |
| 解决思路 | 插入 JSON-RPC 代理层,做 session ID 映射 |
| 映射机制 | 本地文件系统存储,重启安全、并发安全 |
| 当前状态 | 基础代理已验证,acpx 集成待完善 |
| 适用场景 | 任何声明支持 loadSession 但不接受外部 ID 的 ACP Agent |

0 0 投票数
文章评级
订阅评论
提醒
guest

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

0 评论
最多投票
最新 最旧
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x