Skip to content

stefandevo/glm-acp-agent

Repository files navigation

glm-acp-agent

An Agent Client Protocol (ACP) agent written in TypeScript that uses the Z.AI / Zhipu AI GLM model family (GLM-5.1, GLM-4.7, GLM-4.6, …) as its reasoning core.

The agent connects to any ACP-compatible IDE or client over stdio, streams responses back in real time, and can call a rich set of tools to interact with the user's file system, terminal, and the web.


Coding Plan Only

glm-acp-agent is intentionally built for the Z.AI GLM Coding Plan. It is not a general-purpose Z.AI Open Platform API client.

By default, model calls use the Coding Plan endpoint:

https://api.z.ai/api/coding/paas/v4

The same Coding Plan API key is used for the agent's GLM model calls and supported Coding Plan tools. General Z.AI API/resource-package billing surfaces, such as direct /api/paas/v4 Tool API calls, are intentionally out of scope for this ACP agent.

Built-in web tools use Coding Plan-compatible MCP endpoints, not the general /api/paas/v4 Tool API. If you need general Z.AI API billing, separate resource packages, or non-Coding Plan endpoints, use a different provider configuration or fork this agent for that purpose.


Features

  • Full ACP compliance – implements initialize, authenticate, session/new, session/set_mode, session/prompt, session/cancel, session/close, session/list, session/load, session/fork, session/resume, and session/set_model
  • Streaming – assistant text and reasoning tokens are forwarded as incremental ACP chunks
  • Tool calling – agentic loop with up to 20 turns of GLM function calling
  • Thinking mode – GLM's reasoning_content tokens are surfaced as agent_thought_chunk blocks so the client can show the model's chain of thought
  • Per-session model switchingsession/set_model lets clients change the active GLM model mid-conversation; session/new returns the curated availableModels list
  • Image input via Coding Plan Vision MCPpromptCapabilities.image is advertised; pasted ACP image blocks are routed through Z.AI Vision MCP (@z_ai/mcp-server) and the resulting analysis is fed into the main coding model. Direct chat-image (e.g. glm-4v-plus) calls are intentionally not used.
  • Session persistence – conversations are written to ~/.local/state/glm-acp-agent/sessions/ and can be reloaded via session/load, branched via session/fork, or resumed without replay via session/resume
  • Six built-in tools (see below)
  • Capability-aware – every tool is gated on the client capabilities advertised at initialize time; tools the client can't run return a clear error to the model instead of crashing
  • Permissioned writes / commands – every write_file and run_command call asks the user via session/request_permission before doing anything
  • Protocol-correct stop reasons – maps model and runtime conditions to ACP end_turn, max_tokens, max_turn_requests, refusal, and cancelled
  • Protocol-correct tool statusespendingin_progresscompleted / failed
  • Token usage reporting – aggregated usage is returned on the session/prompt response

Architecture

ACP Client (IDE plugin, CLI, …)
        │  stdio (ndjson)
        ▼
  GlmAcpAgent          ← ACP protocol layer  (src/protocol/)
        │
        ├─ GlmClient   ← Z.AI / Zhipu AI Coding Plan Chat Completions  (src/llm/)
        │
        ├─ ToolExecutor ← executes tool calls  (src/tools/)
        │    ├─ read_file / write_file       → ACP client (fs.*)
        │    ├─ list_files / run_command     → ACP client (terminal)
        │    ├─ web_search / web_reader      → Z.AI Coding Plan Web MCP (HTTP)
        │    └─ image_analysis               → Z.AI Coding Plan Vision MCP (stdio)
        │
        └─ VisionMcpClient ← spawns `npx @z_ai/mcp-server` on demand

The agent process needs network access to api.z.ai for chat completions and Web MCP, plus npx available on PATH so it can launch @z_ai/mcp-server for vision. Filesystem and shell operations remain delegated to the ACP client; the agent itself only writes to the OS temp directory when it needs to materialize a pasted image for Vision MCP, and those temp files are removed once the prompt completes.


