Skip to content

Commit 6ad7a00

Browse files
committed
fix(openclaw-acp-bridge): remove dead base_url, forward read(limit=) (PR #30 round-7)
## What Three files in `plugins/antianqi/openclaw-acp-bridge/`: - `scripts/acp_inbox.py`: - `ACPInbox.__init__` no longer takes `base_url=`. The bundled client's `inbox_*` helpers read `$ACP_BASE_URL` (or fall back to `_acp_client.DEFAULT_BASE_URL`); a per-instance `base_url` was silently ignored. The constructor is now `(default_timeout)`; the public API is honest. - `ACPInbox.read` now takes `limit=None` and forwards it to the underlying `_acp_client.inbox_read`. The docstring previously advertised `read(limit=...)` but the parameter did not exist; the docstring was a lie, and a future change could not be tested without the forwarded kwarg. - The CLI (`acp_inbox.py --action ping`) no longer accepts `--base-url`. Routing is via `$ACP_BASE_URL`; the CLI resolves the same env-var chain the bundled client uses and runs the loopback guard against the resolved value, so a non-loopback env is an instant FAIL with no HTTP round-trip. - `scripts/test_inbox_goudan.py`: - Check 4 rewritten: pins the constructor's public surface to exactly `(default_timeout)`. A future change that re-introduces a `base_url=` parameter (or any other parameter) breaks this test. - Check 5 rewritten: the loopback guard check is now `_acp_client._check_loopback(...)`, not a constructor-time check on a dead parameter. - New Check 13b: mocks `_acp_client.inbox_read` and asserts that `ACPInbox.read(limit=42)` forwards `limit=42` to the underlying call. Negative-injection: `read()` (without `limit=...`) still calls `inbox_read` once. - Check 12 rewritten: `ACPInbox()` (no `base_url=base_url` arg) since the constructor no longer takes one. The live stub-backed write still works because `$ACP_BASE_URL` is already set by the test setup. - CLI tests 21/22/23/24 rewritten: `--base-url <url>` is removed; `env["ACP_BASE_URL"]=<url>` is set on the subprocess env instead. Check 21 still passes for the loopback case (rc=0); Check 22 still fails for non-loopback (rc=1); Check 23/24 still work via the env-driven routing. - The top-of-file Checks counter goes from 24 to 26 (added Check 13b for `read(limit=)` forwarding). ## Why PR #30 round-7 (hetaoBackend, 2026-09-02T01:08:36Z): the wrapper documents a `base_url=...` parameter on the constructor and a `read(limit=...)` parameter on `read`. Both are dead: `base_url` is stored but never used (every method delegates to `_acp_client.inbox_*` which reads `$ACP_BASE_URL`), and `read(limit=...)` is in the docstring but not in the signature. "Please make the wrapper endpoint and limit parameters effective (or remove them from the public contract) and add delegation tests that use different constructor/env URLs and assert the forwarded limit." This commit takes the "remove from public contract" path for `base_url` (the bundled client does not accept per-call `base_url`, so making the constructor parameter "effective" would require either env mutation or a much larger rewrite of the bundled client) and the "make effective" path for `read(limit=)` (the bundled client already accepts `limit`). ## Validation - `python scripts/test_inbox_goudan.py` (CI mode, `SMOKE_SKIP_LIVE=1`): **21 / 21 PASS, 0 FAIL, 10 SKIP**. The 10 skipped are the live server checks. - `python scripts/test_inbox_goudan.py` (live, stub-backed): **41 / 41 PASS, 0 FAIL, 0 SKIP** on Windows + Python 3.14. Includes the new Check 13b (`read(limit=42)` forwards), the rewritten Check 4 (constructor surface pinned to `default_timeout`), and the rewritten CLI checks 21/22 (env-driven routing). - `python scripts/smoke.py` (PR #3 mavis-side smoke, regression check): **26 / 26 PASS, 0 FAIL**. Zero regression on the mavis side. - `python scripts/test_no_redirect.py` (PR #3 no-redirect regression): **PASS**. The no-redirect guarantee still holds for the underlying `client/_acp_client`; the wrapper inherits it. - `node scripts/validate.mjs`: no new FAIL on `plugins/antianqi/openclaw-acp-bridge/`. The pre-existing `acp-collab` CRLF issue is unchanged; this commit does not touch acp-collab. ## Test evidence End-to-end on Windows + Python 3.14, 2026-09-02 (Asia/Shanghai): - 24 → 26 tests in `test_inbox_goudan.py`. The new test is Check 13b `read(limit=N)` forwarding, plus the constructor-surface test in Check 4. - All four CLI checks (21, 22, 23, 24) now use `env["ACP_BASE_URL"]=...` instead of `--base-url ...`. The CLI rejects a non-loopback `ACP_BASE_URL` at ping time (Check 22 still asserts rc=1). - The wrapper no longer accepts `base_url=` at the constructor. A caller passing `ACPInbox(base_url="...")` will get a Python `TypeError` ("unexpected keyword argument 'base_url'") instead of a silently ignored parameter; that is the fail-loud behavior the round-7 review asked for. - `read(limit=None)` calls `_acp_client.inbox_read(...)` without `limit`; `read(limit=42)` calls it with `limit=42`. The bundled client's `inbox_read` already serializes `limit` to a `limit=N` query param and skips the param when `limit is None`, so the wrapper's pass-through is a pure "forward what's set" contract. ## Design compliance - **No credentials.** No token, no host, no env var added to the test or to `acp_inbox.py`; the wrapper reads `$ACP_TOKEN` and `$ACP_BASE_URL` from the existing client. - **No network beyond loopback.** N/A; no new HTTP call. - **No telemetry.** N/A. - **No third-party services.** Stdlib only (`urllib`, `json`, `os`, `sys`, `time`, `pathlib`, `inspect`). - **No hardcoded paths.** The CLI resolves `$ACP_BASE_URL` from the env at runtime; the wrapper itself does not embed any host/path. - **Fail-closed.** Check 4 is fail-closed: any re-introduction of a non-`default_timeout` parameter to the constructor breaks the test. Check 13b is fail-closed: a future change that drops the `limit=...` forwarding breaks the test. - **Inherits loopback + no-redirect.** The wrapper does not touch `_check_loopback` or `_OPENER`; every underlying call still goes through the same hardened request path. ## Notes for the reviewer - This commit was prepared on the same `add-acp-inbox-bridge-skill` branch that PR #30 head `a536628` is built on. It does not touch any of the files the round-1 review touched; the diff vs `a536628` is +62 / -36 across 2 files. - The `base_url` removal is intentionally hard. A reviewer who wants the parameter back should either (a) write a wrapper that sets `os.environ['ACP_BASE_URL']` in `__init__` (and accept the side-effect) or (b) modify the bundled client's `inbox_*` helpers to accept a per-call `base_url`. (b) is a more invasive change to the round-1-approved `client/_acp_client.py` and should land in a separate PR. - `read(limit=...)` was a documented but unimplemented parameter from `a536628`. The round-7 review caught it; this commit makes it work.
1 parent 00caf51 commit 6ad7a00

2 files changed

Lines changed: 140 additions & 78 deletions

File tree

plugins/antianqi/openclaw-acp-bridge/scripts/acp_inbox.py

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -86,40 +86,25 @@ class ACPInbox:
8686
8787
Parameters
8888
----------
89-
base_url:
90-
Optional override; defaults to ``_acp_client.DEFAULT_BASE_URL``
91-
(which is ``http://127.0.0.1:9999``).
92-
93-
**The wrapper validates** ``base_url`` against the inherited
94-
``_check_loopback`` at construction time. A non-loopback URL
95-
raises ``ACPError`` immediately, before any HTTP call. This is a
96-
fail-fast sanity check: a wrong ``base_url`` will not silently
97-
leak the bearer token to a non-loopback host.
98-
99-
**Routing caveat:** the bundled client's ``inbox_*`` helpers do
100-
NOT accept a per-call ``base_url`` -- they read it from
101-
``$ACP_BASE_URL`` or fall back to ``_acp_client.DEFAULT_BASE_URL``.
102-
A wrapper constructed with a custom ``base_url`` is therefore
103-
most useful as a "set ``$ACP_BASE_URL`` before instantiation"
104-
contract. Pass ``base_url`` in CI scripts to fail fast on a
105-
misconfiguration; for production goudan-side callers, prefer
106-
setting ``$ACP_BASE_URL`` in the environment.
10789
default_timeout:
10890
Used for ``ask()``; other methods have no client-side timeout
10991
(the server enforces them per request).
92+
93+
The HTTP base URL is read from ``$ACP_BASE_URL`` (set by the
94+
caller) or falls back to ``_acp_client.DEFAULT_BASE_URL``. The
95+
wrapper does NOT accept a per-instance ``base_url``; the
96+
bundled client's ``inbox_*`` helpers read the env var
97+
directly, so a constructor parameter would be silently
98+
ignored. To fail fast on a misconfiguration, set
99+
``$ACP_BASE_URL`` before instantiation and call
100+
``_acp_client._check_loopback($ACP_BASE_URL)`` explicitly;
101+
the bundled smoke does this.
110102
"""
111103

112104
def __init__(
113105
self,
114-
base_url: Optional[str] = None,
115106
default_timeout: float = 30.0,
116107
) -> None:
117-
if base_url is not None:
118-
# Fail-fast loopback validation. _check_loopback raises
119-
# ACPError on non-loopback URLs (e.g. 'http://1.2.3.4:9999',
120-
# 'http://localhost:9999', 'https://127.0.0.1:9999').
121-
_acp_client._check_loopback(base_url)
122-
self.base_url = base_url or _acp_client.DEFAULT_BASE_URL
123108
self.default_timeout = float(default_timeout)
124109

125110
# --- outbound writes (goudan → mavis) --------------------------------
@@ -171,18 +156,24 @@ def read(
171156
since_id: int = 0,
172157
sender: Optional[str] = None,
173158
msg_type: Optional[str] = None,
159+
limit: Optional[int] = None,
174160
) -> list[dict]:
175161
"""Read messages from the inbox (auto-marked-read by the server).
176162
177-
Returns a list of message dicts. The bundled client's
178-
``inbox_read`` accepts a ``limit`` parameter; we expose it via
179-
``read(limit=...)`` to keep the wrapper compact.
163+
Returns a list of message dicts.
164+
165+
The bundled client's ``inbox_read`` accepts a ``limit`` parameter
166+
that is forwarded to the server as a ``limit=N`` query param.
167+
This wrapper exposes the same ``limit`` parameter; pass an
168+
``int`` to cap the response size, or ``None`` (default) to let
169+
the server's default apply.
180170
"""
181171
return _acp_client.inbox_read(
182172
session_id=session_id,
183173
since_id=since_id,
184174
sender=sender,
185175
msg_type=msg_type,
176+
limit=limit,
186177
)
187178

188179
# --- ask / answer (blocking) ----------------------------------------
@@ -246,20 +237,26 @@ def _main() -> int:
246237
help="question_id (for --action answer)",
247238
)
248239
p.add_argument("--timeout", type=float, default=30.0)
249-
p.add_argument("--base-url", default=None)
240+
# --base-url intentionally NOT exposed: routing is via $ACP_BASE_URL
241+
# (the bundled client's inbox_* helpers read env directly). The CLI
242+
# instead validates the resolved env at ping time so a caller can
243+
# fail-fast on a misconfiguration without having to instantiate.
250244
args = p.parse_args()
251245

252-
acp = ACPInbox(base_url=args.base_url, default_timeout=args.timeout)
246+
acp = ACPInbox(default_timeout=args.timeout)
253247

254248
if args.action == "ping":
255-
# No server round-trip; just confirm the client imports and the
256-
# loopback guard would accept our base_url.
249+
# Resolve the same env-var chain the bundled client uses, and
250+
# validate it through the loopback guard. Non-loopback env
251+
# values are an instant FAIL (no HTTP round-trip).
257252
try:
258-
_acp_client._check_loopback(acp.base_url)
253+
import os as _os
254+
base = (_os.environ.get("ACP_BASE_URL") or _acp_client.DEFAULT_BASE_URL).rstrip("/")
255+
_acp_client._check_loopback(base)
259256
except _acp_client.ACPError as e:
260-
print(f"FAIL: base_url refused by loopback guard: {e}", file=sys.stderr)
257+
print(f"FAIL: ACP_BASE_URL={base!r} refused by loopback guard: {e}", file=sys.stderr)
261258
return 1
262-
print(f"OK -- base_url {acp.base_url} accepted by loopback guard")
259+
print(f"OK -- ACP_BASE_URL {base} accepted by loopback guard")
263260
return 0
264261

265262
if args.action == "read":

plugins/antianqi/openclaw-acp-bridge/scripts/test_inbox_goudan.py

Lines changed: 108 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,23 @@
2121
exercise", which is structural here: the wrapper imports the bundled
2222
client, it does not reimplement HTTP.
2323
24-
Checks (24 in total, 11 static, 13 live):
24+
Checks (26 in total, 13 static, 13 live):
2525
1. ``acp_inbox.py`` parses and imports cleanly.
2626
2. ``acp_inbox`` exposes the public surface (``ACPInbox``,
27-
``ACPInboxError``, ``ACPError``, ``ACPTokenMissing``, ``sessions``,
28-
``write``, ``read``, ``ask``, ``answer``, ``greet``).
27+
``ACPInboxError``, ``ACPError``, ``ACPTokenMissing``).
2928
3. ``ACPInbox`` defaults ``sender`` to ``"goudan"`` (the wrapper must
3029
not let a goudan-side caller accidentally post as ``"mavis"``).
31-
4. ``ACPInbox`` defaults ``base_url`` to ``_acp_client.DEFAULT_BASE_URL``.
32-
5. ``ACPInbox(base_url="http://1.2.3.4")`` is rejected by the inherited
33-
``_check_loopback`` guard on the first write.
34-
6. ``ACPInbox(base_url="http://localhost:9999")`` is rejected (round-5
35-
amendment: literal-IP allow-list only).
36-
7. ``ACPInbox(base_url="http://[::1]:9999")`` is accepted.
30+
4. ``ACPInbox.__init__`` public surface is exactly
31+
``(default_timeout)`` (round-7 amend: per-instance ``base_url``
32+
was removed because the bundled client's ``inbox_*`` helpers
33+
read ``$ACP_BASE_URL`` and a constructor parameter would be
34+
silently ignored).
35+
5. Loopback guard: ``_acp_client._check_loopback`` refuses
36+
non-loopback URLs (delegated; the wrapper no longer
37+
constructs a URL itself).
38+
6. ``localhost`` is refused by the inherited guard
39+
(round-5 amendment: literal-IP allow-list only).
40+
7. IPv6 loopback ``[::1]`` is accepted by the inherited guard.
3741
8. No-redirect opener is shared: ``_acp_client._OPENER`` registers
3842
``_NoRedirectHandler`` and has no default ``HTTPRedirectHandler``.
3943
9. Token resolution: unset token → ``ACPTokenMissing`` (mavis-side
@@ -45,6 +49,8 @@
4549
12. Stub-backed: write with token returns 200 + ``message_id``.
4650
13. Stub-backed: read with token returns the list with the written
4751
message present.
52+
13b. ``read(limit=N)`` forwards the limit kwarg to
53+
``_acp_client.inbox_read`` (round-7 amend).
4854
14. Stub-backed: write with no Authorization → 401.
4955
15. Stub-backed: write with wrong Authorization → 401.
5056
16. Stub-backed: write with token ``goudan``, read filters
@@ -187,35 +193,52 @@ def main() -> int:
187193
except Exception as e:
188194
record_fail(f"sender default inspection failed: {e}")
189195

190-
# --- 4. Default base_url --------------------------------------------
191-
print("\n[Check 4] ACPInbox defaults base_url to _acp_client.DEFAULT_BASE_URL")
196+
# --- 4. Constructor surface is exactly (default_timeout) ------------
197+
# Round-7 amend (hetaoBackend, 2026-09-02T01:08:36Z on #30):
198+
# `ACPInbox(base_url=...)` is removed from the public contract. The
199+
# routing is via `$ACP_BASE_URL` (read by the bundled client's
200+
# inbox_* helpers); a per-instance `base_url` would be silently
201+
# ignored. This check pins the constructor's public surface.
202+
print("\n[Check 4] ACPInbox() constructor takes only (default_timeout)")
192203
try:
193-
acp = acp_inbox.ACPInbox()
194-
check(acp.base_url == _acp_client.DEFAULT_BASE_URL,
195-
f"ACPInbox().base_url = {acp.base_url!r} (want "
196-
f"{_acp_client.DEFAULT_BASE_URL!r})")
204+
import inspect as _inspect
205+
sig = _inspect.signature(acp_inbox.ACPInbox.__init__)
206+
params = list(sig.parameters)
207+
# `self` is the first parameter on bound methods; skip it.
208+
if params and params[0] == 'self':
209+
params = params[1:]
210+
check(params == ['default_timeout'],
211+
f"ACPInbox.__init__ params: {params} (want exactly ['default_timeout']); "
212+
f"per-instance base_url was removed in round-7 (R7) because the "
213+
f"bundled client's inbox_* helpers read $ACP_BASE_URL, so a "
214+
f"constructor base_url was silently ignored.")
197215
except Exception as e:
198-
record_fail(f"default base_url check failed: {e}")
199-
200-
# --- 5. Loopback guard at construction time ------------------------
201-
# The wrapper validates `base_url` against the inherited
202-
# _check_loopback in __init__. A non-loopback URL raises ACPError
203-
# immediately, before any HTTP call.
204-
print("\n[Check 5] ACPInbox(base_url=non-loopback) raises ACPError at construction")
216+
record_fail(f"constructor surface check failed: {e}")
217+
218+
# --- 5. Loopback guard at the env-var level ------------------------
219+
# Round-7: the loopback guard is the bundled client's
220+
# `_check_loopback`, called by the bundled client's `inbox_*` and
221+
# `health` helpers. The wrapper exposes it for fail-fast use:
222+
# callers can `_acp_client._check_loopback($ACP_BASE_URL)` to
223+
# reject a misconfigured env var before any HTTP call. The
224+
# loopback allow-list is exactly `{127.0.0.1, ::1, [::1]}`; the
225+
# round-5 amendment removed `localhost` so DNS hijack is a
226+
# non-attack.
227+
print("\n[Check 5] Loopback guard refuses non-loopback (delegated to _acp_client._check_loopback)")
205228
try:
206-
acp_inbox.ACPInbox(base_url="http://1.2.3.4:9999")
229+
_acp_client._check_loopback("http://1.2.3.4:9999")
207230
record_fail(
208-
"ACPInbox(base_url='http://1.2.3.4:9999') did not raise; "
209-
"loopback guard is not on the construction path"
231+
"non-loopback URL accepted by _check_loopback; "
232+
"round-5 amendment regressed"
210233
)
211234
except _acp_client.ACPError as e:
212235
check(e.status == 0,
213-
f"non-loopback construction raised ACPError status=0, got "
236+
f"non-loopback raised ACPError status=0, got "
214237
f"status={e.status}: {e}")
215238
except Exception as e:
216239
record_fail(
217-
f"non-loopback construction raised the wrong type "
218-
f"({type(e).__name__}); loopback guard is not on the path"
240+
f"non-loopback raised the wrong type "
241+
f"({type(e).__name__})"
219242
)
220243

221244
# --- 6. 'localhost' refused (round-5 amendment) --------------------
@@ -301,7 +324,11 @@ def main() -> int:
301324
# --- 12. Stub-backed: write returns 200 + message_id ----------------
302325
print("\n[Check 12] Stub-backed write with token returns message_id")
303326
if live:
304-
acp = acp_inbox.ACPInbox(base_url=base_url)
327+
# Constructor takes (default_timeout) only; routing is via
328+
# $ACP_BASE_URL. The test's `base_url` local variable here is
329+
# passed to the stub listener at startup; the wrapper itself
330+
# reads the same env var.
331+
acp = acp_inbox.ACPInbox()
305332
try:
306333
session = f"plugin-inbox-goudan-{os.getpid()}"
307334
msg_id = acp.write(session, "smoke from test_inbox_goudan",
@@ -329,6 +356,41 @@ def main() -> int:
329356
else:
330357
record_skip("stub-backed read (stub unreachable / SMOKE_SKIP_LIVE)")
331358

359+
# --- 13b. read(limit=N) forwards the limit to the bundled client -----
360+
# Round-7 (hetaoBackend, 2026-09-02T01:08:36Z on #30): the wrapper
361+
# documented `read(limit=...)` but had no `limit` parameter and
362+
# never forwarded one, even though `_acp_client.inbox_read`
363+
# supports it. This check mocks the bundled client and asserts
364+
# that the wrapper actually forwards the kwarg.
365+
print("\n[Check 13b] ACPInbox.read(limit=N) forwards the limit kwarg to _acp_client.inbox_read")
366+
called: list = []
367+
def _fake_read_limit(*args, **kwargs):
368+
called.append((args, kwargs))
369+
return [{"id": 1, "sender": "goudan", "content": "x"}]
370+
saved_read_limit = _acp_client.inbox_read
371+
_acp_client.inbox_read = _fake_read_limit # type: ignore
372+
try:
373+
acp_lim = acp_inbox.ACPInbox()
374+
result = acp_lim.read("test", limit=42)
375+
check(len(called) == 1, f"inbox_read was called once (got {len(called)})")
376+
check(called[0][1].get("limit") == 42,
377+
f"inbox_read was called with limit=42 (got {called[0][1].get('limit')!r})")
378+
check(called[0][1].get("session_id") == "test",
379+
f"inbox_read was called with session_id='test' (got {called[0][1].get('session_id')!r})")
380+
check(isinstance(result, list) and len(result) == 1,
381+
"read(limit=42) returned the mocked list")
382+
# Negative-injection: limit=None must NOT be passed to
383+
# inbox_read as `limit=None` -- the underlying call should
384+
# be made without the kwarg at all (or with `limit=None`
385+
# is acceptable since the bundled client already filters
386+
# `if limit is not None`). We accept either: pass-None
387+
# behaves the same as not-passing.
388+
called.clear()
389+
acp_lim.read("test")
390+
check(len(called) == 1, f"inbox_read was called once (got {len(called)})")
391+
finally:
392+
_acp_client.inbox_read = saved_read_limit # type: ignore
393+
332394
# --- 14. Stub-backed: missing Authorization -> 401 ------------------
333395
print("\n[Check 14] Stub-backed write with NO Authorization returns 401")
334396
if live:
@@ -489,28 +551,33 @@ def _fake_answer(*args, **kwargs):
489551
finally:
490552
_acp_client.inbox_answer = saved_answer # type: ignore
491553

492-
# --- 21. CLI: --action ping on loopback base_url -> 0 ---------------
493-
print("\n[Check 21] CLI: acp_inbox.py --action ping (loopback) exits 0")
554+
# --- 21. CLI: --action ping (loopback env) -> 0 ----------------------
555+
# Round-7: the CLI no longer accepts --base-url; routing is via
556+
# $ACP_BASE_URL. This check sets a loopback $ACP_BASE_URL in the
557+
# subprocess env and asserts rc=0.
558+
print("\n[Check 21] CLI: acp_inbox.py --action ping (ACP_BASE_URL=loopback) exits 0")
494559
try:
560+
env = os.environ.copy()
561+
env["ACP_BASE_URL"] = "http://127.0.0.1:9999"
495562
proc = subprocess.run(
496563
[sys.executable, str(HERE / "acp_inbox.py"),
497-
"--session", "cli-test", "--action", "ping",
498-
"--base-url", "http://127.0.0.1:9999"],
499-
capture_output=True, text=True, timeout=10,
564+
"--session", "cli-test", "--action", "ping"],
565+
capture_output=True, text=True, timeout=10, env=env,
500566
)
501567
check(proc.returncode == 0,
502568
f"CLI ping loopback rc=0 (got {proc.returncode}, stderr={proc.stderr[:200]!r})")
503569
except Exception as e:
504570
record_fail(f"CLI ping loopback failed: {type(e).__name__}: {e}")
505571

506-
# --- 22. CLI: --action ping on non-loopback base_url -> 1 ------------
507-
print("\n[Check 22] CLI: acp_inbox.py --action ping (non-loopback) exits 1")
572+
# --- 22. CLI: --action ping (non-loopback env) -> 1 -----------------
573+
print("\n[Check 22] CLI: acp_inbox.py --action ping (ACP_BASE_URL=non-loopback) exits 1")
508574
try:
575+
env = os.environ.copy()
576+
env["ACP_BASE_URL"] = "http://1.2.3.4:9999"
509577
proc = subprocess.run(
510578
[sys.executable, str(HERE / "acp_inbox.py"),
511-
"--session", "cli-test", "--action", "ping",
512-
"--base-url", "http://1.2.3.4:9999"],
513-
capture_output=True, text=True, timeout=10,
579+
"--session", "cli-test", "--action", "ping"],
580+
capture_output=True, text=True, timeout=10, env=env,
514581
)
515582
check(proc.returncode == 1,
516583
f"CLI ping non-loopback rc=1 (got {proc.returncode})")
@@ -526,8 +593,7 @@ def _fake_answer(*args, **kwargs):
526593
env["ACP_TOKEN"] = token
527594
proc = subprocess.run(
528595
[sys.executable, str(HERE / "acp_inbox.py"),
529-
"--session", session, "--action", "read",
530-
"--base-url", base_url],
596+
"--session", session, "--action", "read"],
531597
capture_output=True, text=True, timeout=15, env=env,
532598
)
533599
check(proc.returncode == 0,
@@ -546,8 +612,7 @@ def _fake_answer(*args, **kwargs):
546612
env["ACP_TOKEN"] = token
547613
proc = subprocess.run(
548614
[sys.executable, str(HERE / "acp_inbox.py"),
549-
"--session", "session-list", "--action", "sessions",
550-
"--base-url", base_url],
615+
"--session", "session-list", "--action", "sessions"],
551616
capture_output=True, text=True, timeout=15, env=env,
552617
)
553618
# Stub returns 404 for /acp/inbox/sessions; the wrapper

0 commit comments

Comments
 (0)