arkclaw-webchat-cli 0.6.1__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/PKG-INFO +8 -5
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/README.md +7 -4
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/pyproject.toml +1 -1
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/cli.py +66 -2
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/flows.py +106 -9
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/transport/openclaw.py +29 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/.gitignore +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/__init__.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/attachments.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/config.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/control.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/core.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/doctor.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/errors.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/identity.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/oauth.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/output.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/policy.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/providers.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/secrets_store.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/sts.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/transport/__init__.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/transport/a2a.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/transport/base.py +0 -0
- {arkclaw_webchat_cli-0.6.1 → arkclaw_webchat_cli-0.6.2}/src/ee_claw/update.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arkclaw-webchat-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: CLI to chat with an ArkClaw EE space's Claw over enterprise SSO — zero permanent AK/SK.
|
|
5
5
|
Author: ArkClaw Team
|
|
6
6
|
Keywords: arkclaw,cli,ee,openclaw,sso,sts
|
|
@@ -31,7 +31,7 @@ at a prompt and for another agent/script (`--json` + exit codes).
|
|
|
31
31
|
```bash
|
|
32
32
|
arkclaw init # one-time interactive setup (asks only what it can't auto-detect)
|
|
33
33
|
arkclaw login # browser SSO
|
|
34
|
-
arkclaw agents # list the
|
|
34
|
+
arkclaw agents # list the agents you can chat
|
|
35
35
|
arkclaw chat ci-xxxxxxxx
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -40,7 +40,8 @@ arkclaw chat ci-xxxxxxxx
|
|
|
40
40
|
## What it can do
|
|
41
41
|
|
|
42
42
|
- **Log in as you** — browser SSO (PKCE), short-lived token, auto-refresh. No AK/SK, no client secret, nothing permanent on disk but a token in your OS keychain.
|
|
43
|
-
- **List your agents** — `arkclaw agents` shows the
|
|
43
|
+
- **List your agents** — `arkclaw agents` shows the agents in your accessible claws (add a claw by chatting it once: `arkclaw chat ci-...`).
|
|
44
|
+
- **Manage agents** — `agents create` / `agents delete` add or remove named agents in a claw, right from the terminal.
|
|
44
45
|
- **Chat** — interactive REPL or one-shot `-m`, streaming token-by-token, with a live "what's it doing" spinner and tool-event trace.
|
|
45
46
|
- **Talk to a specific claw** — by id (`chat ci-...`) or by name (`chat 答疑助手`).
|
|
46
47
|
- **Manage a claw's files** — read/write its managed workspace files (`AGENTS.md`, `SOUL.md`, `MEMORY.md`, …) with `ls` / `pull` / `push`.
|
|
@@ -99,14 +100,16 @@ straight to `arkclaw login https://your-space...`. See **[Configuration](#config
|
|
|
99
100
|
|---|---|
|
|
100
101
|
| `arkclaw init [address]` | One-time interactive setup. Saves the address + (only what isn't auto-discovered) the CLI client and STS role to `~/.arkclaw/defaults.json`, so later commands need no env/flags. |
|
|
101
102
|
| `arkclaw login [space-url]` | Browser SSO login. Uses `init` defaults if you omit the URL. `--transport a2a --endpoint <url>` for an agent endpoint. `--clawid ci-...` sets a default claw. Bare `arkclaw login` re-logs into the previous space. |
|
|
102
|
-
| `arkclaw agents` | List the claws you've used from this machine
|
|
103
|
+
| `arkclaw agents` | List the agents in your accessible claws (verified over the ws; inaccessible claws are pruned). Candidate claws = the ones you've used from this machine + your default — add one by chatting it once (`arkclaw chat ci-...`). Not a space-wide directory. |
|
|
104
|
+
| `arkclaw agents create` | Create a named agent in a claw: `--name` `--role` `--soul` (+ optional `--description`, repeatable `--skill`). Then `chat <claw> --agent <agentId>`. |
|
|
105
|
+
| `arkclaw agents delete <agent>` | Delete a named agent by agentId (`a-...`) or display name. Asks for confirmation unless `--yes`; the `main` agent is protected. |
|
|
103
106
|
| `arkclaw chat [TARGET] [MSG]` | Chat. `TARGET` = a claw id (`ci-...`), an agent name (from `agents`), or a profile. With `MSG` → one-shot; without → interactive REPL. `-f` attach files, `-o` write the reply, `--session NAME` name the conversation, `--approve-all` auto-approve tool runs. |
|
|
104
107
|
| `arkclaw <name>` | Shortcut: `arkclaw 答疑助手` ≡ `arkclaw chat 答疑助手`. |
|
|
105
108
|
| `arkclaw ls` | List the claw's managed workspace files. |
|
|
106
109
|
| `arkclaw pull <name> [local]` | Download a managed file to local disk. |
|
|
107
110
|
| `arkclaw push <local> [name]` | Write a local text file into a managed file. |
|
|
108
111
|
| `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
|
|
109
|
-
| `arkclaw sessions` |
|
|
112
|
+
| `arkclaw sessions [claw]` | An agent's conversations from the server (`--agent` to pick one), newest first — resume with `chat --session <会话ID>`, fork with `--new`. Falls back to the local record when offline / a2a. |
|
|
110
113
|
| `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
|
|
111
114
|
| `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
|
|
112
115
|
| `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
|
|
@@ -7,7 +7,7 @@ at a prompt and for another agent/script (`--json` + exit codes).
|
|
|
7
7
|
```bash
|
|
8
8
|
arkclaw init # one-time interactive setup (asks only what it can't auto-detect)
|
|
9
9
|
arkclaw login # browser SSO
|
|
10
|
-
arkclaw agents # list the
|
|
10
|
+
arkclaw agents # list the agents you can chat
|
|
11
11
|
arkclaw chat ci-xxxxxxxx
|
|
12
12
|
```
|
|
13
13
|
|
|
@@ -16,7 +16,8 @@ arkclaw chat ci-xxxxxxxx
|
|
|
16
16
|
## What it can do
|
|
17
17
|
|
|
18
18
|
- **Log in as you** — browser SSO (PKCE), short-lived token, auto-refresh. No AK/SK, no client secret, nothing permanent on disk but a token in your OS keychain.
|
|
19
|
-
- **List your agents** — `arkclaw agents` shows the
|
|
19
|
+
- **List your agents** — `arkclaw agents` shows the agents in your accessible claws (add a claw by chatting it once: `arkclaw chat ci-...`).
|
|
20
|
+
- **Manage agents** — `agents create` / `agents delete` add or remove named agents in a claw, right from the terminal.
|
|
20
21
|
- **Chat** — interactive REPL or one-shot `-m`, streaming token-by-token, with a live "what's it doing" spinner and tool-event trace.
|
|
21
22
|
- **Talk to a specific claw** — by id (`chat ci-...`) or by name (`chat 答疑助手`).
|
|
22
23
|
- **Manage a claw's files** — read/write its managed workspace files (`AGENTS.md`, `SOUL.md`, `MEMORY.md`, …) with `ls` / `pull` / `push`.
|
|
@@ -75,14 +76,16 @@ straight to `arkclaw login https://your-space...`. See **[Configuration](#config
|
|
|
75
76
|
|---|---|
|
|
76
77
|
| `arkclaw init [address]` | One-time interactive setup. Saves the address + (only what isn't auto-discovered) the CLI client and STS role to `~/.arkclaw/defaults.json`, so later commands need no env/flags. |
|
|
77
78
|
| `arkclaw login [space-url]` | Browser SSO login. Uses `init` defaults if you omit the URL. `--transport a2a --endpoint <url>` for an agent endpoint. `--clawid ci-...` sets a default claw. Bare `arkclaw login` re-logs into the previous space. |
|
|
78
|
-
| `arkclaw agents` | List the claws you've used from this machine
|
|
79
|
+
| `arkclaw agents` | List the agents in your accessible claws (verified over the ws; inaccessible claws are pruned). Candidate claws = the ones you've used from this machine + your default — add one by chatting it once (`arkclaw chat ci-...`). Not a space-wide directory. |
|
|
80
|
+
| `arkclaw agents create` | Create a named agent in a claw: `--name` `--role` `--soul` (+ optional `--description`, repeatable `--skill`). Then `chat <claw> --agent <agentId>`. |
|
|
81
|
+
| `arkclaw agents delete <agent>` | Delete a named agent by agentId (`a-...`) or display name. Asks for confirmation unless `--yes`; the `main` agent is protected. |
|
|
79
82
|
| `arkclaw chat [TARGET] [MSG]` | Chat. `TARGET` = a claw id (`ci-...`), an agent name (from `agents`), or a profile. With `MSG` → one-shot; without → interactive REPL. `-f` attach files, `-o` write the reply, `--session NAME` name the conversation, `--approve-all` auto-approve tool runs. |
|
|
80
83
|
| `arkclaw <name>` | Shortcut: `arkclaw 答疑助手` ≡ `arkclaw chat 答疑助手`. |
|
|
81
84
|
| `arkclaw ls` | List the claw's managed workspace files. |
|
|
82
85
|
| `arkclaw pull <name> [local]` | Download a managed file to local disk. |
|
|
83
86
|
| `arkclaw push <local> [name]` | Write a local text file into a managed file. |
|
|
84
87
|
| `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
|
|
85
|
-
| `arkclaw sessions` |
|
|
88
|
+
| `arkclaw sessions [claw]` | An agent's conversations from the server (`--agent` to pick one), newest first — resume with `chat --session <会话ID>`, fork with `--new`. Falls back to the local record when offline / a2a. |
|
|
86
89
|
| `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
|
|
87
90
|
| `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
|
|
88
91
|
| `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "arkclaw-webchat-cli"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.2"
|
|
8
8
|
description = "CLI to chat with an ArkClaw EE space's Claw over enterprise SSO — zero permanent AK/SK."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -259,14 +259,76 @@ def push(
|
|
|
259
259
|
_run(emitter, lambda: flows.do_push(local, remote, emitter, clawid=clawid))
|
|
260
260
|
|
|
261
261
|
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
agents_app = typer.Typer()
|
|
263
|
+
app.add_typer(agents_app, name="agents")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@agents_app.callback(invoke_without_command=True)
|
|
267
|
+
def agents(ctx: typer.Context, json_mode: bool = _json_opt()) -> None:
|
|
264
268
|
"""List the agents you can chat with (openclaw: the agents in your accessible
|
|
265
269
|
claws; a2a: the agent at the endpoint). Then `chat <claw-or-name>`."""
|
|
270
|
+
if ctx.invoked_subcommand is not None:
|
|
271
|
+
# `agents --json create …` must honor the group-level flag — stash it
|
|
272
|
+
# for the subcommand (click contexts inherit obj), never drop it.
|
|
273
|
+
ctx.obj = {"json": json_mode}
|
|
274
|
+
return
|
|
266
275
|
emitter = Emitter(json_mode=json_mode)
|
|
267
276
|
_run(emitter, lambda: flows.do_agents(emitter))
|
|
268
277
|
|
|
269
278
|
|
|
279
|
+
def _group_json(ctx: typer.Context, json_mode: bool) -> bool:
|
|
280
|
+
"""A subcommand's effective --json: its own flag OR the group-level one."""
|
|
281
|
+
return json_mode or bool((ctx.obj or {}).get("json"))
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@agents_app.command("create")
|
|
285
|
+
def agents_create(
|
|
286
|
+
ctx: typer.Context,
|
|
287
|
+
name: str = typer.Option(..., "--name", help="Agent display name."),
|
|
288
|
+
role: str = typer.Option(..., "--role", help="One-line role (what this agent does)."),
|
|
289
|
+
soul: str = typer.Option(
|
|
290
|
+
..., "--soul", help="Persona / system instructions (the agent's SOUL.md)."
|
|
291
|
+
),
|
|
292
|
+
description: str | None = typer.Option(None, "--description", help="Optional description."),
|
|
293
|
+
skill: list[str] = typer.Option(
|
|
294
|
+
[], "--skill", help="Skill to enable (repeat for several)."
|
|
295
|
+
),
|
|
296
|
+
clawid: str | None = typer.Option(
|
|
297
|
+
None, "--clawid", help="Claw instance id (ci-...). Omit to use your default claw."
|
|
298
|
+
),
|
|
299
|
+
json_mode: bool = _json_opt(),
|
|
300
|
+
) -> None:
|
|
301
|
+
"""Create a named agent in a claw. Then `arkclaw chat <claw> --agent <agentId>`."""
|
|
302
|
+
emitter = Emitter(json_mode=_group_json(ctx, json_mode))
|
|
303
|
+
_run(
|
|
304
|
+
emitter,
|
|
305
|
+
lambda: flows.do_agents_create(
|
|
306
|
+
emitter,
|
|
307
|
+
name=name,
|
|
308
|
+
role=role,
|
|
309
|
+
soul=soul,
|
|
310
|
+
description=description,
|
|
311
|
+
skills=list(skill),
|
|
312
|
+
clawid=clawid,
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@agents_app.command("delete")
|
|
318
|
+
def agents_delete(
|
|
319
|
+
ctx: typer.Context,
|
|
320
|
+
agent: str = typer.Argument(..., help="agentId (a-...) or display name to delete."),
|
|
321
|
+
clawid: str | None = typer.Option(
|
|
322
|
+
None, "--clawid", help="Claw instance id (ci-...). Omit to use your default claw."
|
|
323
|
+
),
|
|
324
|
+
yes: bool = typer.Option(False, "--yes", help="Skip the confirmation prompt."),
|
|
325
|
+
json_mode: bool = _json_opt(),
|
|
326
|
+
) -> None:
|
|
327
|
+
"""Delete a named agent from a claw (asks for confirmation unless --yes)."""
|
|
328
|
+
emitter = Emitter(json_mode=_group_json(ctx, json_mode))
|
|
329
|
+
_run(emitter, lambda: flows.do_agents_delete(emitter, agent, clawid=clawid, yes=yes))
|
|
330
|
+
|
|
331
|
+
|
|
270
332
|
@app.command()
|
|
271
333
|
def fanout(
|
|
272
334
|
message: str = typer.Argument(..., help="The message to send to every claw."),
|
|
@@ -412,6 +474,8 @@ def _schema_data() -> dict:
|
|
|
412
474
|
for name, cmd in sorted(getattr(root, "commands", {}).items()):
|
|
413
475
|
subs = getattr(cmd, "commands", None)
|
|
414
476
|
if subs:
|
|
477
|
+
if getattr(cmd, "invoke_without_command", False):
|
|
478
|
+
commands.append(info(name, cmd)) # the bare group is a command too
|
|
415
479
|
commands.extend(info(f"{name} {s}", c) for s, c in sorted(subs.items()))
|
|
416
480
|
else:
|
|
417
481
|
commands.append(info(name, cmd))
|
|
@@ -52,7 +52,7 @@ from ee_claw.identity import (
|
|
|
52
52
|
read_chrome_recent_claw,
|
|
53
53
|
)
|
|
54
54
|
from ee_claw.oauth import OAuthClient
|
|
55
|
-
from ee_claw.output import Emitter
|
|
55
|
+
from ee_claw.output import Emitter, sanitize
|
|
56
56
|
from ee_claw.providers import ProviderContext, resolve_token_source
|
|
57
57
|
from ee_claw.sts import assume_role_with_oidc
|
|
58
58
|
from ee_claw.transport.a2a import A2ATransport, agent_card
|
|
@@ -1201,15 +1201,14 @@ def do_agents(emitter: Emitter) -> dict[str, Any]:
|
|
|
1201
1201
|
return {"current": current}
|
|
1202
1202
|
|
|
1203
1203
|
|
|
1204
|
-
def
|
|
1205
|
-
|
|
1206
|
-
|
|
1204
|
+
def _openclaw_claw_transport(
|
|
1205
|
+
clawid: str | None, *, feature: str, hint: str
|
|
1206
|
+
) -> tuple[OpenClawTransport, str]:
|
|
1207
|
+
"""Build an OpenClawTransport against the given (or default) claw for an
|
|
1208
|
+
openclaw-only feature. Returns (transport, clawid)."""
|
|
1207
1209
|
cfg, id_token = _load_session()
|
|
1208
1210
|
if cfg.transport != "openclaw":
|
|
1209
|
-
raise ValidationError(
|
|
1210
|
-
"文件传输目前仅支持 openclaw transport(claw 工作区文件)。",
|
|
1211
|
-
hint="A2A agent 没有可直传的工作区文件系统。",
|
|
1212
|
-
)
|
|
1211
|
+
raise ValidationError(f"{feature}目前仅支持 openclaw transport。", hint=hint)
|
|
1213
1212
|
clawid = clawid or cfg.claw
|
|
1214
1213
|
if not clawid:
|
|
1215
1214
|
raise NoClawError("未指定 claw。", hint="加 --clawid <ci-...>。")
|
|
@@ -1221,6 +1220,104 @@ def _openclaw_file_transport(clawid: str | None) -> tuple[OpenClawTransport, str
|
|
|
1221
1220
|
), clawid
|
|
1222
1221
|
|
|
1223
1222
|
|
|
1223
|
+
def _openclaw_file_transport(clawid: str | None) -> tuple[OpenClawTransport, str]:
|
|
1224
|
+
"""Build an OpenClawTransport for file transfer (openclaw-only). Returns
|
|
1225
|
+
(transport, clawid)."""
|
|
1226
|
+
return _openclaw_claw_transport(
|
|
1227
|
+
clawid, feature="文件传输", hint="A2A agent 没有可直传的工作区文件系统。"
|
|
1228
|
+
)
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
def _agent_mgmt_transport(clawid: str | None) -> tuple[OpenClawTransport, str]:
|
|
1232
|
+
return _openclaw_claw_transport(
|
|
1233
|
+
clawid, feature="agent 管理", hint="A2A 模式连接的是单个 agent 端点,没有可管理的 claw。"
|
|
1234
|
+
)
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
def do_agents_create(
|
|
1238
|
+
emitter: Emitter,
|
|
1239
|
+
*,
|
|
1240
|
+
name: str,
|
|
1241
|
+
role: str,
|
|
1242
|
+
soul: str,
|
|
1243
|
+
description: str | None = None,
|
|
1244
|
+
skills: list[str] | None = None,
|
|
1245
|
+
clawid: str | None = None,
|
|
1246
|
+
) -> dict[str, Any]:
|
|
1247
|
+
"""``arkclaw agents create``: create a named agent in a claw (ws RPC
|
|
1248
|
+
``arkclaw.team.agent.create``; live-calibrated 2026-06-10). The server
|
|
1249
|
+
requires name+role+soul; skills may be empty."""
|
|
1250
|
+
for label, value in (("--name", name), ("--role", role), ("--soul", soul)):
|
|
1251
|
+
if not value.strip():
|
|
1252
|
+
raise ValidationError(f"{label} 不能为空。")
|
|
1253
|
+
if name.strip().startswith("a-") or name.strip() == "main":
|
|
1254
|
+
raise ValidationError(
|
|
1255
|
+
f"--name 不能是 {name.strip()!r} — 会与 agentId 命名空间(a-…/main)冲突。"
|
|
1256
|
+
)
|
|
1257
|
+
transport, clawid = _agent_mgmt_transport(clawid)
|
|
1258
|
+
raw = asyncio.run(
|
|
1259
|
+
transport.create_agent(
|
|
1260
|
+
name=name, role=role, soul=soul, description=description, skills=skills or []
|
|
1261
|
+
)
|
|
1262
|
+
)
|
|
1263
|
+
agent = redact_obj(raw)
|
|
1264
|
+
assert isinstance(agent, dict) # redact_obj preserves the dict shape
|
|
1265
|
+
aid = str(agent.get("agentId") or "")
|
|
1266
|
+
emitter.line(f"✓ 已创建 agent {agent.get('name') or name}({aid or '?'})· claw {clawid}")
|
|
1267
|
+
if aid:
|
|
1268
|
+
emitter.line(f" 开聊: arkclaw chat {clawid} --agent {aid}")
|
|
1269
|
+
return {"claw": clawid, "agent": agent}
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
def do_agents_delete(
|
|
1273
|
+
emitter: Emitter, agent: str, *, clawid: str | None = None, yes: bool = False
|
|
1274
|
+
) -> dict[str, Any]:
|
|
1275
|
+
"""``arkclaw agents delete``: remove a named agent from a claw (ws RPC
|
|
1276
|
+
``arkclaw.team.agent.delete``). Accepts an agentId (``a-…``) or the agent's
|
|
1277
|
+
display name; either way the target is resolved against the claw's live
|
|
1278
|
+
agent list first — so a typo'd id can't delete anything, an ``a-…``-looking
|
|
1279
|
+
display name can't shadow another agent's id, and the claw's default agent
|
|
1280
|
+
(``main`` or ``default: true``) stays protected."""
|
|
1281
|
+
if agent == "main": # fail fast — no network needed to refuse this
|
|
1282
|
+
raise ValidationError("默认(main)agent 不能删除。")
|
|
1283
|
+
transport, clawid = _agent_mgmt_transport(clawid)
|
|
1284
|
+
agents = asyncio.run(transport.list_agents())
|
|
1285
|
+
matches = [a for a in agents if str(a.get("agentId") or "") == agent]
|
|
1286
|
+
if not matches: # not an id → try the display name
|
|
1287
|
+
matches = [a for a in agents if str(a.get("name") or "") == agent]
|
|
1288
|
+
if len(matches) > 1:
|
|
1289
|
+
ids = ", ".join(str(a.get("agentId") or "?") for a in matches)
|
|
1290
|
+
raise ValidationError(
|
|
1291
|
+
f"名称 {agent!r} 对应多个 agent({ids}),请直接用 agentId。"
|
|
1292
|
+
)
|
|
1293
|
+
if not matches:
|
|
1294
|
+
raise ValidationError(
|
|
1295
|
+
f"claw {clawid} 里没有 agentId 或名称为 {agent!r} 的 agent。",
|
|
1296
|
+
hint="用 `arkclaw agents` 查看 agentId 与名称。",
|
|
1297
|
+
)
|
|
1298
|
+
target = matches[0]
|
|
1299
|
+
agent_id = str(target.get("agentId") or "")
|
|
1300
|
+
if not agent_id:
|
|
1301
|
+
raise ValidationError(f"服务端没有给出 {agent!r} 的 agentId,无法安全删除。")
|
|
1302
|
+
if agent_id == "main" or bool(target.get("default")):
|
|
1303
|
+
raise ValidationError("默认(main)agent 不能删除。")
|
|
1304
|
+
if not yes:
|
|
1305
|
+
if emitter.json or not sys.stdin.isatty():
|
|
1306
|
+
raise ValidationError("headless 删除必须显式 --yes。")
|
|
1307
|
+
# agent_id is upstream content: sanitize before it touches the TTY —
|
|
1308
|
+
# input() bypasses Emitter.line's control-char stripping.
|
|
1309
|
+
prompt = sanitize(f"确认删除 claw {clawid} 的 agent {agent_id}? [y/N] ")
|
|
1310
|
+
answer = input(prompt).strip().lower()
|
|
1311
|
+
if answer not in ("y", "yes"):
|
|
1312
|
+
emitter.line("已取消。")
|
|
1313
|
+
return {"cancelled": True}
|
|
1314
|
+
result = redact_obj(asyncio.run(transport.delete_agent(agent_id)))
|
|
1315
|
+
if isinstance(result, dict) and result.get("success") is False:
|
|
1316
|
+
raise NetworkError(f"claw 未确认删除 agent {agent_id}(success=false)。")
|
|
1317
|
+
emitter.line(f"✓ 已删除 agent {agent_id} · claw {clawid}")
|
|
1318
|
+
return {"claw": clawid, "agentId": agent_id, "result": result}
|
|
1319
|
+
|
|
1320
|
+
|
|
1224
1321
|
def do_ls(emitter: Emitter, *, clawid: str | None = None) -> dict[str, Any]:
|
|
1225
1322
|
"""``arkclaw ls``: list files in the claw workspace."""
|
|
1226
1323
|
transport, clawid = _openclaw_file_transport(clawid)
|
|
@@ -1426,7 +1523,7 @@ def do_claw(
|
|
|
1426
1523
|
if op == "delete" and not yes:
|
|
1427
1524
|
if emitter.json or not sys.stdin.isatty():
|
|
1428
1525
|
raise ValidationError("headless 删除必须显式 --yes。")
|
|
1429
|
-
answer = input(f"确认删除 claw {clawid}? [y/N] ").strip().lower()
|
|
1526
|
+
answer = input(sanitize(f"确认删除 claw {clawid}? [y/N] ")).strip().lower()
|
|
1430
1527
|
if answer not in ("y", "yes"):
|
|
1431
1528
|
emitter.line("已取消。")
|
|
1432
1529
|
return {"cancelled": True}
|
|
@@ -527,6 +527,35 @@ class OpenClawTransport:
|
|
|
527
527
|
return [a for a in v if isinstance(a, dict)]
|
|
528
528
|
return []
|
|
529
529
|
|
|
530
|
+
async def create_agent(
|
|
531
|
+
self,
|
|
532
|
+
*,
|
|
533
|
+
name: str,
|
|
534
|
+
role: str,
|
|
535
|
+
soul: str,
|
|
536
|
+
description: str | None = None,
|
|
537
|
+
skills: Sequence[str] = (),
|
|
538
|
+
) -> dict[str, Any]:
|
|
539
|
+
"""Create a named agent in this claw (ws RPC ``arkclaw.team.agent.create``).
|
|
540
|
+
The server requires name + role + soul + skills (array, may be empty);
|
|
541
|
+
returns the created agent ``{agentId, name, role, soul, …}``."""
|
|
542
|
+
params: dict[str, Any] = {
|
|
543
|
+
"name": name,
|
|
544
|
+
"role": role,
|
|
545
|
+
"soul": soul,
|
|
546
|
+
"skills": list(skills),
|
|
547
|
+
}
|
|
548
|
+
if description:
|
|
549
|
+
params["description"] = description
|
|
550
|
+
payload = await self._request("arkclaw.team.agent.create", params)
|
|
551
|
+
return payload if isinstance(payload, dict) else {}
|
|
552
|
+
|
|
553
|
+
async def delete_agent(self, agent_id: str) -> dict[str, Any]:
|
|
554
|
+
"""Delete an agent from this claw (ws RPC ``arkclaw.team.agent.delete``).
|
|
555
|
+
Returns the server ack (``{success: true}``)."""
|
|
556
|
+
payload = await self._request("arkclaw.team.agent.delete", {"agentId": agent_id})
|
|
557
|
+
return payload if isinstance(payload, dict) else {}
|
|
558
|
+
|
|
530
559
|
async def list_sessions(self, agent_id: str = "main") -> list[dict[str, Any]]:
|
|
531
560
|
"""An agent's conversations (ws RPC ``sessions.list``). Each item:
|
|
532
561
|
``{key, sessionId, derivedTitle?, updatedAt, status, ...}`` — ``key`` is
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|