Available Tools

Tool Runs on Requires client capability Description
read_file ACP client fs.readTextFile Read the text content of a file
write_file ACP client fs.writeTextFile Write or overwrite a text file (asks for permission)
list_files ACP client terminal List a directory via ls -la (POSIX shell required)
run_command ACP client terminal Run an arbitrary shell command via sh -c (asks for permission)
web_search Agent (Z.AI Coding Plan MCP) Search the web — returns titles, URLs, and summaries
web_reader Agent (Z.AI Coding Plan MCP) Fetch and parse a web page (markdown or plain text)
image_analysis Agent (Z.AI Vision MCP, stdio) Analyze a local image path or remote URL using @z_ai/mcp-server

Prerequisites


Installation

git clone https://github.com/stefandevo/glm-acp-agent.git
cd glm-acp-agent
npm install
npm run build

Configuration

The agent reads its configuration from environment variables, plus an optional credentials file written by glm-acp-agent --setup.

Variable Required Default Description
Z_AI_API_KEY One of env / --setup API key for the Z.AI / Zhipu AI service. If unset, the credentials file is consulted.
ACP_GLM_MODEL No glm-5.1 Default GLM model for new sessions
ACP_GLM_AVAILABLE_MODELS No built-in list Comma-separated list of model ids advertised in session/set_model
ACP_GLM_BASE_URL No https://api.z.ai/api/coding/paas/v4 Override the API base URL
ACP_GLM_MAX_TOKENS No 8192 Cap on max_tokens for each completion
ACP_GLM_THINKING No auto-detected Force thinking mode true / false
ACP_GLM_SESSION_DIR No $XDG_STATE_HOME/glm-acp-agent/sessions Where session JSON files are persisted
ACP_GLM_DEBUG No Set to true or 1 to enable verbose debug logging to stderr (shows model selection, API key resolution, tool calls, and usage stats)
XDG_CONFIG_HOME No ~/.config Where the credentials file is read/written

One-time setup

If you'd rather not pass Z_AI_API_KEY through your ACP client's environment block, run the interactive setup once and the agent will read the key from disk on subsequent launches:

# From the project directory (after npm run build)
node dist/index.js --setup

# Or, if you installed globally
glm-acp-agent --setup

The key is written to $XDG_CONFIG_HOME/glm-acp-agent/credentials.json (default: ~/.config/glm-acp-agent/credentials.json) with 0600 permissions. The Z_AI_API_KEY environment variable, when set, always wins over the file.

Supported models

The agent advertises only the models on the current Z.AI Coding Plan allowlist:

Model Notes
glm-5.1 Default. Long-horizon coding model; thinking mode auto-enabled
glm-5-turbo Faster Coding Plan reasoning model
glm-4.7 200K-context reasoning model
glm-4.5-air Lightweight, lower-latency model

ACP_GLM_AVAILABLE_MODELS still lets you advertise custom IDs, but custom IDs sit outside the supported Coding Plan list — the Coding Plan endpoint will reject any model code Z.AI hasn't whitelisted (business code 1211).

Vision (glm-4v-plus etc.) is not advertised as a chat model: vision on the Coding Plan flows through the Vision MCP section below instead.

When the model name matches glm-4.5, glm-4.6, glm-4.7, or glm-5.x, the agent enables Z.AI's thinking: { type: "enabled" } extension and forwards reasoning tokens to the client as agent_thought_chunk blocks. Override with ACP_GLM_THINKING=false if you want plain completions only.

Vision MCP

Pasted ACP image blocks are not sent to the chat-completions endpoint. Instead, the agent boots @z_ai/mcp-server over stdio (via npx -y @z_ai/mcp-server@latest) and calls its image_analysis tool. The text result is spliced into the user message as <image_analysis index="N">…</image_analysis> so the regular Coding Plan model can reason about it.

Prerequisites:

  • npx on PATH (Node 18+ / npm 9+).
  • The same Z_AI_API_KEY used for chat completions; the agent forwards it to the MCP server as Z_AI_API_KEY plus Z_AI_MODE=ZAI.

