agenticros 0.1.18 → 0.2.0
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/dist/__tests__/robot-config.test.d.ts +2 -0
- package/dist/__tests__/robot-config.test.d.ts.map +1 -0
- package/dist/__tests__/robot-config.test.js +374 -0
- package/dist/__tests__/robot-config.test.js.map +1 -0
- package/dist/__tests__/transport-shorthand.test.d.ts +2 -0
- package/dist/__tests__/transport-shorthand.test.d.ts.map +1 -0
- package/dist/__tests__/transport-shorthand.test.js +88 -0
- package/dist/__tests__/transport-shorthand.test.js.map +1 -0
- package/dist/commands/robots.d.ts +57 -0
- package/dist/commands/robots.d.ts.map +1 -0
- package/dist/commands/robots.js +678 -0
- package/dist/commands/robots.js.map +1 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +125 -2
- package/dist/commands/skills.js.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/menu.js +22 -4
- package/dist/menu.js.map +1 -1
- package/dist/util/marketplace.d.ts +57 -0
- package/dist/util/marketplace.d.ts.map +1 -0
- package/dist/util/marketplace.js +144 -0
- package/dist/util/marketplace.js.map +1 -0
- package/dist/util/mcp-discovery.d.ts +57 -0
- package/dist/util/mcp-discovery.d.ts.map +1 -0
- package/dist/util/mcp-discovery.js +153 -0
- package/dist/util/mcp-discovery.js.map +1 -0
- package/dist/util/robot-config.d.ts +167 -0
- package/dist/util/robot-config.d.ts.map +1 -0
- package/dist/util/robot-config.js +375 -0
- package/dist/util/robot-config.js.map +1 -0
- package/dist/util/skills.d.ts +6 -6
- package/dist/util/skills.d.ts.map +1 -1
- package/dist/util/skills.js +14 -9
- package/dist/util/skills.js.map +1 -1
- package/dist/util/transport-shorthand.d.ts +66 -0
- package/dist/util/transport-shorthand.d.ts.map +1 -0
- package/dist/util/transport-shorthand.js +102 -0
- package/dist/util/transport-shorthand.js.map +1 -0
- package/package.json +12 -10
- package/runtime/BUNDLE.json +1 -1
- package/runtime/README.md +62 -1
- package/runtime/package.json +6 -1
- package/runtime/packages/agenticros/openclaw.plugin.json +7 -1
- package/runtime/packages/agenticros/package.json +2 -1
- package/runtime/packages/agenticros/src/__tests__/capabilities-plugin.test.ts +568 -0
- package/runtime/packages/agenticros/src/config-page.ts +1 -1
- package/runtime/packages/agenticros/src/mission-registry.ts +22 -0
- package/runtime/packages/agenticros/src/service.ts +120 -2
- package/runtime/packages/agenticros/src/skill-loader.ts +109 -30
- package/runtime/packages/agenticros/src/tools/_robot-helpers.ts +68 -0
- package/runtime/packages/agenticros/src/tools/index.ts +49 -9
- package/runtime/packages/agenticros/src/tools/mission-cancel.ts +70 -0
- package/runtime/packages/agenticros/src/tools/ros2-action.ts +11 -4
- package/runtime/packages/agenticros/src/tools/ros2-camera.ts +10 -4
- package/runtime/packages/agenticros/src/tools/ros2-capabilities.ts +63 -0
- package/runtime/packages/agenticros/src/tools/ros2-depth-distance.ts +11 -4
- package/runtime/packages/agenticros/src/tools/ros2-discover.ts +65 -0
- package/runtime/packages/agenticros/src/tools/ros2-find-robots-for.ts +128 -0
- package/runtime/packages/agenticros/src/tools/ros2-mission.ts +311 -0
- package/runtime/packages/agenticros/src/tools/ros2-param.ts +20 -7
- package/runtime/packages/agenticros/src/tools/ros2-publish.ts +15 -8
- package/runtime/packages/agenticros/src/tools/ros2-robots.ts +52 -0
- package/runtime/packages/agenticros/src/tools/ros2-service.ts +11 -4
- package/runtime/packages/agenticros/src/tools/ros2-subscribe.ts +11 -4
- package/runtime/packages/agenticros-claude-code/README.md +52 -9
- package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.d.ts +2 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.d.ts.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.js +773 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.js.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.d.ts +2 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.d.ts.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.js +97 -0
- package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.js.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts +2 -2
- package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js +5 -5
- package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.d.ts +109 -0
- package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.d.ts.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.js +392 -0
- package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.js.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts +8 -3
- package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js +30 -12
- package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/index.js +5 -5
- package/runtime/packages/agenticros-claude-code/dist/index.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/mission-registry.d.ts +16 -0
- package/runtime/packages/agenticros-claude-code/dist/mission-registry.d.ts.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/mission-registry.js +19 -0
- package/runtime/packages/agenticros-claude-code/dist/mission-registry.js.map +1 -0
- package/runtime/packages/agenticros-claude-code/dist/tools.d.ts +9 -0
- package/runtime/packages/agenticros-claude-code/dist/tools.d.ts.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/tools.js +700 -54
- package/runtime/packages/agenticros-claude-code/dist/tools.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/transport.d.ts +28 -8
- package/runtime/packages/agenticros-claude-code/dist/transport.d.ts.map +1 -1
- package/runtime/packages/agenticros-claude-code/dist/transport.js +37 -34
- package/runtime/packages/agenticros-claude-code/dist/transport.js.map +1 -1
- package/runtime/packages/agenticros-claude-code/package.json +2 -1
- package/runtime/packages/agenticros-claude-code/src/__tests__/capabilities-mcp.test.ts +965 -0
- package/runtime/packages/agenticros-claude-code/src/__tests__/follow-me-registry.test.ts +119 -0
- package/runtime/packages/agenticros-claude-code/src/find-object/find-object.ts +7 -6
- package/runtime/packages/agenticros-claude-code/src/follow-me/depth-loop.ts +41 -9
- package/runtime/packages/agenticros-claude-code/src/follow-me/loop.ts +40 -11
- package/runtime/packages/agenticros-claude-code/src/index.ts +5 -5
- package/runtime/packages/agenticros-claude-code/src/mission-registry.ts +21 -0
- package/runtime/packages/agenticros-claude-code/src/tools.ts +668 -56
- package/runtime/packages/agenticros-claude-code/src/transport.ts +43 -43
- package/runtime/packages/agenticros-gemini/package.json +1 -0
- package/runtime/packages/agenticros-gemini/src/__tests__/mission-cancel.test.ts +197 -0
- package/runtime/packages/agenticros-gemini/src/__tests__/mission-transcripts.test.ts +178 -0
- package/runtime/packages/agenticros-gemini/src/tools.ts +504 -21
- package/runtime/packages/agenticros-gemini/src/transport.ts +40 -43
- package/runtime/packages/core/LICENSE +192 -0
- package/runtime/packages/core/README.md +88 -0
- package/runtime/packages/core/package.json +36 -3
- package/runtime/packages/core/src/__tests__/capabilities.test.ts +266 -0
- package/runtime/packages/core/src/__tests__/discovery.test.ts +206 -0
- package/runtime/packages/core/src/__tests__/find-robots-for.test.ts +258 -0
- package/runtime/packages/core/src/__tests__/mission-cancel-transcript.test.ts +371 -0
- package/runtime/packages/core/src/__tests__/mission-transcript-sink.test.ts +189 -0
- package/runtime/packages/core/src/__tests__/mission.test.ts +501 -0
- package/runtime/packages/core/src/__tests__/planner.test.ts +279 -0
- package/runtime/packages/core/src/__tests__/robots.test.ts +406 -0
- package/runtime/packages/core/src/__tests__/topic-utils.test.ts +105 -0
- package/runtime/packages/core/src/__tests__/transport-pool.test.ts +295 -0
- package/runtime/packages/core/src/capabilities.ts +314 -0
- package/runtime/packages/core/src/config.ts +221 -39
- package/runtime/packages/core/src/discovery.ts +193 -0
- package/runtime/packages/core/src/find-robots-for.ts +164 -0
- package/runtime/packages/core/src/index.ts +67 -1
- package/runtime/packages/core/src/mission-registry.ts +142 -0
- package/runtime/packages/core/src/mission-transcript-sink.ts +81 -0
- package/runtime/packages/core/src/mission.ts +574 -0
- package/runtime/packages/core/src/planner/index.ts +564 -0
- package/runtime/packages/core/src/robots.ts +282 -0
- package/runtime/packages/core/src/topic-utils.ts +47 -9
- package/runtime/packages/core/src/transport-pool.ts +171 -0
- package/runtime/ros2_ws/src/agenticros_discovery/agenticros_discovery/discovery_node.py +108 -13
- package/runtime/ros2_ws/src/agenticros_msgs/CMakeLists.txt +1 -0
- package/runtime/ros2_ws/src/agenticros_msgs/msg/RobotInfo.msg +44 -0
- package/runtime/scripts/__tests__/refresh-skill-deps.test.mjs +222 -0
- package/runtime/scripts/configure_agenticros.sh +0 -0
- package/runtime/scripts/configure_for_sim.sh +0 -0
- package/runtime/scripts/fix-openclaw-control-ui-path.sh +0 -0
- package/runtime/scripts/install_cli.sh +0 -0
- package/runtime/scripts/install_rosbridge_from_source.sh +0 -0
- package/runtime/scripts/onboard_robot.sh +0 -0
- package/runtime/scripts/pack-runtime.mjs +0 -0
- package/runtime/scripts/refresh-skill-deps.mjs +381 -0
- package/runtime/scripts/run_demo_native.sh +0 -0
- package/runtime/scripts/run_nemoclaw_host_stack.sh +0 -0
- package/runtime/scripts/run_robot_rosbridge.sh +0 -0
- package/runtime/scripts/setup_gateway_plugin.sh +32 -5
- package/runtime/scripts/setup_robot.sh +0 -0
- package/runtime/scripts/setup_workspace.sh +0 -0
- package/runtime/scripts/sim/run_sim.sh +0 -0
- package/runtime/scripts/smoke_test_nemoclaw.sh +0 -0
- package/runtime/scripts/start_demo.sh +0 -0
- package/runtime/scripts/sync-skill-tools.mjs +69 -12
- package/runtime/scripts/use-openclaw-2026.2.26.sh +0 -0
- package/runtime/scripts/use-openclaw-2026.3.11.sh +0 -0
|
@@ -2,7 +2,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
3
3
|
import type { AgenticROSConfig } from "@agenticros/core";
|
|
4
4
|
import { toNamespacedTopic } from "@agenticros/core";
|
|
5
|
-
import {
|
|
5
|
+
import { getTransportForRobot } from "../service.js";
|
|
6
|
+
import { ROBOT_ID_SCHEMA, resolveRobotForTool } from "./_robot-helpers.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Register ros2_param_get and ros2_param_set tools with the AI agent.
|
|
@@ -13,18 +14,24 @@ export function registerParamTools(api: OpenClawPluginApi, config: AgenticROSCon
|
|
|
13
14
|
label: "ROS2 Get Parameter",
|
|
14
15
|
description:
|
|
15
16
|
"Get the value of a ROS2 parameter from a node. " +
|
|
16
|
-
"Use this to check robot configuration values."
|
|
17
|
+
"Use this to check robot configuration values. " +
|
|
18
|
+
"Pass robot_id (from ros2_list_robots) to target a specific robot.",
|
|
17
19
|
parameters: Type.Object({
|
|
18
20
|
node: Type.String({ description: "The fully qualified node name (e.g., '/turtlebot3/controller')" }),
|
|
19
21
|
parameter: Type.String({ description: "The parameter name (e.g., 'max_velocity')" }),
|
|
22
|
+
...ROBOT_ID_SCHEMA,
|
|
20
23
|
}),
|
|
21
24
|
|
|
22
25
|
async execute(_toolCallId, params) {
|
|
26
|
+
const resolved = resolveRobotForTool(config, params);
|
|
27
|
+
if ("error" in resolved) return resolved.error;
|
|
28
|
+
const { robot } = resolved;
|
|
29
|
+
|
|
23
30
|
const rawNode = params["node"] as string;
|
|
24
|
-
const node = toNamespacedTopic(
|
|
31
|
+
const node = toNamespacedTopic(robot.namespace, rawNode);
|
|
25
32
|
const parameter = params["parameter"] as string;
|
|
26
33
|
|
|
27
|
-
const transport =
|
|
34
|
+
const transport = await getTransportForRobot(config, robot);
|
|
28
35
|
const response = await transport.callService({
|
|
29
36
|
service: `${node}/get_parameters`,
|
|
30
37
|
type: "rcl_interfaces/srv/GetParameters",
|
|
@@ -49,20 +56,26 @@ export function registerParamTools(api: OpenClawPluginApi, config: AgenticROSCon
|
|
|
49
56
|
label: "ROS2 Set Parameter",
|
|
50
57
|
description:
|
|
51
58
|
"Set the value of a ROS2 parameter on a node. " +
|
|
52
|
-
"Use this to change robot configuration at runtime."
|
|
59
|
+
"Use this to change robot configuration at runtime. " +
|
|
60
|
+
"Pass robot_id (from ros2_list_robots) to target a specific robot.",
|
|
53
61
|
parameters: Type.Object({
|
|
54
62
|
node: Type.String({ description: "The fully qualified node name" }),
|
|
55
63
|
parameter: Type.String({ description: "The parameter name" }),
|
|
56
64
|
value: Type.Unknown({ description: "The new parameter value" }),
|
|
65
|
+
...ROBOT_ID_SCHEMA,
|
|
57
66
|
}),
|
|
58
67
|
|
|
59
68
|
async execute(_toolCallId, params) {
|
|
69
|
+
const resolved = resolveRobotForTool(config, params);
|
|
70
|
+
if ("error" in resolved) return resolved.error;
|
|
71
|
+
const { robot } = resolved;
|
|
72
|
+
|
|
60
73
|
const rawNode = params["node"] as string;
|
|
61
|
-
const node = toNamespacedTopic(
|
|
74
|
+
const node = toNamespacedTopic(robot.namespace, rawNode);
|
|
62
75
|
const parameter = params["parameter"] as string;
|
|
63
76
|
const value = params["value"];
|
|
64
77
|
|
|
65
|
-
const transport =
|
|
78
|
+
const transport = await getTransportForRobot(config, robot);
|
|
66
79
|
const response = await transport.callService({
|
|
67
80
|
service: `${node}/set_parameters`,
|
|
68
81
|
type: "rcl_interfaces/srv/SetParameters",
|
|
@@ -2,7 +2,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
3
3
|
import type { AgenticROSConfig } from "@agenticros/core";
|
|
4
4
|
import { toNamespacedTopic, applyCmdVelTwistSignConvention } from "@agenticros/core";
|
|
5
|
-
import {
|
|
5
|
+
import { getTransportForRobot } from "../service.js";
|
|
6
|
+
import { ROBOT_ID_SCHEMA, resolveRobotForTool } from "./_robot-helpers.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Register the ros2_publish tool with the AI agent.
|
|
@@ -14,37 +15,43 @@ export function registerPublishTool(api: OpenClawPluginApi, config: AgenticROSCo
|
|
|
14
15
|
label: "ROS2 Publish",
|
|
15
16
|
description:
|
|
16
17
|
"Publish a message to a ROS2 topic. Use this to send commands to the robot " +
|
|
17
|
-
"(e.g., velocity commands to /cmd_vel, navigation goals, etc.)."
|
|
18
|
+
"(e.g., velocity commands to /cmd_vel, navigation goals, etc.). " +
|
|
19
|
+
"Pass robot_id (from ros2_list_robots) to target a specific robot; omitted = active robot.",
|
|
18
20
|
parameters: Type.Object({
|
|
19
21
|
topic: Type.String({ description: "The ROS2 topic name (e.g., '/cmd_vel')" }),
|
|
20
22
|
type: Type.String({ description: "The ROS2 message type (e.g., 'geometry_msgs/msg/Twist')" }),
|
|
21
23
|
message: Type.Record(Type.String(), Type.Unknown(), {
|
|
22
24
|
description: "The message payload matching the ROS2 message type schema",
|
|
23
25
|
}),
|
|
26
|
+
...ROBOT_ID_SCHEMA,
|
|
24
27
|
}),
|
|
25
28
|
|
|
26
29
|
async execute(_toolCallId, params) {
|
|
30
|
+
const resolved = resolveRobotForTool(config, params);
|
|
31
|
+
if ("error" in resolved) return resolved.error;
|
|
32
|
+
const { robot } = resolved;
|
|
33
|
+
|
|
27
34
|
const rawTopic = params["topic"] as string;
|
|
28
|
-
const topic = toNamespacedTopic(
|
|
35
|
+
const topic = toNamespacedTopic(robot.namespace, rawTopic);
|
|
29
36
|
const type = params["type"] as string;
|
|
30
37
|
let message = params["message"] as Record<string, unknown>;
|
|
31
38
|
message = applyCmdVelTwistSignConvention(topic, type, message);
|
|
32
39
|
|
|
33
|
-
const transport =
|
|
40
|
+
const transport = await getTransportForRobot(config, robot);
|
|
34
41
|
transport.publish({ topic, type, msg: message });
|
|
35
42
|
|
|
36
|
-
const ns = (
|
|
43
|
+
const ns = (robot.namespace ?? "").trim();
|
|
37
44
|
const namespaceApplied = ns && topic.startsWith(`/${ns}/`);
|
|
38
45
|
let summary = namespaceApplied
|
|
39
|
-
? `Published to ${topic} (robot.namespace="${ns}" applied).`
|
|
46
|
+
? `Published to ${topic} (robot="${robot.id}", namespace="${ns}" applied).`
|
|
40
47
|
: `Published to ${topic}.`;
|
|
41
48
|
if (!ns && (rawTopic === "/cmd_vel" || rawTopic.trim().replace(/^\/+/, "") === "cmd_vel")) {
|
|
42
49
|
summary += " If the robot did not move, set robot.namespace in plugin config to the robot's cmd_vel prefix (e.g. robot3946b404c33e4aa39a8d16deb1c5c593), then restart the gateway.";
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
const result = { success: true, topic, type, summary };
|
|
52
|
+
const result = { success: true, topic, type, robot_id: robot.id, summary };
|
|
46
53
|
return {
|
|
47
|
-
content: [{ type: "text", text: summary + "\n" + JSON.stringify({ success: true, topic, type }) }],
|
|
54
|
+
content: [{ type: "text", text: summary + "\n" + JSON.stringify({ success: true, topic, type, robot_id: robot.id }) }],
|
|
48
55
|
details: result,
|
|
49
56
|
};
|
|
50
57
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: ros2_list_robots — Phase 1.d of the AgenticROS strategy.
|
|
3
|
+
*
|
|
4
|
+
* Returns the list of robots this gateway knows about (id, name, ROS2
|
|
5
|
+
* namespace, default camera topic) and which one is active. The agent
|
|
6
|
+
* uses this to discover the fleet and (in a follow-up iteration) target
|
|
7
|
+
* specific robots via a `robot_id` parameter on other tools.
|
|
8
|
+
*
|
|
9
|
+
* Read-only and transport-free: this tool reads the multi-robot section
|
|
10
|
+
* of the config (with legacy single-robot fallback) so it works even
|
|
11
|
+
* when the robot is offline. Mirrored across all three adapters
|
|
12
|
+
* (OpenClaw, Claude Code, Gemini) — see
|
|
13
|
+
* docs/strategy-ai-agents-plus-ros.md §4 Phase 1.d.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Type } from "@sinclair/typebox";
|
|
17
|
+
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
18
|
+
import type { AgenticROSConfig } from "@agenticros/core";
|
|
19
|
+
import { getActiveRobotId, listRobots } from "@agenticros/core";
|
|
20
|
+
|
|
21
|
+
export function registerRobotsTool(
|
|
22
|
+
api: OpenClawPluginApi,
|
|
23
|
+
config: AgenticROSConfig,
|
|
24
|
+
): void {
|
|
25
|
+
api.registerTool({
|
|
26
|
+
name: "ros2_list_robots",
|
|
27
|
+
label: "ROS2 List Robots",
|
|
28
|
+
description:
|
|
29
|
+
"List the robots this gateway knows about (id, name, ROS2 namespace, default camera topic) " +
|
|
30
|
+
"and which one is the active default. Use this FIRST when the user mentions multiple robots, " +
|
|
31
|
+
"asks 'which robots can you see?', or names a specific robot you haven't heard of. The " +
|
|
32
|
+
"returned `id` is what later tools (in upcoming iterations) will accept as a `robot_id` " +
|
|
33
|
+
"parameter — today there's a single active robot, but the field will scope per-tool calls " +
|
|
34
|
+
"in fleet deployments.",
|
|
35
|
+
parameters: Type.Object({}),
|
|
36
|
+
|
|
37
|
+
async execute(_toolCallId, _params) {
|
|
38
|
+
const robots = listRobots(config);
|
|
39
|
+
const active = getActiveRobotId(config);
|
|
40
|
+
const result = {
|
|
41
|
+
success: true,
|
|
42
|
+
total: robots.length,
|
|
43
|
+
active_robot_id: active,
|
|
44
|
+
robots,
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
48
|
+
details: result,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -2,7 +2,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
3
3
|
import type { AgenticROSConfig } from "@agenticros/core";
|
|
4
4
|
import { toNamespacedTopic } from "@agenticros/core";
|
|
5
|
-
import {
|
|
5
|
+
import { getTransportForRobot } from "../service.js";
|
|
6
|
+
import { ROBOT_ID_SCHEMA, resolveRobotForTool } from "./_robot-helpers.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Register the ros2_service_call tool with the AI agent.
|
|
@@ -14,22 +15,28 @@ export function registerServiceTool(api: OpenClawPluginApi, config: AgenticROSCo
|
|
|
14
15
|
label: "ROS2 Service Call",
|
|
15
16
|
description:
|
|
16
17
|
"Call a ROS2 service and return the response. Use this for request/response operations " +
|
|
17
|
-
"like setting parameters, triggering behaviors, or querying node state."
|
|
18
|
+
"like setting parameters, triggering behaviors, or querying node state. " +
|
|
19
|
+
"Pass robot_id (from ros2_list_robots) to target a specific robot.",
|
|
18
20
|
parameters: Type.Object({
|
|
19
21
|
service: Type.String({ description: "The ROS2 service name (e.g., '/spawn_entity')" }),
|
|
20
22
|
type: Type.Optional(Type.String({ description: "The ROS2 service type (e.g., 'gazebo_msgs/srv/SpawnEntity')" })),
|
|
21
23
|
args: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
22
24
|
description: "The service request arguments",
|
|
23
25
|
})),
|
|
26
|
+
...ROBOT_ID_SCHEMA,
|
|
24
27
|
}),
|
|
25
28
|
|
|
26
29
|
async execute(_toolCallId, params) {
|
|
30
|
+
const resolved = resolveRobotForTool(config, params);
|
|
31
|
+
if ("error" in resolved) return resolved.error;
|
|
32
|
+
const { robot } = resolved;
|
|
33
|
+
|
|
27
34
|
const rawService = params["service"] as string;
|
|
28
|
-
const service = toNamespacedTopic(
|
|
35
|
+
const service = toNamespacedTopic(robot.namespace, rawService);
|
|
29
36
|
const type = params["type"] as string | undefined;
|
|
30
37
|
const args = params["args"] as Record<string, unknown> | undefined;
|
|
31
38
|
|
|
32
|
-
const transport =
|
|
39
|
+
const transport = await getTransportForRobot(config, robot);
|
|
33
40
|
const response = await transport.callService({ service, type, args });
|
|
34
41
|
|
|
35
42
|
const result = {
|
|
@@ -2,7 +2,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import type { OpenClawPluginApi } from "../plugin-api.js";
|
|
3
3
|
import type { AgenticROSConfig } from "@agenticros/core";
|
|
4
4
|
import { toNamespacedTopic } from "@agenticros/core";
|
|
5
|
-
import {
|
|
5
|
+
import { getTransportForRobot } from "../service.js";
|
|
6
|
+
import { ROBOT_ID_SCHEMA, resolveRobotForTool } from "./_robot-helpers.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Register the ros2_subscribe_once tool with the AI agent.
|
|
@@ -14,16 +15,22 @@ export function registerSubscribeTool(api: OpenClawPluginApi, config: AgenticROS
|
|
|
14
15
|
label: "ROS2 Subscribe Once",
|
|
15
16
|
description:
|
|
16
17
|
"Subscribe to a ROS2 topic and return the next message. Use this to read sensor data, " +
|
|
17
|
-
"check robot state, or get the current value of a topic."
|
|
18
|
+
"check robot state, or get the current value of a topic. " +
|
|
19
|
+
"Pass robot_id (from ros2_list_robots) to target a specific robot.",
|
|
18
20
|
parameters: Type.Object({
|
|
19
21
|
topic: Type.String({ description: "The ROS2 topic name (e.g., '/battery_state')" }),
|
|
20
22
|
type: Type.Optional(Type.String({ description: "The ROS2 message type (e.g., 'sensor_msgs/msg/BatteryState')" })),
|
|
21
23
|
timeout: Type.Optional(Type.Number({ description: "Timeout in milliseconds (default: 5000)" })),
|
|
24
|
+
...ROBOT_ID_SCHEMA,
|
|
22
25
|
}),
|
|
23
26
|
|
|
24
27
|
async execute(_toolCallId, params) {
|
|
28
|
+
const resolved = resolveRobotForTool(config, params);
|
|
29
|
+
if ("error" in resolved) return resolved.error;
|
|
30
|
+
const { robot } = resolved;
|
|
31
|
+
|
|
25
32
|
const rawTopic = params["topic"] as string;
|
|
26
|
-
const topic = toNamespacedTopic(
|
|
33
|
+
const topic = toNamespacedTopic(robot.namespace, rawTopic);
|
|
27
34
|
let msgType = params["type"] as string | undefined;
|
|
28
35
|
const timeout = (params["timeout"] as number | undefined) ?? 5000;
|
|
29
36
|
|
|
@@ -31,7 +38,7 @@ export function registerSubscribeTool(api: OpenClawPluginApi, config: AgenticROS
|
|
|
31
38
|
msgType = rawTopic.includes("compressed") ? "sensor_msgs/msg/CompressedImage" : "sensor_msgs/msg/Image";
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
const transport =
|
|
41
|
+
const transport = await getTransportForRobot(config, robot);
|
|
35
42
|
|
|
36
43
|
const result = await new Promise<Record<string, unknown>>((resolve, reject) => {
|
|
37
44
|
const subscription = transport.subscribe(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AgenticROS Claude Code adapter
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server that exposes AgenticROS ROS2 tools to **Claude Code CLI** and to the **Claude desktop app** on macOS (including **Claude Dispatch** on iPhone when paired to Claude on your Mac). Use natural language to control and query your ROS2 robot (e.g. "what do you see?"
|
|
3
|
+
MCP (Model Context Protocol) server that exposes AgenticROS ROS2 tools to **Claude Code CLI** and to the **Claude desktop app** on macOS (including **Claude Dispatch** on iPhone when paired to Claude on your Mac). Use natural language to control and query your ROS2 robot (e.g. *"what do you see?"*, *"find a chair and drive toward it"*, *"list every robot that can follow a person"*).
|
|
4
4
|
|
|
5
5
|
This adapter does **not** provide the config or teleop web UI; use the [OpenClaw plugin](../../packages/agenticros) for that, or run the gateway for the browser-based teleop page.
|
|
6
6
|
|
|
@@ -94,6 +94,38 @@ claude
|
|
|
94
94
|
|
|
95
95
|
Scope options: `--scope user` (default), `--scope project` (shared via `.mcp.json`).
|
|
96
96
|
|
|
97
|
+
## Codex CLI (OpenAI)
|
|
98
|
+
|
|
99
|
+
The same MCP server works unmodified with the **OpenAI Codex CLI** — Codex is a vanilla MCP client, and our server speaks the standard `2024-11-05` MCP protocol that every MCP-compatible client uses. Two ways to register it:
|
|
100
|
+
|
|
101
|
+
**Option A — `codex mcp add` (recommended)**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
cd /path/to/agenticros
|
|
105
|
+
codex mcp add agenticros \
|
|
106
|
+
-- node "$(pwd)/packages/agenticros-claude-code/dist/index.js"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Option B — direct edit of `~/.codex/config.toml`**
|
|
110
|
+
|
|
111
|
+
```toml
|
|
112
|
+
[mcp_servers.agenticros]
|
|
113
|
+
command = "node"
|
|
114
|
+
args = ["/ABSOLUTE/PATH/TO/agenticros/packages/agenticros-claude-code/dist/index.js"]
|
|
115
|
+
enabled = true
|
|
116
|
+
startup_timeout_sec = 30
|
|
117
|
+
|
|
118
|
+
[mcp_servers.agenticros.env]
|
|
119
|
+
AGENTICROS_ROBOT_NAMESPACE = "robotYOUR_NAMESPACE_NO_DASHES"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Then start a Codex session and run `/mcp` to verify — you should see `agenticros` connected with **15 tools** (more if you have skills like `agenticros-skill-followme` or `agenticros-skill-find` registered). Same tools, same tool names, same JSON shapes as in Claude Code; everything in the **Tools** section below applies identically.
|
|
123
|
+
|
|
124
|
+
Two Codex-specific notes:
|
|
125
|
+
|
|
126
|
+
- **Absolute path required.** Codex's working directory at server-spawn time is not the AgenticROS repo root, so `args = ["packages/agenticros-claude-code/dist/index.js"]` will fail. Use the full absolute path.
|
|
127
|
+
- **Project-scoped config.** Codex also supports a `.codex/config.toml` in a project directory (and a `mcp.json` in cwd on recent builds) — handy for per-repo MCP setups when you don't want `agenticros` enabled globally. See OpenAI's [Codex config reference](https://developers.openai.com/codex/config-reference) for the precedence rules.
|
|
128
|
+
|
|
97
129
|
## Claude desktop app + Claude Dispatch (iOS)
|
|
98
130
|
|
|
99
131
|
The Claude **desktop** app uses a different MCP config file than Claude Code:
|
|
@@ -134,18 +166,29 @@ The server exposes the same ROS2 tools as the OpenClaw plugin:
|
|
|
134
166
|
|
|
135
167
|
| Tool | Description |
|
|
136
168
|
|------|-------------|
|
|
169
|
+
| **Inspection** | |
|
|
137
170
|
| `ros2_list_topics` | List topics and types |
|
|
138
|
-
| `
|
|
171
|
+
| `ros2_list_capabilities` | Typed verb manifest (built-in + skill-declared) — the planning surface for agents |
|
|
172
|
+
| **Fleet** | |
|
|
173
|
+
| `ros2_list_robots` | List configured robots — id, name, kind, capabilities, online status |
|
|
174
|
+
| `ros2_discover_robots` | Online discovery: detect `/<ns>/cmd_vel` namespaces + classify reachability |
|
|
175
|
+
| `ros2_find_robots_for` | Ranked filter by capability + kind + online — *"who can `follow_person` right now?"* |
|
|
176
|
+
| **Missions** | |
|
|
177
|
+
| `run_mission` | Execute a multi-step mission **or** compile a natural-language `goal` into one. Chains capabilities via `{{stepId.outputs.field}}` template refs; returns a `mission_id` |
|
|
178
|
+
| `mission_cancel` | Cancel an in-flight mission by `mission_id` at the next step boundary (idempotent, safe on unknown ids) |
|
|
179
|
+
| **Direct ROS** | |
|
|
180
|
+
| `ros2_publish` | Publish to a topic (e.g. cmd_vel) — safety-clamped |
|
|
139
181
|
| `ros2_subscribe_once` | Get next message from a topic |
|
|
140
182
|
| `ros2_service_call` | Call a ROS2 service |
|
|
141
183
|
| `ros2_action_goal` | Send goal to an action server |
|
|
142
184
|
| `ros2_param_get` / `ros2_param_set` | Get/set node parameters |
|
|
143
|
-
| `ros2_camera_snapshot` | "What do you see" — one frame from camera topic |
|
|
185
|
+
| `ros2_camera_snapshot` | *"What do you see"* — one frame from camera topic |
|
|
144
186
|
| `ros2_depth_distance` | Distance in meters from depth camera |
|
|
145
|
-
|
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
187
|
+
| **Memory** *(only when enabled)* | |
|
|
188
|
+
| `memory_remember` | Store a durable fact for the robot — shared with OpenClaw, Claude Desktop, Gemini |
|
|
189
|
+
| `memory_recall` | Semantic search across long-term memory (also reads `mission:<id>` step transcripts) |
|
|
190
|
+
| `memory_forget` | Delete by id, query, or whole namespace |
|
|
191
|
+
| `memory_status` | Health check + record count + embedder info |
|
|
149
192
|
|
|
150
193
|
Safety limits (max linear/angular velocity) from config are applied before `ros2_publish`.
|
|
151
194
|
|
|
@@ -255,6 +298,6 @@ If `ros2_publish` runs but the robot doesn’t move:
|
|
|
255
298
|
|
|
256
299
|
In the chat you can type `/mcp` to see MCP server status. If the transport isn’t running (e.g. no Zenoh router), tool calls will fail with connection errors until the ROS2 side is up.
|
|
257
300
|
|
|
258
|
-
##
|
|
301
|
+
## Skills
|
|
259
302
|
|
|
260
|
-
|
|
303
|
+
Skill packages (e.g. `agenticros-skill-followme`, `agenticros-skill-find`) extend the capability registry with new verbs like `follow_person` and `find_object`. The MCP server reads each skill's `package.json` `agenticros` block (`id`, `capabilities[]`) at startup and surfaces those verbs through `ros2_list_capabilities` and `run_mission` — no per-skill MCP tool needed. To register a skill for this adapter, install it with `agenticros skills install <slug>` from the marketplace, or add its path under `skillPaths[]` in `~/.agenticros/config.json` (or use the `agenticros skills add <path>` CLI). See [docs/skills.md](../../docs/skills.md) for the full skill contract.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities-mcp.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/capabilities-mcp.test.ts"],"names":[],"mappings":""}
|