Skip to content

Commit 4195631

Browse files
ignatovkobe0938
andauthored
Add generic ACP registry agent support (harbor-framework#1464)
* Add generic ACP registry agent support * Drop unneeded reset_dirs mock from multi-step trial test The mocked environment already satisfies the multi-step flow; the test passes identically without it and the file now matches main. --------- Co-authored-by: Kobe Chen <[email protected]>
1 parent 5270111 commit 4195631

16 files changed

Lines changed: 3320 additions & 9 deletions

File tree

docs/content/docs/agents/acp.mdx

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
title: ACP Registry Agents
3+
description: Run agents published in the Agent Client Protocol registry
4+
---
5+
6+
Harbor can run agents from the [ACP registry](https://github.com/agentclientprotocol/registry) through the built-in generic `acp` runner.
7+
8+
## CLI
9+
10+
Use the `acp:<id>[@version]` shorthand anywhere `--agent` is accepted:
11+
12+
```bash
13+
harbor run \
14+
--path examples/tasks/hello-world \
15+
--agent acp:[email protected] \
16+
--model openai/gpt-5.4 \
17+
--ae OPENAI_API_KEY=$OPENAI_API_KEY
18+
```
19+
20+
If the version is omitted, Harbor resolves the latest `agent.json` from the registry's `main` branch during agent setup.
21+
22+
## Config Files
23+
24+
The same shorthand works in YAML or JSON configs and is preserved in the persisted `config.json`:
25+
26+
```yaml
27+
agents:
28+
- name: acp:[email protected]
29+
model_name: openai/gpt-5.4
30+
kwargs:
31+
auth_policy: auto
32+
permission_mode: allow
33+
```
34+
35+
## SDK
36+
37+
SDK users can use the same declarative agent name:
38+
39+
```python
40+
from harbor.models.trial.config import AgentConfig
41+
42+
agent = AgentConfig(
43+
name="acp:[email protected]",
44+
model_name="openai/gpt-5.4",
45+
env={"OPENAI_API_KEY": "${OPENAI_API_KEY}"},
46+
)
47+
```
48+
49+
Registry resolution happens asynchronously in `AcpAgent.setup()`, so creating configs and agents does not perform network I/O.
50+
51+
## Options
52+
53+
Common ACP kwargs:
54+
55+
- `auth_policy`: `auto`, `explicit`, or `disabled`
56+
- `permission_mode`: `allow` or `deny`
57+
- `distribution_preference`: comma-separated preference among `binary`, `npx`, and `uvx`
58+
- `registry_ref`: ACP registry git ref for latest-version resolution
59+
- `registry_cache_dir`: local cache directory for fetched registry entries
60+
61+
You can also run the generic ACP agent with an explicit registry entry:
62+
63+
```yaml
64+
agents:
65+
- name: acp
66+
kwargs:
67+
registry_entry_path: /path/to/agent.json
68+
```
69+
70+
## Outputs
71+
72+
ACP runs write these files under the agent log directory:
73+
74+
- `acp.txt`
75+
- `acp-events.jsonl`
76+
- `acp-summary.json`
77+
- `trajectory.json`
78+
79+
Because Harbor generates `trajectory.json`, standard trace export works:
80+
81+
```bash
82+
harbor traces export -p jobs/<job-name> --recursive
83+
```

docs/content/docs/agents/meta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"title": "Agents",
3-
"pages": ["index", "terminus-2", "trajectory-format"]
3+
"pages": ["index", "terminus-2", "acp", "trajectory-format"]
44
}

examples/configs/acp-job.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Example ACP job config.
2+
#
3+
# uv run harbor job start -c examples/configs/acp-job.yaml \
4+
# --ae OPENAI_API_KEY=$OPENAI_API_KEY
5+
6+
job_name: acp-opencode
7+
jobs_dir: jobs
8+
n_attempts: 1
9+
n_concurrent_trials: 1
10+
environment:
11+
type: docker
12+
force_build: true
13+
delete: true
14+
agents:
15+
- name: acp:[email protected]
16+
model_name: openai/gpt-5.4
17+
kwargs:
18+
auth_policy: auto
19+
permission_mode: allow
20+
tasks:
21+
- path: examples/tasks/hello-world

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,4 @@ python = ".venv"
123123

124124
[tool.ty.src]
125125
include = ["src/harbor", "packages/rewardkit/src", "packages/harbor-langsmith/src"]
126-
exclude = ["src/harbor/cli/template-adapter", "src/harbor/cli/template-task", "src/harbor/agents/installed/openhands_sdk_runner.py", "src/harbor/agents/installed/nemo_agent_run_wrapper.py"]
126+
exclude = ["src/harbor/cli/template-adapter", "src/harbor/cli/template-task", "src/harbor/agents/installed/openhands_sdk_runner.py", "src/harbor/agents/installed/acp_runner.py", "src/harbor/agents/installed/nemo_agent_run_wrapper.py"]

src/harbor/agents/factory.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
from pathlib import Path
22

3+
from harbor.agents.installed.acp import AcpAgent
4+
from harbor.agents.installed.acp_registry import (
5+
is_acp_registry_shorthand,
6+
registry_spec_from_agent_name,
7+
)
38
from harbor.utils.import_path import import_class
49

510
from harbor.agents.base import BaseAgent
@@ -39,6 +44,7 @@ class AgentFactory:
3944
_AGENTS: list[type[BaseAgent]] = [
4045
OracleAgent,
4146
NopAgent,
47+
AcpAgent,
4248
Terminus2,
4349
ClaudeCode,
4450
CopilotCli,
@@ -143,6 +149,21 @@ def create_agent_from_config(
143149
ValueError: If the configuration is invalid.
144150
"""
145151
extra_env = resolve_env_vars(config.env)
152+
if config.name is not None and is_acp_registry_shorthand(config.name):
153+
agent_kwargs = {**config.kwargs, **kwargs}
154+
agent_kwargs["registry_spec"] = registry_spec_from_agent_name(config.name)
155+
if config.override_setup_timeout_sec is not None:
156+
agent_kwargs["override_setup_timeout_sec"] = (
157+
config.override_setup_timeout_sec
158+
)
159+
return cls.create_agent_from_name(
160+
AgentName.ACP,
161+
logs_dir=logs_dir,
162+
model_name=config.model_name,
163+
extra_env=extra_env,
164+
**agent_kwargs,
165+
)
166+
146167
if config.name is not None and config.name in AgentName.values():
147168
name = AgentName(config.name)
148169
agent_kwargs = {**config.kwargs, **kwargs}

0 commit comments

Comments
 (0)