The model can also call image_analysis explicitly with { image_source: "/path/or/url", prompt?: "…" }. Vision failures (missing npx, MCP startup, quota) are surfaced as actionable errors but never abort the prompt; an inline <image_analysis_error> annotation is used so the conversation can continue.


Running

Standalone (stdio)

export Z_AI_API_KEY=your_key_here
node dist/index.js

The agent speaks the ACP newline-delimited JSON protocol over stdin/stdout. You can connect any ACP-compatible client to it.

As a global CLI

npm install -g .
export Z_AI_API_KEY=your_key_here
glm-acp-agent

Development mode (watch)

export Z_AI_API_KEY=your_key_here
npm run dev        # tsc --watch

Connecting to an ACP Client

Zed (recommended for local testing)

Zed is currently the most polished editor for trying out ACP agents locally — it spawns the agent process over stdio and surfaces it in the agent panel. This is the fastest way to iterate on glm-acp-agent before publishing it to the ACP registry or to npm.

1. Prerequisites

2. Build the agent

git clone https://github.com/stefandevo/glm-acp-agent.git
cd glm-acp-agent
npm install
npm run build

Take note of the absolute path to the freshly built entry point — Zed needs it (no ~, no $HOME shortcuts):

echo "$(pwd)/dist/index.js"

3. Wire it into Zed

Open (or create) ~/.config/zed/settings.json and add an agent_servers entry. Pick one of the two API-key strategies below.

Option A — inline env block (simplest):

{
  "agent_servers": {
    "glm": {
      "command": "node",
      "args": ["/absolute/path/to/glm-acp-agent/dist/index.js"],
      "env": { "Z_AI_API_KEY": "sk-…" }
    }
  }
}

Option B — credentials file (no key in your editor settings):

Run the interactive setup once. From the project directory:

node dist/index.js --setup

…or, if you npm install -g .'d the package:

glm-acp-agent --setup

The key is written to ~/.config/glm-acp-agent/credentials.json with 0600 permissions. Then drop the env block from the Zed entry — the agent will read the file on launch:

{
  "agent_servers": {
    "glm": {
      "command": "node",
      "args": ["/absolute/path/to/glm-acp-agent/dist/index.js"]
    }
  }
}

If Z_AI_API_KEY is set in the environment and a credentials file exists, the environment variable wins.

4. Verify it works

  1. Save settings.json. Zed reloads settings automatically.
  2. Open the agent panel (use the command palette: agent panel: toggle focus).
  3. In the agent picker, select glm — Zed labels external agents by their agent_servers key.
  4. Start a new thread and send a small prompt that exercises a tool, e.g. Read package.json and tell me the project name.
  5. You should see streaming text, a read_file tool call awaiting permission, and (with a thinking-capable model like glm-5.1) reasoning surfaced as a separate thought block.

5. Iterating on the agent

After editing the source, rebuild:

npm run build

Zed spawns a fresh agent process per thread, so the easiest way to pick up changes is to start a new thread with the glm agent. If you see stale behavior, fully quit and reopen Zed — that guarantees no in-flight process is reused.

For a tighter inner loop, run npm run dev in a terminal so dist/ rebuilds on every save; you only need to start a new Zed thread to test the latest code.

6. Troubleshooting

  • The "glm" agent doesn't appear in the picker.settings.json likely has a JSON parse error, or your Zed build is older than agent_servers support. Open the Zed log via the command palette (zed: open log) and look for settings errors.
  • Error: Cannot find module '/.../dist/index.js' — you skipped npm run build, or the path in args is wrong. It must be absolute and point at a file that exists.
  • No API key found. — neither Z_AI_API_KEY nor ~/.config/glm-acp-agent/credentials.json is set. Use Option A or Option B in step 3.
  • HTTP 401: Invalid API key — your key is wrong, expired, or for the wrong region. Rotate it on https://z.ai/manage-apikey/apikey-list.
  • client does not advertise the … capability — Zed didn't expose that capability to the agent (e.g. terminal for run_command/list_files). Ask the model to use a different tool, or upgrade Zed.

