diff --git a/CHANGELOG.md b/CHANGELOG.md index 71f1c28e..88cb4831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Repo: https://github.com/openclaw/acpx - Agents/built-ins: bump the default Claude ACP adapter range to `@agentclientprotocol/claude-agent-acp@^0.37.0`. Thanks @trumpyla. - Runtime/embedding: surface cost, token usage breakdowns, and advertised command metadata on runtime status/events. Thanks @DaniAkash. +- Agents/built-ins: add `fast-agent` as a built-in fast-agent ACP adapter via `uvx fast-agent-mcp acp`. ### Breaking diff --git a/README.md b/README.md index 9eb16824..9fe7dc4e 100644 --- a/README.md +++ b/README.md @@ -341,24 +341,25 @@ unless `agentSessionId` is present. Built-ins: -| Agent | Adapter | Wraps | -| ---------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| `pi` | [pi-acp](https://github.com/svkozak/pi-acp) | [Pi Coding Agent](https://github.com/mariozechner/pi) | -| `openclaw` | native (`openclaw acp`) | [OpenClaw ACP bridge](https://github.com/openclaw/openclaw) | -| `codex` | [codex-acp](https://github.com/agentclientprotocol/codex-acp) | [Codex CLI](https://codex.openai.com) | -| `claude` | [claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp) | [Claude Code](https://claude.ai/code) | -| `gemini` | native (`gemini --acp`) | [Gemini CLI](https://github.com/google/gemini-cli) | -| `cursor` | native (`cursor-agent acp`) | [Cursor CLI](https://cursor.com/docs/cli/acp) | -| `copilot` | native (`copilot --acp --stdio`) | [GitHub Copilot CLI](https://docs.github.com/copilot/how-tos/copilot-chat/use-copilot-chat-in-the-command-line) | -| `droid` | native (`droid exec --output-format acp`) | [Factory Droid](https://www.factory.ai) | -| `iflow` | native (`iflow --experimental-acp`) | [iFlow CLI](https://github.com/iflow-ai/iflow-cli) | -| `kilocode` | `npx -y @kilocode/cli acp` | [Kilocode](https://kilocode.ai) | -| `kimi` | native (`kimi acp`) | [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) | -| `kiro` | native (`kiro-cli-chat acp`) | [Kiro CLI](https://kiro.dev) | -| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) | -| `qoder` | native (`qodercli --acp`) | [Qoder CLI](https://docs.qoder.com/cli/acp) | -| `qwen` | native (`qwen --acp`) | [Qwen Code](https://github.com/QwenLM/qwen-code) | -| `trae` | native (`traecli acp serve`) | [Trae CLI](https://docs.trae.cn/cli) | +| Agent | Adapter | Wraps | +| ------------ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| `pi` | [pi-acp](https://github.com/svkozak/pi-acp) | [Pi Coding Agent](https://github.com/mariozechner/pi) | +| `openclaw` | native (`openclaw acp`) | [OpenClaw ACP bridge](https://github.com/openclaw/openclaw) | +| `codex` | [codex-acp](https://github.com/agentclientprotocol/codex-acp) | [Codex CLI](https://codex.openai.com) | +| `claude` | [claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp) | [Claude Code](https://claude.ai/code) | +| `gemini` | native (`gemini --acp`) | [Gemini CLI](https://github.com/google/gemini-cli) | +| `cursor` | native (`cursor-agent acp`) | [Cursor CLI](https://cursor.com/docs/cli/acp) | +| `copilot` | native (`copilot --acp --stdio`) | [GitHub Copilot CLI](https://docs.github.com/copilot/how-tos/copilot-chat/use-copilot-chat-in-the-command-line) | +| `droid` | native (`droid exec --output-format acp`) | [Factory Droid](https://www.factory.ai) | +| `fast-agent` | `uvx fast-agent-mcp acp` | [fast-agent](https://fast-agent.ai) | +| `iflow` | native (`iflow --experimental-acp`) | [iFlow CLI](https://github.com/iflow-ai/iflow-cli) | +| `kilocode` | `npx -y @kilocode/cli acp` | [Kilocode](https://kilocode.ai) | +| `kimi` | native (`kimi acp`) | [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) | +| `kiro` | native (`kiro-cli-chat acp`) | [Kiro CLI](https://kiro.dev) | +| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) | +| `qoder` | native (`qodercli --acp`) | [Qoder CLI](https://docs.qoder.com/cli/acp) | +| `qwen` | native (`qwen --acp`) | [Qwen Code](https://github.com/QwenLM/qwen-code) | +| `trae` | native (`traecli acp serve`) | [Trae CLI](https://docs.trae.cn/cli) | `factory-droid` and `factorydroid` also resolve to the built-in `droid` adapter. diff --git a/agents/FastAgent.md b/agents/FastAgent.md new file mode 100644 index 00000000..c648b198 --- /dev/null +++ b/agents/FastAgent.md @@ -0,0 +1,9 @@ +# FastAgent + +- Built-in name: `fast-agent` +- Default command: `uvx fast-agent-mcp acp` +- Upstream: https://fast-agent.ai/acp + +`acpx fast-agent` starts fast-agent through its ACP entrypoint. It requires `uvx` on `PATH`. + +Configure model/provider settings through fast-agent environment variables, fast-agent configuration, or an `acpx` agent override with additional `fast-agent-mcp acp` arguments. diff --git a/agents/README.md b/agents/README.md index 2f543782..abc2ea8e 100644 --- a/agents/README.md +++ b/agents/README.md @@ -10,6 +10,7 @@ Built-in agents: - `cursor -> cursor-agent acp` - `copilot -> copilot --acp --stdio` - `droid -> droid exec --output-format acp` (`factory-droid` and `factorydroid` also resolve to `droid`) +- `fast-agent -> uvx fast-agent-mcp acp` - `iflow -> iflow --experimental-acp` - `kilocode -> npx -y @kilocode/cli acp` - `kimi -> kimi acp` @@ -25,6 +26,7 @@ Harness-specific docs in this directory: - [Claude](Claude.md): built-in `claude -> npx -y @agentclientprotocol/claude-agent-acp` - [Copilot](Copilot.md): built-in `copilot -> copilot --acp --stdio` - [Droid](Droid.md): built-in `droid -> droid exec --output-format acp` with `factory-droid` and `factorydroid` aliases +- [fast-agent](FastAgent.md): built-in `fast-agent -> uvx fast-agent-mcp acp` - [Cursor](Cursor.md): built-in `cursor -> cursor-agent acp` - [Gemini](Gemini.md): built-in `gemini -> gemini --acp` - [iFlow](Iflow.md): built-in `iflow -> iflow --experimental-acp` diff --git a/docs/agents.md b/docs/agents.md index ec405674..dcbb4eb3 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -9,24 +9,25 @@ The default agent for top-level commands like `acpx exec …` and `acpx prompt ## Built-in registry -| Agent | Adapter command | Wraps | -| ---------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| `pi` | `npx pi-acp` | [Pi Coding Agent](https://github.com/mariozechner/pi) | -| `openclaw` | `openclaw acp` | [OpenClaw ACP bridge](https://github.com/openclaw/openclaw) | -| `codex` | `npx -y @agentclientprotocol/codex-acp` | [Codex CLI](https://codex.openai.com) | -| `claude` | `npx -y @agentclientprotocol/claude-agent-acp` | [Claude Code](https://claude.ai/code) | -| `gemini` | `gemini --acp` | [Gemini CLI](https://github.com/google/gemini-cli) | -| `cursor` | `cursor-agent acp` | [Cursor CLI](https://cursor.com/docs/cli/acp) | -| `copilot` | `copilot --acp --stdio` | [GitHub Copilot CLI](https://docs.github.com/copilot/how-tos/copilot-chat/use-copilot-chat-in-the-command-line) | -| `droid` | `droid exec --output-format acp` | [Factory Droid](https://www.factory.ai) | -| `iflow` | `iflow --experimental-acp` | [iFlow CLI](https://github.com/iflow-ai/iflow-cli) | -| `kilocode` | `npx -y @kilocode/cli acp` | [Kilocode](https://kilocode.ai) | -| `kimi` | `kimi acp` | [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) | -| `kiro` | `kiro-cli-chat acp` | [Kiro CLI](https://kiro.dev) | -| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) | -| `qoder` | `qodercli --acp` | [Qoder CLI](https://docs.qoder.com/cli/acp) | -| `qwen` | `qwen --acp` | [Qwen Code](https://github.com/QwenLM/qwen-code) | -| `trae` | `traecli acp serve` | [Trae CLI](https://docs.trae.cn/cli) | +| Agent | Adapter command | Wraps | +| ------------ | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| `pi` | `npx pi-acp` | [Pi Coding Agent](https://github.com/mariozechner/pi) | +| `openclaw` | `openclaw acp` | [OpenClaw ACP bridge](https://github.com/openclaw/openclaw) | +| `codex` | `npx -y @agentclientprotocol/codex-acp` | [Codex CLI](https://codex.openai.com) | +| `claude` | `npx -y @agentclientprotocol/claude-agent-acp` | [Claude Code](https://claude.ai/code) | +| `gemini` | `gemini --acp` | [Gemini CLI](https://github.com/google/gemini-cli) | +| `cursor` | `cursor-agent acp` | [Cursor CLI](https://cursor.com/docs/cli/acp) | +| `copilot` | `copilot --acp --stdio` | [GitHub Copilot CLI](https://docs.github.com/copilot/how-tos/copilot-chat/use-copilot-chat-in-the-command-line) | +| `droid` | `droid exec --output-format acp` | [Factory Droid](https://www.factory.ai) | +| `fast-agent` | `uvx fast-agent-mcp acp` | [fast-agent](https://fast-agent.ai/) | +| `iflow` | `iflow --experimental-acp` | [iFlow CLI](https://github.com/iflow-ai/iflow-cli) | +| `kilocode` | `npx -y @kilocode/cli acp` | [Kilocode](https://kilocode.ai) | +| `kimi` | `kimi acp` | [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) | +| `kiro` | `kiro-cli-chat acp` | [Kiro CLI](https://kiro.dev) | +| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) | +| `qoder` | `qodercli --acp` | [Qoder CLI](https://docs.qoder.com/cli/acp) | +| `qwen` | `qwen --acp` | [Qwen Code](https://github.com/QwenLM/qwen-code) | +| `trae` | `traecli acp serve` | [Trae CLI](https://docs.trae.cn/cli) | `factory-droid` and `factorydroid` also resolve to the built-in `droid` adapter. @@ -123,6 +124,16 @@ If your Cursor install exposes ACP as `agent acp` instead of `cursor-agent acp`, - Default command: `droid exec --output-format acp` - Upstream: [factory.ai](https://www.factory.ai) +### fast-agent + +- Built-in name: `fast-agent` +- Default command: `uvx fast-agent-mcp acp` +- Upstream: https://fast-agent.ai/acp + +`acpx fast-agent` starts fast-agent through its ACP entrypoint. It requires `uvx` on `PATH`. + +Configure model/provider settings through fast-agent environment variables, fast-agent configuration, or an `acpx` agent override with additional `fast-agent-mcp acp` arguments. + ### Qoder - Built-in name: `qoder` diff --git a/docs/install.md b/docs/install.md index e1a890fb..45d7d44c 100644 --- a/docs/install.md +++ b/docs/install.md @@ -21,7 +21,7 @@ Some older Corepack builds bundled with supported Node.js versions have stale package-signing keys and fail while preparing current pnpm releases. Installing pnpm with npm avoids that bootstrap failure. -`acpx` itself does not need a global install of every adapter. Built-in adapters that ship as npm packages (`pi-acp`, `@agentclientprotocol/codex-acp`, `@agentclientprotocol/claude-agent-acp`, `@kilocode/cli`, `opencode-ai`) are auto-fetched with `npx` on first use. +`acpx` itself does not need a global install of every adapter. Built-in adapters that ship as npm packages (`pi-acp`, `@agentclientprotocol/codex-acp`, `@agentclientprotocol/claude-agent-acp`, `@kilocode/cli`, `opencode-ai`) are auto-fetched with `npx` on first use. The `fast-agent` built-in uses `uvx fast-agent-mcp acp`, so it requires `uvx` on `PATH`. ## Global install (recommended) diff --git a/skills/acpx/SKILL.md b/skills/acpx/SKILL.md index d2617f83..62ed5d58 100644 --- a/skills/acpx/SKILL.md +++ b/skills/acpx/SKILL.md @@ -87,6 +87,7 @@ Friendly agent names resolve to commands: - `cursor` -> `cursor-agent acp` - `copilot` -> `copilot --acp --stdio` - `droid` -> `droid exec --output-format acp` (`factory-droid` and `factorydroid` also resolve to `droid`) +- `fast-agent` -> `uvx fast-agent-mcp acp` - `iflow` -> `iflow --experimental-acp` - `kilocode` -> `npx -y @kilocode/cli acp` - `kimi` -> `kimi acp` diff --git a/src/agent-registry.ts b/src/agent-registry.ts index 18010943..52e14421 100644 --- a/src/agent-registry.ts +++ b/src/agent-registry.ts @@ -44,6 +44,7 @@ export const AGENT_REGISTRY: Record = { cursor: "cursor-agent acp", copilot: "copilot --acp --stdio", droid: "droid exec --output-format acp", + "fast-agent": "uvx fast-agent-mcp acp", iflow: "iflow --experimental-acp", kilocode: "npx -y @kilocode/cli acp", kimi: "kimi acp", diff --git a/test/agent-registry.test.ts b/test/agent-registry.test.ts index 69c334c4..9b389d5f 100644 --- a/test/agent-registry.test.ts +++ b/test/agent-registry.test.ts @@ -49,6 +49,11 @@ test("kiro built-in uses kiro-cli-chat directly", () => { assert.equal(resolveAgentCommand("kiro"), "kiro-cli-chat acp"); }); +test("fast-agent built-in runs the ACP entrypoint through uvx", () => { + assert.equal(AGENT_REGISTRY["fast-agent"], "uvx fast-agent-mcp acp"); + assert.equal(resolveAgentCommand("fast-agent"), "uvx fast-agent-mcp acp"); +}); + test("listBuiltInAgents preserves the required example prefix and alphabetical tail", () => { const agents = listBuiltInAgents(); assert.deepEqual(agents, Object.keys(AGENT_REGISTRY)); @@ -63,6 +68,7 @@ test("listBuiltInAgents preserves the required example prefix and alphabetical t ]); assert.deepEqual(agents.slice(7), [ "droid", + "fast-agent", "iflow", "kilocode", "kimi", diff --git a/test/integration.test.ts b/test/integration.test.ts index d4f47c3a..8f477493 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -821,6 +821,33 @@ test("integration: factory-droid alias resolves to droid exec --output-format ac }); }); +test("integration: built-in fast-agent resolves to uvx fast-agent-mcp acp", async () => { + await withTempHome(async (homeDir) => { + const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-")); + const fakeBinDir = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-fake-fast-agent-")); + + try { + await writeFakeUvxFastAgentAcp(fakeBinDir); + + const result = await runCli( + ["--approve-all", "--cwd", cwd, "--format", "quiet", "fast-agent", "exec", "echo hello"], + homeDir, + { + env: { + PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH ?? ""}`, + }, + }, + ); + + assert.equal(result.code, 0, result.stderr); + assert.match(result.stdout, /hello/); + } finally { + await fs.rm(fakeBinDir, { recursive: true, force: true }); + await fs.rm(cwd, { recursive: true, force: true }); + } + }); +}); + test("integration: built-in iflow agent resolves to iflow --experimental-acp", async () => { await withTempHome(async (homeDir) => { const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-")); @@ -3867,6 +3894,40 @@ async function writeFakeDroidAgent(binDir: string): Promise { ); } +async function writeFakeUvxFastAgentAcp(binDir: string): Promise { + if (process.platform === "win32") { + await fs.writeFile( + path.join(binDir, "uvx.cmd"), + [ + "@echo off", + "setlocal", + 'if "%~1"=="fast-agent-mcp" shift', + 'if "%~1"=="acp" shift', + `"${process.execPath}" "${MOCK_AGENT_PATH}" %*`, + "", + ].join("\r\n"), + { encoding: "utf8" }, + ); + return; + } + + await fs.writeFile( + path.join(binDir, "uvx"), + [ + "#!/bin/sh", + 'if [ "$1" = "fast-agent-mcp" ]; then', + " shift", + "fi", + 'if [ "$1" = "acp" ]; then', + " shift", + "fi", + `exec "${process.execPath}" "${MOCK_AGENT_PATH}" "$@"`, + "", + ].join("\n"), + { encoding: "utf8", mode: 0o755 }, + ); +} + async function writeFakeIflowAgent(binDir: string): Promise { if (process.platform === "win32") { await fs.writeFile(