Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/crates/interfaces/acp/src/client/builtin_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const LEGACY_CLAUDE_ACP_ARGS: &[&str] = &["--yes", "@zed-industries/claude-code-
const CODEX_ACP_PACKAGE: &str = "@agentclientprotocol/codex-acp";
const CODEX_ACP_ARGS: &[&str] = &["--yes", "@agentclientprotocol/codex-acp@latest"];
const LEGACY_CODEX_ACP_ARGS: &[&str] = &["--yes", "@zed-industries/codex-acp@latest"];
const DSH_ACP_PACKAGE: &str = "@deepseek-ai/dsh-acp-demo@next";

pub(crate) struct BuiltinAcpClientPreset {
pub(crate) id: &'static str,
Expand All @@ -32,6 +33,19 @@ const BUILTIN_ACP_CLIENT_PRESETS: &[BuiltinAcpClientPreset] = &[
adapter_package: None,
adapter_bin: None,
},
// DeepSeek Harness exposes its automation surface as a native ACP server
// through the `dsh-acp-demo` bin. The server reads `./cordis.yml` by
// default; users can override that path in the preset arguments. The ACP
// package follows DSH's developer-preview `next` release channel.
BuiltinAcpClientPreset {
id: "dsh",
command: "dsh-acp-demo",
args: &[],
tool_command: "dsh-acp-demo",
install_package: Some(DSH_ACP_PACKAGE),
adapter_package: None,
adapter_bin: None,
},
// Oh My Pi (omp) — a terminal coding agent that speaks ACP natively via
// `omp acp` (no adapter needed, like opencode). User-managed: omp targets
// the bun runtime (installed via `bun install -g @oh-my-pi/pi-coding-agent`
Expand Down Expand Up @@ -152,6 +166,22 @@ mod tests {
assert_eq!(config.args, vec!["acp"]);
}

#[test]
fn dsh_is_a_native_acp_preset() {
let preset = builtin_acp_client_preset("dsh").expect("DSH preset registered");
assert_eq!(preset.command, "dsh-acp-demo");
assert!(preset.args.is_empty());
assert_eq!(preset.tool_command, "dsh-acp-demo");
assert_eq!(preset.install_package, Some(DSH_ACP_PACKAGE));
assert!(preset.adapter_package.is_none());
assert!(preset.adapter_bin.is_none());

let config = default_config_for_builtin_client("dsh").expect("DSH config");
assert!(config.enabled);
assert_eq!(config.command, "dsh-acp-demo");
assert!(config.args.is_empty());
}

#[test]
fn migrates_only_exact_legacy_builtin_commands() {
let mut config_file = AcpClientConfigFile {
Expand Down
11 changes: 11 additions & 0 deletions src/crates/interfaces/acp/src/client/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2721,4 +2721,15 @@ mod tests {
assert_eq!(resolved.env.get("BASE").map(String::as_str), Some("1"));
assert!(resolved.enabled);
}

#[test]
fn resolves_builtin_dsh_config_for_remote_workspace() {
let resolved =
resolve_config_for_client(&AcpClientConfigFile::default(), "dsh", Some("remote-host"))
.expect("built-in DSH config");

assert_eq!(resolved.command, "dsh-acp-demo");
assert!(resolved.args.is_empty());
assert!(resolved.enabled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,30 @@ describe('AcpAgentsConfig', () => {
expect(notifySuccessMock).toHaveBeenCalledWith('notifications.configAddedManualCliRequired');
});

it('offers DeepSeek Harness as a native ACP preset', async () => {
probeClientRequirementsMock.mockResolvedValue([
{
id: 'dsh',
tool: { name: 'dsh-acp-demo', installed: true, version: '0.1.0-rc.6' },
runnable: true,
notes: [],
},
]);

await act(async () => {
root.render(<AcpAgentsConfig />);
});

await act(async () => {
await Promise.resolve();
await Promise.resolve();
});

expect(container.textContent).toContain('DeepSeek Harness');
expect(container.textContent).toContain('dsh-acp-demo');
expect(container.textContent).not.toContain('registry.acpMissing');
});

it('does not downgrade enabled agents on transient probe timeouts during refresh', async () => {
probeClientRequirementsMock
.mockResolvedValueOnce([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ interface AcpClientPreset {

// Presets that speak ACP natively and therefore need no separate adapter
// package (their CLI binary is launched directly).
const NATIVE_ACP_PRESET_IDS = new Set(['opencode', 'omp']);
const NATIVE_ACP_PRESET_IDS = new Set(['opencode', 'dsh', 'omp']);

// Presets BitFun cannot install on the user's behalf — the agent must be
// installed manually (e.g. omp targets bun and ships via its own installer).
Expand All @@ -105,6 +105,13 @@ const PRESETS: AcpClientPreset[] = [
command: 'opencode',
args: ['acp'],
},
{
id: 'dsh',
name: 'DeepSeek Harness',
description: 'Native ACP server (dsh-acp-demo); add --config with an absolute DSH cordis.yml path.',
command: 'dsh-acp-demo',
args: [],
},
{
id: 'omp',
name: 'Oh My Pi',
Expand Down