Neovim / VS Code / JetBrains / any ACP client

Any client that supports configuring an ACP agent via a command + args invocation works the same way: point it at node /absolute/path/to/glm-acp-agent/dist/index.js and supply Z_AI_API_KEY in the environment.

Authentication

The agent advertises two authentication methods at initialize time:

  1. An agent-default method — the agent will read the API key itself, either from the Z_AI_API_KEY environment variable or from the credentials file written by glm-acp-agent --setup.
  2. An env_var method (experimental SDK extension) describing the Z_AI_API_KEY variable so capable clients can prompt the user and inject it.

ACP clients that support the auth-methods proposal will use whichever method they recognise; clients that don't handle auth methods should set Z_AI_API_KEY themselves before launching the agent (or run glm-acp-agent --setup once and let the agent read it from disk).


Project Structure

src/
├── index.ts                  # Entry point – starts stdio connection or --setup flow
├── setup.ts                  # Interactive credential setup (`--setup`)
├── llm/
│   ├── glm-client.ts         # OpenAI-compatible client for Z.AI / Zhipu AI
│   └── credentials.ts        # API-key resolution (env var > credentials.json)
├── protocol/
│   ├── connection.ts         # Sets up the ACP stdio connection
│   ├── agent.ts              # GlmAcpAgent – ACP protocol implementation
│   └── session-store.ts      # On-disk persistence for load/fork/resume
├── tools/
│   ├── definitions.ts        # Tool JSON schemas (function-calling format)
│   └── executor.ts           # ToolExecutor – dispatches tool calls
└── tests/
    ├── agent.test.ts         # Protocol-level tests for GlmAcpAgent
    ├── credentials.test.ts   # Credential resolution and --setup persistence
    ├── executor.test.ts      # Tests for ToolExecutor
    ├── glm-client.test.ts    # Tests for streaming / tool-call assembly
    └── integration.test.ts   # End-to-end tests over the real ACP ndjson transport

Building & Testing

npm run build   # one-shot TypeScript compilation → dist/
npm run dev     # watch mode
npm test        # build + run unit tests with the node:test runner

The test suite covers:

  • ACP protocol-version negotiation, capability advertising, and auth method shape
  • Session lifecycle (new / list / close, filter by cwd)
  • Prompt loop streaming, tool-call assembly, max-turn cap, cancellation, stop-reason mapping (stopend_turn, lengthmax_tokens, content_filterrefusal, tool_calls exhausted → max_turn_requests)
  • Content-block conversion (text, resource_link, embedded resource)
  • Token usage reporting on the PromptResponse
  • Tool call lifecycle (pendingin_progresscompleted / failed)
  • Capability gating (tools refuse cleanly when the client did not advertise the required capability)
  • Permission flows for write_file and run_command (allow / reject / cancel)
  • Shell-quoted argument handling for list_files and run_command
  • GLM streaming: text deltas, reasoning_content deltas, multi-chunk tool-call assembly, and trailing usage
  • Image preprocessing through a mocked Vision MCP client and graceful degradation on Vision MCP failures

Troubleshooting

  • No API key found. — either set Z_AI_API_KEY in the environment, or run node dist/index.js --setup (or glm-acp-agent --setup if installed globally) once to store the key on disk.
  • HTTP 401: Invalid API key — your key is wrong or expired; rotate it on https://z.ai/manage-apikey/apikey-list.
  • The agent says "client does not advertise the … capability". — your ACP client doesn't expose that capability (e.g. terminal). Ask the model to use a different tool, or upgrade the client.
  • Tools never get to run. — make sure the client is sending the clientCapabilities field in initialize; the agent uses it to decide which tools to expose to the model.

License

Apache 2.0 – see LICENSE.

About

ACP agent in TypeScript that uses the Zhipu AI GLM series (specifically GLM-5.1 and GLM-4.7) as the reasoning core

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors