agenticros 0.3.3 → 0.3.5
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.
- package/README.md +25 -7
- package/dist/__tests__/claude-config.test.d.ts +2 -0
- package/dist/__tests__/claude-config.test.d.ts.map +1 -0
- package/dist/__tests__/claude-config.test.js +77 -0
- package/dist/__tests__/claude-config.test.js.map +1 -0
- package/dist/__tests__/mcp-setup.test.d.ts +2 -0
- package/dist/__tests__/mcp-setup.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-setup.test.js +23 -0
- package/dist/__tests__/mcp-setup.test.js.map +1 -0
- package/dist/commands/claude.d.ts +16 -0
- package/dist/commands/claude.d.ts.map +1 -0
- package/dist/commands/claude.js +30 -0
- package/dist/commands/claude.js.map +1 -0
- package/dist/commands/codex.d.ts +4 -4
- package/dist/commands/codex.d.ts.map +1 -1
- package/dist/commands/codex.js +21 -90
- package/dist/commands/codex.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +22 -27
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hermes.d.ts +3 -3
- package/dist/commands/hermes.d.ts.map +1 -1
- package/dist/commands/hermes.js +13 -76
- package/dist/commands/hermes.js.map +1 -1
- package/dist/commands/init.d.ts +2 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +16 -38
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts +20 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +31 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -1
- package/dist/util/claude-config.d.ts +47 -0
- package/dist/util/claude-config.d.ts.map +1 -0
- package/dist/util/claude-config.js +227 -0
- package/dist/util/claude-config.js.map +1 -0
- package/dist/util/mcp-setup.d.ts +55 -0
- package/dist/util/mcp-setup.d.ts.map +1 -0
- package/dist/util/mcp-setup.js +235 -0
- package/dist/util/mcp-setup.js.map +1 -0
- package/dist/util/skill-manifest.d.ts.map +1 -1
- package/dist/util/skill-manifest.js +22 -1
- package/dist/util/skill-manifest.js.map +1 -1
- package/package.json +1 -1
- package/runtime/BUNDLE.json +1 -1
- package/runtime/README.md +31 -6
- package/runtime/docs/cli.md +54 -14
- package/runtime/docs/robot-setup.md +1 -1
- package/runtime/packages/agenticros/openclaw.plugin.json +147 -1
- package/runtime/packages/agenticros/src/__tests__/capabilities-plugin.test.ts +2 -0
- package/runtime/packages/agenticros/src/routes.ts +4 -3
- package/runtime/packages/agenticros/src/tools/index.ts +6 -5
- package/runtime/packages/agenticros/src/tools/mission-pause.ts +49 -0
- package/runtime/packages/agenticros/src/tools/mission-resume.ts +41 -0
- package/runtime/packages/agenticros/src/tools/ros2-mission.ts +33 -84
- package/runtime/packages/agenticros-claude-code/README.md +2 -0
- package/runtime/packages/agenticros-claude-code/dist/tools.d.ts.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/tools.js +130 -111
- package/runtime/packages/agenticros-claude-code/dist/tools.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/src/tools.ts +140 -99
- package/runtime/packages/agenticros-gemini/package.json +2 -0
- package/runtime/packages/agenticros-gemini/src/find-object/coco-classes.ts +38 -0
- package/runtime/packages/agenticros-gemini/src/find-object/find-object.ts +191 -0
- package/runtime/packages/agenticros-gemini/src/follow-me/controller.ts +109 -0
- package/runtime/packages/agenticros-gemini/src/follow-me/depth-loop.ts +452 -0
- package/runtime/packages/agenticros-gemini/src/follow-me/detector.ts +303 -0
- package/runtime/packages/agenticros-gemini/src/follow-me/loop.ts +359 -0
- package/runtime/packages/agenticros-gemini/src/tools.ts +351 -90
- package/runtime/packages/core/README.md +1 -1
- package/runtime/packages/core/package.json +1 -1
- package/runtime/packages/core/src/__tests__/config-persistence.test.ts +26 -0
- package/runtime/packages/core/src/__tests__/external-capability.test.ts +72 -0
- package/runtime/packages/core/src/__tests__/heartbeat-fleet.test.ts +152 -0
- package/runtime/packages/core/src/__tests__/mission-bindings.test.ts +101 -0
- package/runtime/packages/core/src/__tests__/mission-pause.test.ts +104 -0
- package/runtime/packages/core/src/capabilities.ts +38 -3
- package/runtime/packages/core/src/capability-schema.ts +58 -0
- package/runtime/packages/core/src/config.ts +20 -0
- package/runtime/packages/core/src/discovery.ts +21 -3
- package/runtime/packages/core/src/external-capability.ts +219 -0
- package/runtime/packages/core/src/fleet-config.ts +91 -0
- package/runtime/packages/core/src/heartbeat.ts +167 -0
- package/runtime/packages/core/src/index.ts +55 -0
- package/runtime/packages/core/src/mission-bindings.ts +189 -0
- package/runtime/packages/core/src/mission-registry.ts +31 -3
- package/runtime/packages/core/src/mission.ts +64 -7
- package/runtime/packages/core/src/robots.ts +6 -2
- package/runtime/packages/core/src/transport/rosbridge/client.ts +7 -0
- package/runtime/pnpm-lock.yaml +6 -0
- package/templates/skills/camera/package.json +1 -1
- package/templates/skills/depth/package.json +1 -1
- package/templates/skills/robot/package.json +1 -1
package/runtime/README.md
CHANGED
|
@@ -33,6 +33,29 @@ With AgenticROS, your robot can describe what it sees, follow intent ("go check
|
|
|
33
33
|
|
|
34
34
|
AgenticROS is built so that new adapters (LangGraph, OpenAI, local models, voice stacks, etc.) can be added without touching the ROS 2 layer. The core transport and tool contract are platform-agnostic; adapters are thin shims that surface those tools to each agent runtime.
|
|
35
35
|
|
|
36
|
+
## Local VLM (Ollama) — no cloud API required
|
|
37
|
+
|
|
38
|
+
Control your robot with a **local vision-language model** instead of OpenAI or other cloud APIs. AgenticROS robot tools work the same; you point **OpenClaw** or **Hermes** at Ollama on your machine.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ollama pull qwen3-vl:8b-instruct # recommended: chat + tools + camera vision
|
|
42
|
+
# or: ollama pull qwen3-vl:2b # smaller hardware
|
|
43
|
+
|
|
44
|
+
npx agenticros init # skip the OpenAI key step when prompted
|
|
45
|
+
# Configure OpenClaw to use Ollama as primary model (see guide below)
|
|
46
|
+
agenticros up sim-amr # or: agenticros up real
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then chat in OpenClaw web UI or Hermes: *"List ROS topics"*, *"drive forward slowly"*, *"what do you see?"*
|
|
50
|
+
|
|
51
|
+
| Path | Best for |
|
|
52
|
+
|------|----------|
|
|
53
|
+
| **OpenClaw + Ollama** | Web chat, teleop, messaging channels, skills |
|
|
54
|
+
| **Hermes + Ollama** | Terminal agent with any Ollama model |
|
|
55
|
+
| **NemoClaw + Ollama** | Sandboxed Jetson / edge (see [docs/nemoclaw.md](docs/nemoclaw.md)) |
|
|
56
|
+
|
|
57
|
+
**Full setup, model picks, multimodal catalog patches, describer, Follow Me VLM, and troubleshooting:** **[docs/local-vlm.md](docs/local-vlm.md)**
|
|
58
|
+
|
|
36
59
|
## Architecture
|
|
37
60
|
|
|
38
61
|

|
|
@@ -103,6 +126,8 @@ On the ROS side, every robot publishes a 1 Hz heartbeat on `<ns>/agenticros/robo
|
|
|
103
126
|
|
|
104
127
|
`mission_cancel({ mission_id })` flips an in-process cancellation token; the runner stops at the next step boundary and marks remaining steps `cancelled`. When the [shared memory backend](#memory-optional) is on, every step is also written to `mission:<id>` in long-term memory, tagged with `step:<status>` and `capability:<id>`. A different agent — different process, different vendor — can `memory_recall` later and reconstruct exactly what happened, so two agents can collaborate on or hand off a mission.
|
|
105
128
|
|
|
129
|
+
**How-to:** step-by-step fleet setup, declarative plans, NL goals, cancel, and handoff — **[docs/missions.md](docs/missions.md)**. Runnable walkthrough: **[examples/find-and-approach/README.md](examples/find-and-approach/README.md)**.
|
|
130
|
+
|
|
106
131
|
Full architecture + design trade-offs: **[docs/strategy-ai-agents-plus-ros.md](docs/strategy-ai-agents-plus-ros.md)**.
|
|
107
132
|
|
|
108
133
|
## Repository layout
|
|
@@ -112,7 +137,7 @@ Full architecture + design trade-offs: **[docs/strategy-ai-agents-plus-ros.md](d
|
|
|
112
137
|
- `**packages/agenticros-claude-code**` — MCP server for Claude Code + Claude desktop / Dispatch (tools only; no config UI).
|
|
113
138
|
- `**packages/agenticros-gemini**` — Gemini CLI (function calling; no MCP).
|
|
114
139
|
- `**ros2_ws/**` — ROS2 workspace: `agenticros_msgs`, `agenticros_bringup` (Gazebo + RViz + rosbridge launches), `agenticros_discovery`, `agenticros_agent`, `agenticros_follow_me`.
|
|
115
|
-
- `**docs/**` — Architecture, skills, robot setup, Zenoh, teleop.
|
|
140
|
+
- `**docs/**` — Architecture, skills, robot setup, Zenoh, teleop, **[local VLM / Ollama](docs/local-vlm.md)**.
|
|
116
141
|
- `**scripts/**` — Workspace setup, gateway plugin config, run demos.
|
|
117
142
|
- `**docker/**` — Docker Compose and Dockerfiles for ROS2 + plugin images.
|
|
118
143
|
- `**examples/**` — Example projects.
|
|
@@ -138,7 +163,7 @@ The first run launches the interactive menu:
|
|
|
138
163
|
? What would you like to do?
|
|
139
164
|
Launch with real robot
|
|
140
165
|
❯ Launch with simulation
|
|
141
|
-
First-time setup (workspace + OpenClaw plugin + Codex MCP + API key)
|
|
166
|
+
First-time setup (workspace + OpenClaw plugin + Codex MCP + optional API key)
|
|
142
167
|
Manage skills (2 registered, 0 available, 0 broken)
|
|
143
168
|
Stop everything
|
|
144
169
|
Doctor (health check)
|
|
@@ -146,8 +171,8 @@ The first run launches the interactive menu:
|
|
|
146
171
|
Tail logs
|
|
147
172
|
```
|
|
148
173
|
|
|
149
|
-
Pick **First-time setup** once (workspace + OpenClaw plugin + optional Codex MCP + API key, all
|
|
150
|
-
idempotent)
|
|
174
|
+
Pick **First-time setup** once (workspace + OpenClaw plugin + optional Codex MCP + optional API key, all
|
|
175
|
+
idempotent). **Using local Ollama instead of OpenAI?** Skip the API key step — see **[Local VLM (Ollama)](#local-vlm-ollama--no-cloud-api-required)**. Then choose how you want to run:
|
|
151
176
|
|
|
152
177
|
| You want to … | Pick |
|
|
153
178
|
|---|---|
|
|
@@ -163,7 +188,7 @@ so **Stop everything** cleanly tears the demo down.
|
|
|
163
188
|
Prefer scripted invocations? Every menu item maps to a direct command:
|
|
164
189
|
|
|
165
190
|
```bash
|
|
166
|
-
npx agenticros init # one-time workspace + plugin + Codex/Hermes MCP + API key
|
|
191
|
+
npx agenticros init # one-time workspace + plugin + Codex/Hermes MCP (+ optional API key)
|
|
167
192
|
agenticros codex setup # register AgenticROS MCP for OpenAI Codex CLI
|
|
168
193
|
agenticros codex doctor # validate ~/.codex/config.toml
|
|
169
194
|
agenticros hermes setup # register AgenticROS MCP for Hermes Agent
|
|
@@ -212,7 +237,7 @@ needing token auth: run `node scripts/agenticros-proxy.cjs 18790` and open
|
|
|
212
237
|
See **[docs/openclaw-releases-and-plugin-routes.md](docs/openclaw-releases-and-plugin-routes.md)**
|
|
213
238
|
and **[docs/teleop.md](docs/teleop.md)**.
|
|
214
239
|
|
|
215
|
-
See **`docs/`** for robot setup, skills, teleop, simulation internals, and Docker.
|
|
240
|
+
See **`docs/`** for robot setup, **[missions](docs/missions.md)**, skills, teleop, simulation internals, and Docker.
|
|
216
241
|
|
|
217
242
|
## RViz2 and Gazebo (TurtleBot3 + rosbridge)
|
|
218
243
|
|
package/runtime/docs/cli.md
CHANGED
|
@@ -64,10 +64,9 @@ skipped (with a checkmark) when already done:
|
|
|
64
64
|
3. ROS 2 workspace build (`colcon build --symlink-install`)
|
|
65
65
|
4. OpenClaw plugin install (via `scripts/setup_gateway_plugin.sh`)
|
|
66
66
|
5. Robot config (writes `~/.agenticros/config.json`)
|
|
67
|
-
6. OpenAI API key (
|
|
68
|
-
7.
|
|
69
|
-
8.
|
|
70
|
-
9. Final `agenticros doctor` summary
|
|
67
|
+
6. OpenAI API key (optional — skip when using local Ollama; see [local-vlm.md](local-vlm.md))
|
|
68
|
+
7. MCP client config (optional — `agenticros mcp setup` for Codex, Hermes, and Claude)
|
|
69
|
+
8. Final `agenticros doctor` summary
|
|
71
70
|
|
|
72
71
|
Pass `--force` to re-run every step regardless of state.
|
|
73
72
|
|
|
@@ -85,9 +84,31 @@ same report as a structured object for CI / scripting:
|
|
|
85
84
|
|
|
86
85
|
Exits non-zero if any check is red.
|
|
87
86
|
|
|
88
|
-
Checks include MCP server build status, OpenClaw plugin health, **
|
|
89
|
-
(
|
|
90
|
-
|
|
87
|
+
Checks include MCP server build status, OpenClaw plugin health, **MCP client configs**
|
|
88
|
+
(Codex, Hermes, Claude — path and namespace policy), and CLI presence on `PATH`.
|
|
89
|
+
|
|
90
|
+
### `agenticros mcp setup [--codex] [--hermes] [--claude] [--project] [--desktop]`
|
|
91
|
+
|
|
92
|
+
**Primary command** — register the AgenticROS MCP server for all MCP clients at once:
|
|
93
|
+
|
|
94
|
+
| Flag | Effect |
|
|
95
|
+
|---|---|
|
|
96
|
+
| (default) | Codex (`~/.codex/config.toml` + project `.codex/config.toml`), Hermes (`~/.hermes/config.yaml`), Claude Desktop + project `.mcp.json` |
|
|
97
|
+
| `--codex` | Codex global config only |
|
|
98
|
+
| `--hermes` | Hermes global config only |
|
|
99
|
+
| `--claude` | Claude Desktop + project `.mcp.json` |
|
|
100
|
+
| `--project` | Also write project-scoped Codex / Claude configs |
|
|
101
|
+
| `--desktop` | With `--claude`, Claude Desktop config only |
|
|
102
|
+
|
|
103
|
+
Uses an **absolute path** to the MCP server binary. Sets `AGENTICROS_ROBOT_NAMESPACE` empty so `agenticros mode real|sim` drives the active robot namespace.
|
|
104
|
+
|
|
105
|
+
Also offered as an optional step during `agenticros init`.
|
|
106
|
+
|
|
107
|
+
See **[docs/mcp-setup.md](mcp-setup.md)** for the unified onboarding guide.
|
|
108
|
+
|
|
109
|
+
### `agenticros mcp doctor [--json] [--codex] [--hermes] [--claude]`
|
|
110
|
+
|
|
111
|
+
Validate MCP configuration for Codex, Hermes, and Claude. Exits non-zero on red checks.
|
|
91
112
|
|
|
92
113
|
### `agenticros codex setup [--project]`
|
|
93
114
|
|
|
@@ -122,6 +143,22 @@ Validate Hermes MCP configuration: `~/.hermes/config.yaml`, MCP binary path, and
|
|
|
122
143
|
|
|
123
144
|
See **[docs/hermes-setup.md](hermes-setup.md)** for the full Hermes onboarding guide.
|
|
124
145
|
|
|
146
|
+
### `agenticros claude setup [--desktop] [--project]`
|
|
147
|
+
|
|
148
|
+
Register the AgenticROS MCP server for **Claude Code** and **Claude Desktop**:
|
|
149
|
+
|
|
150
|
+
| Flag | Effect |
|
|
151
|
+
|---|---|
|
|
152
|
+
| (default) | Claude Desktop config + project `.mcp.json` (when in a repo) |
|
|
153
|
+
| `--desktop` | `claude_desktop_config.json` only |
|
|
154
|
+
| `--project` | `.mcp.json` in repo root only |
|
|
155
|
+
|
|
156
|
+
Alias for `agenticros mcp setup --claude`. Restart Claude Desktop fully after desktop config changes.
|
|
157
|
+
|
|
158
|
+
### `agenticros claude doctor [--json]`
|
|
159
|
+
|
|
160
|
+
Validate Claude MCP configuration (desktop + project `.mcp.json`). Exits non-zero on red checks.
|
|
161
|
+
|
|
125
162
|
### `agenticros status [--json]`
|
|
126
163
|
|
|
127
164
|
Shows running components (camera / sim / mcp / rosbridge / openclaw-gateway)
|
|
@@ -150,9 +187,11 @@ Read or edit `~/.agenticros/config.json`. Actions:
|
|
|
150
187
|
|---|---|---|
|
|
151
188
|
| `~/.agenticros/config.json` | User | AgenticROS runtime config (transport mode, namespace, safety limits). |
|
|
152
189
|
| `~/.agenticros/cli-state.json` | CLI | Last-used mode/namespace for the menu's "(yesterday)" hint. |
|
|
153
|
-
| `~/.hermes/config.yaml` | Hermes Agent | MCP server registrations (written by `agenticros hermes setup`). |
|
|
154
|
-
| `~/.codex/config.toml` | Codex CLI | MCP server registrations (written by `agenticros codex setup`). |
|
|
155
|
-
| `.codex/config.toml` | Codex CLI | Project-scoped MCP config (written by `agenticros codex setup --project`). |
|
|
190
|
+
| `~/.hermes/config.yaml` | Hermes Agent | MCP server registrations (written by `agenticros mcp setup` or `agenticros hermes setup`). |
|
|
191
|
+
| `~/.codex/config.toml` | Codex CLI | MCP server registrations (written by `agenticros mcp setup` or `agenticros codex setup`). |
|
|
192
|
+
| `.codex/config.toml` | Codex CLI | Project-scoped MCP config (written by `agenticros mcp setup` or `agenticros codex setup --project`). |
|
|
193
|
+
| `.mcp.json` | Claude Code | Project-scoped MCP config (written by `agenticros mcp setup` or `agenticros claude setup`). |
|
|
194
|
+
| `~/Library/Application Support/Claude/claude_desktop_config.json` | Claude Desktop | MCP server registrations (written by `agenticros mcp setup` or `agenticros claude setup --desktop`). |
|
|
156
195
|
| `~/agenticros/` | CLI (npm-install mode) | Copy of the monorepo, with built dist + colcon install. |
|
|
157
196
|
| `/tmp/agenticros-*.pid` | CLI | PIDs of background processes the CLI spawned. |
|
|
158
197
|
| `/tmp/agenticros-*.log` | CLI | Stdout/stderr from those processes. |
|
|
@@ -182,11 +221,12 @@ Read or edit `~/.agenticros/config.json`. Actions:
|
|
|
182
221
|
## Troubleshooting
|
|
183
222
|
|
|
184
223
|
- **`doctor` shows red checks** → run `agenticros init` to walk through every
|
|
185
|
-
step. Re-run `doctor` afterward. For
|
|
186
|
-
`agenticros
|
|
187
|
-
- **
|
|
224
|
+
step. Re-run `doctor` afterward. For MCP-specific issues, run
|
|
225
|
+
`agenticros mcp doctor` (or `agenticros codex doctor`, `agenticros hermes doctor`, `agenticros claude doctor`).
|
|
226
|
+
- **MCP tools missing in any client** → run `agenticros mcp setup`. See [mcp-setup.md](mcp-setup.md).
|
|
227
|
+
- **Codex `/mcp` does not list agenticros** → run `agenticros mcp setup --codex`
|
|
188
228
|
(absolute MCP path required). See [codex-setup.md](codex-setup.md).
|
|
189
|
-
- **Hermes MCP tools missing** → run `agenticros
|
|
229
|
+
- **Hermes MCP tools missing** → run `agenticros mcp setup --hermes`, then `/reload-mcp`
|
|
190
230
|
in Hermes. See [hermes-setup.md](hermes-setup.md).
|
|
191
231
|
- **`up` exits immediately** → `agenticros logs <component>` (the CLI now
|
|
192
232
|
records where every child wrote its output) and read the error in context.
|
|
@@ -296,7 +296,7 @@ The message comes from **OpenAI's API limits**, not from AgenticROS. The gateway
|
|
|
296
296
|
1. **Confirm it's OpenAI** — Check gateway logs:
|
|
297
297
|
`journalctl --user -u openclaw-gateway.service -n 100 --no-pager | grep -i "429\|rate\|limit\|error"`
|
|
298
298
|
2. **Check your OpenAI account** — [Usage](https://platform.openai.com/usage), [API keys](https://platform.openai.com/api-keys). Free/low tiers have strict RPM/TPM and can stay limited for a while.
|
|
299
|
-
3. **What helps** — Wait (RPM/TPM reset in minutes; daily limits at UTC midnight). Or in OpenClaw switch to a model with higher limits if available.
|
|
299
|
+
3. **What helps** — Wait (RPM/TPM reset in minutes; daily limits at UTC midnight). Or switch OpenClaw to a **local Ollama VLM** — see [local-vlm.md](local-vlm.md). Or in OpenClaw switch to a model with higher limits if available.
|
|
300
300
|
4. **AgenticROS** — We only trim context/tool output to use fewer tokens; we can't remove OpenAI's limits.
|
|
301
301
|
|
|
302
302
|
### 404 errors when installing rosbridge_suite
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"ros2_find_robots_for",
|
|
22
22
|
"run_mission",
|
|
23
23
|
"mission_cancel",
|
|
24
|
+
"mission_pause",
|
|
25
|
+
"mission_resume",
|
|
24
26
|
"ros2_camera_snapshot",
|
|
25
27
|
"ros2_depth_distance",
|
|
26
28
|
"memory_remember",
|
|
@@ -30,7 +32,8 @@
|
|
|
30
32
|
"follow_robot",
|
|
31
33
|
"follow_me_see",
|
|
32
34
|
"ollama_status",
|
|
33
|
-
"find_object"
|
|
35
|
+
"find_object",
|
|
36
|
+
"scan_surroundings"
|
|
34
37
|
]
|
|
35
38
|
},
|
|
36
39
|
"configSchema": {
|
|
@@ -178,6 +181,149 @@
|
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
},
|
|
184
|
+
"robots": {
|
|
185
|
+
"type": "array",
|
|
186
|
+
"description": "Multi-robot fleet list. When non-empty, used by ros2_list_robots and per-tool robot_id. When empty, the legacy config.robot entry is used. Manage via `agenticros robots` CLI.",
|
|
187
|
+
"default": [],
|
|
188
|
+
"items": {
|
|
189
|
+
"type": "object",
|
|
190
|
+
"required": [
|
|
191
|
+
"id"
|
|
192
|
+
],
|
|
193
|
+
"properties": {
|
|
194
|
+
"id": {
|
|
195
|
+
"type": "string",
|
|
196
|
+
"description": "Stable identifier referenced by robot_id tool arguments"
|
|
197
|
+
},
|
|
198
|
+
"name": {
|
|
199
|
+
"type": "string",
|
|
200
|
+
"default": "Robot"
|
|
201
|
+
},
|
|
202
|
+
"namespace": {
|
|
203
|
+
"type": "string",
|
|
204
|
+
"default": ""
|
|
205
|
+
},
|
|
206
|
+
"cameraTopic": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"default": ""
|
|
209
|
+
},
|
|
210
|
+
"default": {
|
|
211
|
+
"type": "boolean",
|
|
212
|
+
"description": "When true, this robot is active even if not first in the list"
|
|
213
|
+
},
|
|
214
|
+
"kind": {
|
|
215
|
+
"type": "string",
|
|
216
|
+
"description": "Robot kind for ros2_find_robots_for (e.g. amr, arm, drone, rover)",
|
|
217
|
+
"default": "amr"
|
|
218
|
+
},
|
|
219
|
+
"sensors": {
|
|
220
|
+
"type": "object",
|
|
221
|
+
"properties": {
|
|
222
|
+
"has_realsense": {
|
|
223
|
+
"type": "boolean",
|
|
224
|
+
"default": false
|
|
225
|
+
},
|
|
226
|
+
"has_lidar": {
|
|
227
|
+
"type": "boolean",
|
|
228
|
+
"default": false
|
|
229
|
+
},
|
|
230
|
+
"has_arm": {
|
|
231
|
+
"type": "boolean",
|
|
232
|
+
"default": false
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"capabilities": {
|
|
237
|
+
"type": "array",
|
|
238
|
+
"description": "Optional per-robot capability allowlist for ros2_find_robots_for",
|
|
239
|
+
"items": {
|
|
240
|
+
"type": "string"
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"transport": {
|
|
244
|
+
"type": "object",
|
|
245
|
+
"description": "Per-robot transport override (inherits global transport when omitted)",
|
|
246
|
+
"properties": {
|
|
247
|
+
"mode": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"enum": [
|
|
250
|
+
"rosbridge",
|
|
251
|
+
"local",
|
|
252
|
+
"webrtc",
|
|
253
|
+
"zenoh"
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
"zenoh": {
|
|
257
|
+
"type": "object",
|
|
258
|
+
"properties": {
|
|
259
|
+
"routerEndpoint": {
|
|
260
|
+
"type": "string"
|
|
261
|
+
},
|
|
262
|
+
"domainId": {
|
|
263
|
+
"type": "number"
|
|
264
|
+
},
|
|
265
|
+
"keyFormat": {
|
|
266
|
+
"type": "string",
|
|
267
|
+
"enum": [
|
|
268
|
+
"ros2dds",
|
|
269
|
+
"rmw_zenoh"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
"bridgeNamespace": {
|
|
273
|
+
"type": "string"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"rosbridge": {
|
|
278
|
+
"type": "object",
|
|
279
|
+
"properties": {
|
|
280
|
+
"url": {
|
|
281
|
+
"type": "string"
|
|
282
|
+
},
|
|
283
|
+
"reconnect": {
|
|
284
|
+
"type": "boolean"
|
|
285
|
+
},
|
|
286
|
+
"reconnectInterval": {
|
|
287
|
+
"type": "number"
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"local": {
|
|
292
|
+
"type": "object",
|
|
293
|
+
"properties": {
|
|
294
|
+
"domainId": {
|
|
295
|
+
"type": "number"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
"webrtc": {
|
|
300
|
+
"type": "object",
|
|
301
|
+
"properties": {
|
|
302
|
+
"signalingUrl": {
|
|
303
|
+
"type": "string"
|
|
304
|
+
},
|
|
305
|
+
"apiUrl": {
|
|
306
|
+
"type": "string"
|
|
307
|
+
},
|
|
308
|
+
"robotId": {
|
|
309
|
+
"type": "string"
|
|
310
|
+
},
|
|
311
|
+
"robotKey": {
|
|
312
|
+
"type": "string"
|
|
313
|
+
},
|
|
314
|
+
"iceServers": {
|
|
315
|
+
"type": "array",
|
|
316
|
+
"items": {
|
|
317
|
+
"type": "object"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
},
|
|
181
327
|
"teleop": {
|
|
182
328
|
"type": "object",
|
|
183
329
|
"description": "Teleop web app: camera and twist controls",
|
|
@@ -131,6 +131,8 @@ test("plugin: register() is synchronous and produces the base 15-tool surface",
|
|
|
131
131
|
"run_mission",
|
|
132
132
|
// Phase 1.f — cancel an in-flight mission by id.
|
|
133
133
|
"mission_cancel",
|
|
134
|
+
"mission_pause",
|
|
135
|
+
"mission_resume",
|
|
134
136
|
];
|
|
135
137
|
for (const name of expected) {
|
|
136
138
|
assert.ok(toolNames.includes(name), `Expected base tool ${name} in registered set`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenClawPluginApi, HttpRouteHandler, HttpRouteResponse } from "./plugin-api.js";
|
|
2
2
|
import type { AgenticROSConfig } from "@agenticros/core";
|
|
3
|
-
import { parseConfig } from "@agenticros/core";
|
|
3
|
+
import { parseConfig, prepareConfigForPersistence } from "@agenticros/core";
|
|
4
4
|
import {
|
|
5
5
|
readOpenClawConfig,
|
|
6
6
|
writeAgenticROSConfig,
|
|
@@ -172,8 +172,9 @@ export function registerRoutes(api: OpenClawPluginApi, config: AgenticROSConfig)
|
|
|
172
172
|
api.logger.warn("AgenticROS config read failed: " + readMsg);
|
|
173
173
|
return { success: false, error: readMsg, statusCode: 500 };
|
|
174
174
|
}
|
|
175
|
+
let combined: Record<string, unknown>;
|
|
175
176
|
try {
|
|
176
|
-
|
|
177
|
+
combined =
|
|
177
178
|
existingAgenticROS && typeof existingAgenticROS === "object"
|
|
178
179
|
? mergeIncomingAgenticROSConfig(existingAgenticROS, body)
|
|
179
180
|
: body;
|
|
@@ -192,7 +193,7 @@ export function registerRoutes(api: OpenClawPluginApi, config: AgenticROSConfig)
|
|
|
192
193
|
merged.webrtc.robotKey = existingKey;
|
|
193
194
|
}
|
|
194
195
|
try {
|
|
195
|
-
writeAgenticROSConfig(merged
|
|
196
|
+
writeAgenticROSConfig(prepareConfigForPersistence(merged, combined));
|
|
196
197
|
} catch (err) {
|
|
197
198
|
const msg = err instanceof ConfigFileError ? err.message : (err instanceof Error ? err.message : "Failed to write config");
|
|
198
199
|
api.logger.warn("AgenticROS config write failed: " + msg);
|
|
@@ -14,6 +14,8 @@ import { registerDiscoverRobotsTool } from "./ros2-discover.js";
|
|
|
14
14
|
import { registerFindRobotsForTool } from "./ros2-find-robots-for.js";
|
|
15
15
|
import { registerMissionTool, type ToolRegistry } from "./ros2-mission.js";
|
|
16
16
|
import { registerMissionCancelTool } from "./mission-cancel.js";
|
|
17
|
+
import { registerMissionPauseTool } from "./mission-pause.js";
|
|
18
|
+
import { registerMissionResumeTool } from "./mission-resume.js";
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Wrap the OpenClaw API so every registerTool() call is also recorded in
|
|
@@ -21,11 +23,8 @@ import { registerMissionCancelTool } from "./mission-cancel.js";
|
|
|
21
23
|
* dispatch sub-tool calls by name (e.g. capability "drive_base" routes
|
|
22
24
|
* to the registered "ros2_publish" tool's execute()).
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
* `
|
|
26
|
-
* v1: today the mission runner only supports the eight intrinsic
|
|
27
|
-
* capability bindings declared in ros2-mission.ts. Phase 1.d will
|
|
28
|
-
* extend this to capture skill-declared tools as well.
|
|
26
|
+
* Skill tools registered via `api.registerTool` are captured too, so
|
|
27
|
+
* `buildMissionBindings` can resolve `ros2_<capability_id>` when present.
|
|
29
28
|
*/
|
|
30
29
|
function wrapApiWithToolCapture(api: OpenClawPluginApi): {
|
|
31
30
|
wrappedApi: OpenClawPluginApi;
|
|
@@ -63,4 +62,6 @@ export function registerTools(api: OpenClawPluginApi, config: AgenticROSConfig):
|
|
|
63
62
|
registerFindRobotsForTool(wrappedApi, config);
|
|
64
63
|
registerMissionTool(wrappedApi, config, registry);
|
|
65
64
|
registerMissionCancelTool(wrappedApi);
|
|
65
|
+
registerMissionPauseTool(wrappedApi);
|
|
66
|
+
registerMissionResumeTool(wrappedApi);
|
|
66
67
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: mission_pause — pause a running mission at the next step boundary.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
7
|
+
import { getMissionRegistry } from "../mission-registry.js";
|
|
8
|
+
|
|
9
|
+
export function registerMissionPauseTool(api: OpenClawPluginApi): void {
|
|
10
|
+
api.registerTool({
|
|
11
|
+
name: "mission_pause",
|
|
12
|
+
label: "Pause Mission",
|
|
13
|
+
description:
|
|
14
|
+
"Pause a mission that's currently running in this OpenClaw plugin process. " +
|
|
15
|
+
"Pass the mission_id returned by run_mission. The runner waits at the next step " +
|
|
16
|
+
"boundary until mission_resume (or mission_cancel). Idempotent if already paused.",
|
|
17
|
+
parameters: Type.Object({
|
|
18
|
+
mission_id: Type.String({
|
|
19
|
+
description: "The mission_id echoed by run_mission. Required.",
|
|
20
|
+
}),
|
|
21
|
+
reason: Type.Optional(
|
|
22
|
+
Type.String({
|
|
23
|
+
description: "Optional free-text reason — surfaced in the paused transcript entry.",
|
|
24
|
+
}),
|
|
25
|
+
),
|
|
26
|
+
}),
|
|
27
|
+
|
|
28
|
+
async execute(_toolCallId, params) {
|
|
29
|
+
const missionId = typeof params["mission_id"] === "string" ? (params["mission_id"] as string).trim() : "";
|
|
30
|
+
if (!missionId) {
|
|
31
|
+
const text = "mission_pause requires 'mission_id' (a non-empty string returned by run_mission).";
|
|
32
|
+
return { content: [{ type: "text", text }], details: { success: false, error: text } };
|
|
33
|
+
}
|
|
34
|
+
const reason = typeof params["reason"] === "string" ? (params["reason"] as string) : undefined;
|
|
35
|
+
const outcome = getMissionRegistry().pause(missionId, reason);
|
|
36
|
+
const details = {
|
|
37
|
+
success: true,
|
|
38
|
+
mission_id: missionId,
|
|
39
|
+
found: outcome.found,
|
|
40
|
+
already_paused: outcome.alreadyPaused,
|
|
41
|
+
reason: reason ?? null,
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: JSON.stringify(details) }],
|
|
45
|
+
details,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: mission_resume — resume a paused mission.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
7
|
+
import { getMissionRegistry } from "../mission-registry.js";
|
|
8
|
+
|
|
9
|
+
export function registerMissionResumeTool(api: OpenClawPluginApi): void {
|
|
10
|
+
api.registerTool({
|
|
11
|
+
name: "mission_resume",
|
|
12
|
+
label: "Resume Mission",
|
|
13
|
+
description:
|
|
14
|
+
"Resume a mission previously paused with mission_pause. Pass the mission_id " +
|
|
15
|
+
"returned by run_mission. Idempotent if the mission is not paused.",
|
|
16
|
+
parameters: Type.Object({
|
|
17
|
+
mission_id: Type.String({
|
|
18
|
+
description: "The mission_id echoed by run_mission. Required.",
|
|
19
|
+
}),
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
async execute(_toolCallId, params) {
|
|
23
|
+
const missionId = typeof params["mission_id"] === "string" ? (params["mission_id"] as string).trim() : "";
|
|
24
|
+
if (!missionId) {
|
|
25
|
+
const text = "mission_resume requires 'mission_id' (a non-empty string returned by run_mission).";
|
|
26
|
+
return { content: [{ type: "text", text }], details: { success: false, error: text } };
|
|
27
|
+
}
|
|
28
|
+
const outcome = getMissionRegistry().resume(missionId);
|
|
29
|
+
const details = {
|
|
30
|
+
success: true,
|
|
31
|
+
mission_id: missionId,
|
|
32
|
+
found: outcome.found,
|
|
33
|
+
was_paused: outcome.wasPaused,
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: JSON.stringify(details) }],
|
|
37
|
+
details,
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|