Skip to content

Add ACP backend router for WeChat switching#8

Open
huluma1314 wants to merge 1 commit intowong2:mainfrom
huluma1314:feat/acp-router-backends
Open

Add ACP backend router for WeChat switching#8
huluma1314 wants to merge 1 commit intowong2:mainfrom
huluma1314:feat/acp-router-backends

Conversation

@huluma1314
Copy link
Copy Markdown

Summary

  • add router mode for weixin-acp so one WeChat conversation can switch between multiple ACP backends
  • support /claude, /codex, /mode, and persistent per-conversation backend selection
  • document router config usage and add an example config file

Validation

  • pnpm --filter weixin-acp build
  • node packages/agent-acp/dist/main.mjs
  • verified locally with a live WeChat bridge using Claude and Codex backends

Notes

  • pnpm -r run typecheck still reports existing workspace module-resolution issues for weixin-agent-sdk; this is not introduced by this change and also affects example-openai in the current repo state.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a “router mode” to the weixin-acp ACP adapter so a single WeChat conversation can switch among multiple ACP backends (e.g., Claude vs Codex), with optional per-conversation persistence and documented CLI usage.

Changes:

  • Introduces router configuration types and a small persistent state store for per-conversation backend selection.
  • Updates AcpAgent to route requests and maintain separate ACP connections/sessions per backend.
  • Extends the CLI + README with --router-config usage and an example router config JSON.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/agent-acp/src/types.ts Adds router config + backend spec types; updates agent options shape.
packages/agent-acp/src/router-state.ts Adds JSON file-backed store for conversation → backend mapping.
packages/agent-acp/src/acp-agent.ts Implements routing, backend switching commands, and per-backend connections/sessions.
packages/agent-acp/router.example.json Provides an example router config.
packages/agent-acp/main.ts Adds --router-config CLI path and config loading.
README.md Documents router mode and backend switching commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +23 to +26
export type AcpAgentOptions = AcpBackendSpec & {
/** Optional router mode for switching backends from WeChat commands. */
router?: AcpRouterConfig;
};
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AcpAgentOptions currently always requires command because it extends AcpBackendSpec, even when router is provided (where the top-level command is unused). This forces callers (and the CLI) to pass a dummy command: "", which weakens type-safety and makes it easier to accidentally construct invalid options. Consider changing this to a union type where command is required only in single-backend mode, and router mode uses router + optional global defaults (e.g., promptTimeoutMs/cwd) without requiring command.

Suggested change
export type AcpAgentOptions = AcpBackendSpec & {
/** Optional router mode for switching backends from WeChat commands. */
router?: AcpRouterConfig;
};
type AcpAgentSingleBackendOptions = AcpBackendSpec & {
/** Single-backend mode: no router configured. */
router?: undefined;
};
type AcpAgentRouterOptions = {
/** Router mode: dynamically select among multiple ACP backends. */
router: AcpRouterConfig;
/**
* Optional global defaults applied to all routed backends.
* `command` is intentionally omitted since the router controls backends.
*/
} & Omit<Partial<AcpBackendSpec>, "command">;
export type AcpAgentOptions =
| AcpAgentSingleBackendOptions
| AcpAgentRouterOptions;

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines +51 to +57
```bash
# 安装两个 ACP agent
npm install -g @zed-industries/claude-agent-acp @zed-industries/codex-acp

# 使用多后端路由启动
npx weixin-acp start --router-config ./packages/agent-acp/router.example.json
```
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example uses ./packages/agent-acp/router.example.json, which only exists when running from this monorepo checkout. For users following the README via npx weixin-acp ..., that path won’t exist. Consider adjusting the docs to instruct users to create their own router.json (and optionally reference the example file on GitHub) rather than pointing to a workspace-relative path.

Copilot uses AI. Check for mistakes.
}

const agent = new AcpAgent({
command: "",
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In router-config mode the CLI constructs new AcpAgent({ command: "", router: ... }). If the router config fails to load or router mode is later refactored, an empty command could lead to confusing spawn errors. This will also remain necessary as long as the type requires command even in router mode. Consider updating the options typing/API so router mode doesn’t need a placeholder command, and update this construction accordingly.

Suggested change
command: "",
// In router-config mode, no external command is spawned; this placeholder satisfies the type.
command: "__ROUTER_MODE_NO_COMMAND__",

Copilot uses AI. Check for mistakes.
Comment on lines 85 to 86
const res = await conn.newSession({
cwd: this.options.cwd ?? process.cwd(),
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In router mode, the per-backend spec includes cwd (documented as affecting both the subprocess and ACP sessions), but newSession always uses this.options.cwd (global) and ignores the selected backend’s cwd. This can lead to sessions starting in the wrong working directory for a backend that relies on a specific cwd. Consider deriving the session cwd from the routed backend spec (with a global fallback) instead of only this.options.cwd.

Suggested change
const res = await conn.newSession({
cwd: this.options.cwd ?? process.cwd(),
const backendCwd =
this.options.router?.backends?.[backend]?.cwd;
const sessionCwd = backendCwd ?? this.options.cwd ?? process.cwd();
const res = await conn.newSession({
cwd: sessionCwd,

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +151
return {
backend,
request: {
...request,
text: command.prompt ?? request.text,
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When handling a backend switch command, the routed request text is set to command.prompt ?? request.text. If the user sends /claude (no prompt) together with media, request.text will still be /claude, so the agent will receive the command string as part of the prompt. Consider stripping the routing prefix even when request.media is present (e.g., set text to the parsed remainder or empty) while still switching the default backend.

Suggested change
return {
backend,
request: {
...request,
text: command.prompt ?? request.text,
const routedText =
command.prompt !== undefined
? command.prompt
: request.media
? ""
: request.text;
return {
backend,
request: {
...request,
text: routedText,

Copilot uses AI. Check for mistakes.
console.log(`[acp] ${msg}`);
}

type RouterCommand =
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hhhh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants