huawei-cloud-cloudrobo-dispatch

v2026.09.24

Manage CloudRobo embodied-agent task dispatch (robo-dispatcher) — create embodied tasks that drive a robot via an exec/model and constraints, list/show tasks in a session, cancel tasks, and retrieve task results. Dispatch orchestrates robots (robot_id from cloudrobo-robot) with inference models (exec_model_id from cloudrobo-infer / cloudrobo-asset) inside a session. Triggers include: dispatch, dispatcher, task dispatch, embodied task, agent task, run task on robot, task scheduling, cancel task, task result, robo-dispatcher, 调度, 智能体调度, 任务下发, 机器人任务, 取消任务, 任务结果, 会话任务.

GitHub
安装命令
npx skhub add huaweicloud/huawei-cloud-cloudrobo-dispatch
Markdown
SKILL.md

Windows / PowerShell: Examples use bash syntax. To run on Windows PowerShell:

  • Flatten \ line continuations to a single line, or end lines with a backtick.
  • Set env vars with $env:NAME="value" instead of export NAME="value".
  • Single-quoted JSON '{"a":"b"}' works as-is.

Overview

The cloudrobo-dispatch skill manages embodied task dispatch via the robo-dispatcher service. It lets the agent create a task that runs on a robot (identified by robot_id) under an execution model (exec_model_id) inside a session (session_id), monitor it, cancel it, and retrieve the natural-language task result plus log items.

Applicable scenarios:

  • Task dispatch — Create a task on a robot given a natural-language task description; always provide a stop condition (exec_constraints: default max_run_time=10 min, max_iter_num=100 steps)
  • Task monitoring — List/show tasks in a session, filter by status/robot/infer-service
  • Wait for task completion — Block until a dispatched task leaves RUNNING without manual polling (wait-task, the preferred way to wait for a task to finish)
  • Task cancellation — Cancel a running/pending task
  • Result retrieval — Get the task result (task + log_items) of a finished task
  • Cross-skill orchestration — Combine robots (cloudrobo-robot) and inference models (cloudrobo-infer / cloudrobo-asset) into concrete robot-executable tasks.

Architecture:

Agent / LLM
    │
    ├── CLI  →  cloudrobo dispatch <command>
    └── SDK  →  DispatchClient (Python) — domain RoboDispatcherTaskManagement
                    │
                    ▼
              cloudrobo-service (REST API)
              /v1/robo-dispatcher/sessions/{session_id}/tasks*

All operations target the cloudrobo-service backend, are scoped to a session_id, and require a valid workspace_id. A session is a stable execution context; multiple tasks can be created within one session across time.

session_id: In the current version, session_id is identical to the current workspace's workspace_id. You can obtain it by reading the active workspace (cloudrobo workspace current) or the configured workspace_id, and reuse it directly as the --session-id. If a caller explicitly provides a different session_id, prefer confirming it against the current workspace.

Prerequisites

  • See references/cli-installation-guide.md for CLI installation, AK/SK authentication, and workspace configuration.
  • A valid session_id for all task operations. In the current version session_id equals the current workspace's workspace_id — read it via cloudrobo workspace current or the configured workspace_id (there is no separate session-create API).
  • A valid robot_id (from cloudrobo-robot) and exec_model_id for the constrained model service that drives the task. The robot must be ONLINE (i.e. its R2C edge client is connected) for a task to run — otherwise the backend rejects it with failure_reason: "Robot offline".

How to obtain exec_model_id (important) — exec_model_id is the execution-model handle that drives the task. Do not put the raw model/asset id (e.g. 8b804b51-…) into it; the backend cannot resolve the asset id and the task will fail.

Two kinds of exec_model_id (verified 2026-08 on this platform):

  1. User-created inference services (deployed via cloudrobo infer create in cloudrobo-infer): exec_model_id equals the inference service's service_id — i.e. the id returned by cloudrobo infer create and by cloudrobo infer list. Practical derivation: run cloudrobo infer list, pick the service you deployed (e.g. so101-real-demo-0828), and use its id (<uuid>) directly as exec_model_id. No separate "model-service UUID" lookup is needed for user-deployed services.
  2. Platform prebuilt / external model-services show an ext_-prefixed opaque handle, e.g. ext_2dcc1539e72040c78650c554102debaf (name e.g. Claude-3.5-Updated) or ext_1ee0bcc7… (name e.g. cloudrobo-real-rl-model-…). These are NOT infer-list services; obtain them from an existing task's constraints.model.exec_model_id.

At any time you can confirm the exact value against an existing successful task in the same session: cloudrobo dispatch list-tasks --session-id <sid> --content-match "<skill prompt>" and read its constraints.model.exec_model_id (the returned exec_model_name equals the source service name).

Workflow

Natural-Language-First Principle

Every workflow below starts from a user intent (1-2 sentences), not from manual CLI/SDK orchestration. The skill then drives the matching command chain and reports state feedback.

Task Dispatch Workflow (module + robot + model + workspace)

Scenario: "Tell robot A to go pick up the red cube and place it in the bin."

  1. Resolve session — read session_id from the current workspace: in the current version session_id == workspace_id (obtain via cloudrobo workspace current / configured workspace_id).
  2. Resolve robot & model — obtain robot_id (from robot registration) and exec_model_id. exec_model_id is the execution-model handle that drives the task — for a service you deployed, it is simply that service's service_id (see the "How to resolve exec_model_id" note below). Both are required in constraints.
  3. Verify robot reachable — the target robot must be ONLINE (r2c edge client connected). A dispatch task on an offline/unconnected robot fails with a Robot offline failure reason. See cloudrobo-r2c to bring a (dummy/real) robot online before dispatching.
  4. Describe task — collect the natural-language task text (e.g. "pick up the red cube and place it in the bin") and a name. If the inference service was deployed with strict:true, the task text MUST match the predefined skill prompt; otherwise the service rejects it. (See cloudrobo-infer for deploying a service with skill_config.strict.)
  5. Create task with stop condition — cloudrobo dispatch create-task --session-id <sid> --name <name> --task "<task>" --constraints-json '<json>'. The --constraints-json is required and carries model, robot_id, and the stop condition exec_constraints. Always set a stop condition (max_run_time and max_iter_num) so the task cannot run unboundedly. Defaults if the user does not specify: max_run_time=10 (minutes), max_iter_num=100 (steps). Confirm before submitting (mutating).
  6. Wait for completion (preferred) — block until the task finishes with cloudrobo dispatch wait-task --session-id <sid> --task-id <task_id> [--timeout <secs>]. This polls internally every 5s and returns once the task status leaves RUNNING (i.e. reaches COMPLETED/FAILED/CANCELLED or any non-RUNNING state). Prefer wait-task over manual show-task polling — it replaces the old 20-30s manual polling loop.
  7. Get result — on completion, cloudrobo dispatch show-task-result --session-id <sid> --task-id <task_id> to read the natural-language result and log items.

Note: robot_id and exec_model_id are required inside constraints. Do not hardcode them; resolve from robot and infer/asset outputs.

How to resolve exec_model_id — exec_model_id is NOT the model asset ID (the 8b804b51-...-style asset UUID from cloudrobo-asset). It is the execution-model handle the task drives. For a service you deployed yourself via cloudrobo infer create, exec_model_id equals that service's service_id (read it from cloudrobo infer list / the create response). Platform prebuilt / external model-services use an ext_-prefixed opaque handle instead. Resolve it by:

  1. If the target model is one of your deployed inference services → cloudrobo infer list, take the service id as exec_model_id (verified equivalent on 2026-08).
  2. Otherwise, confirm the exact value against an existing successful task in the same session: cloudrobo dispatch list-tasks --session-id <sid> --content-match "<deployed skill prompt>" and read its constraints.model.exec_model_id (exec_model_name is the source service name, informational). Using the raw asset UUID in exec_model_id is a common root cause of dispatch failures.

Task Monitoring / Lookup Workflow (module + filters)

Scenario: "What tasks are running in my session?"

  1. cloudrobo dispatch list-tasks --session-id <sid> [--status <status>] [--robot-id <rid>] [--infer-service-id <iid>] [--start-time <ms>] [--end-time <ms>] [--content-match <text>] with pagination (--limit/--offset) and sorting (--sort-key/--sort-dir).
  2. cloudrobo dispatch show-task --session-id <sid> --task-id <task_id> for detail.
  3. Report task status, robot, model, and content.

Task Result Retrieval Workflow (module)

Scenario: "Show me the outcome of that pick-and-place task."

  1. Wait for the task to finish via wait-task (or confirm it is terminal via show-task).
  2. cloudrobo dispatch show-task-result --session-id <sid> --task-id <task_id> — returns the task object plus log_items. Supports --inverse, --limit, --offset for pagination.

Task Cancellation Workflow (module)

Scenario: "Abort that task — the robot picked the wrong object."

  1. Confirm the task via show-task.
  2. cloudrobo dispatch cancel-task --session-id <sid> --task-id <task_id> (mutating; confirm).
  3. Verify via show-task that the task moved to a cancelled state.

Session Context Note

  • Tasks are always created under a session_id. In the current version session_id is the same as the current workspace's workspace_id; obtain it from cloudrobo workspace current. You may create many tasks within one session over time.
  • Stop condition: every task should be created with constraints.exec_constraints so it stops on time — see the Create a Task section for the required object shape and defaults.
  • strict services: if the driving inference service was deployed with skill_config.strict:true, the task you pass MUST match one of its predefined skill prompts; a mismatched prompt is rejected.
  • The old create-session / exec_task / create-session-task interfaces are deprecated and must not be used. All operations use session_id directly on the task endpoints.

CLI Command Format Standard

cloudrobo dispatch <command> [OPTIONS]
FeatureDescription
Command groupdispatch
Subcommandkebab-case: create-task, list-tasks, show-task, cancel-task, show-task-result, wait-task
Session--session-id <id> (all task operations; equals workspace_id in current version)
JSON params--constraints-json '<object>' (create-task; required; holds model/robot_id/exec_constraints)
Dry-run--dry-run (create-task/cancel-task)
Result pagination--inverse, --limit, --offset (show-task-result)
Wait timeout--timeout <secs> (wait-task; default 600, IntRange 1–3600)

Full coverage: SDK exposes 6 methods, CLI exposes 6 commands (0 gaps). See references/cli-installation-guide.md and the acceptance criteria for the coverage mapping.

Core Commands

SDK Direct Calls: When CLI is inconvenient (dynamic JSON, cross-package queries), use the Python SDK directly. DispatchClient (domain RoboDispatcherTaskManagement) exposes the 6 methods below.

Create a Task

cloudrobo dispatch create-task --session-id <session-id> --name <task-name> --task "<natural language task>" --constraints-json '{"model":{"exec_model_id":"<model-id>"},"robot_id":"<robot-id>","exec_constraints":{"max_run_time":10,"max_iter_num":100}}' [--dry-run]

Stop condition is required in practice (constraints.exec_constraints). If the user does not specify values, default to max_run_time=10 (minutes) and max_iter_num=100 (steps) to avoid unbounded/long-running debug tasks. Valid ranges: max_run_time 1–300 minutes, max_iter_num 1–300000 steps.

model object shape (important) — in create-task's constraints.model, only include exec_model_id. Do not add exec_model_name: the create API rejects it with 400 Invalid parameter: exec_model_name. exec_model_name is a response-only field (present in show-task / list-tasks / show-task-result output), never a request field. See the "How to resolve exec_model_id" note for what exec_model_id should be.

from cloudrobo_core.sdk import Config, HttpClient
from cloudrobo_dispatch import DispatchClient

config = Config()
http_client = HttpClient(config)
client = DispatchClient(http_client)

# session_id equals the current workspace_id in the current version
req = {
    "name": "pick-red-cube",
    "task": "pick up the red cube and place it in the bin",
    "constraints": {
        "model": {"exec_model_id": "<mid>"},
        "robot_id": "<robot-id>",
        # stop condition: use the given values, else default max_run_time=10, max_iter_num=100
        "exec_constraints": {"max_run_time": 10, "max_iter_num": 100},
    },
}
task = client.create_dispatcher_task("<session-id>", req)
print(task)  # includes task_id

List Tasks

cloudrobo dispatch list-tasks --session-id <sid> [--status <status>] [--limit 20] [--offset 0]
tasks = client.list_dispatcher_tasks("<session-id>", status="RUNNING")
for t in tasks.get("items", []):
    print(t["id"], t["status"], t["name"])

Show Task Detail

cloudrobo dispatch show-task --session-id <sid> --task-id <task-id>
task = client.show_dispatcher_task("<session-id>", "<task-id>")
print(task["name"], task["status"], task["robot_id"])

Cancel Task

cloudrobo dispatch cancel-task --session-id <sid> --task-id <task-id> [--dry-run]
client.cancel_dispatcher_task("<session-id>", "<task-id>")

Show Task Result

cloudrobo dispatch show-task-result --session-id <sid> --task-id <task-id> [--inverse] [--limit 100] [--offset 0]
result = client.show_dispatcher_task_result("<session-id>", "<task-id>")
print(result["task"]["result"])
for item in result.get("log_items", []):
    print(item)

Wait for Task Completion

Purpose: Block until a dispatched task finishes (its status leaves RUNNING), so you do not have to manually poll show-task in a loop. This is the preferred way to wait for a task in non-interactive / automation scenarios.

cloudrobo dispatch wait-task --session-id <sid> --task-id <task-id> [--timeout <seconds>]
result = client.wait_dispatcher_task("<session-id>", "<task-id>", timeout=600)
# result is the full task dict once status != "RUNNING" (e.g. COMPLETED / FAILED / CANCELLED)
status = (result.get("task") or {}).get("status")

Behavior (authoritative, from source):

  • Method: wait_dispatcher_task(session_id, task_id, timeout=600).
  • Polling: every 5 seconds (POLL_INTERVAL = 5); it calls show_dispatcher_task internally (GET /v1/robo-dispatcher/sessions/{session_id}/tasks/{task_id}).
  • Return condition: returns the task dict as soon as data["task"]["status"] != "RUNNING" — regardless of whether it reached COMPLETED, FAILED, CANCELLED, or another non-RUNNING state. Terminal states: COMPLETED, FAILED, CANCELLED.
  • Default timeout: 600 seconds. --timeout is an IntRange(1, 3600) — max 3600 s (1 hour).
  • On timeout: raises TimeoutError (client); the CLI prints [ERROR] <msg> to stderr and exits with code 1. Always check the return status to distinguish success, failure, and timeout.
  • No independent REST API: wait-task is a client-side polling helper — it has no dedicated backend endpoint and simply wraps show-task.
  • Must create the task first: wait-task does not create a task. Call create-task to get the task_id first, then wait-task on it.

Recommendation (when to use wait-task):

  • Use wait-task right after create-task, then fetch the outcome with show-task-result — this replaces the old manual show-task polling every 20-30s.
  • It is ideal for non-interactive / automation flows that should block until a terminal state.
  • In interactive flows where you want to observe intermediate states, you may still use show-task to inspect progress — but use wait-task when you simply need to wait for the outcome.

Parameter Confirmation

ParameterSourceRequiredConfirmation Needed
--session-idCurrent workspace (workspace_id)Yes (all)In current version session_id == workspace_id; verify against cloudrobo workspace current
--taskUserYes (create)Natural-language task description; if strict service, must match predefined skill prompt
--nameUserYes (create)Task name
--constraints-jsonUser/derivedYes (create)JSON object {model, robot_id, exec_constraints}; holds stop condition
exec_constraints (in --constraints-json)User, else defaultYes in practice (create)Default max_run_time=10 (min), max_iter_num=100 (steps); ranges 1–300 / 1–300000
--task-idUser or prior outputYes (show/cancel/result/wait)Verify before cancel; must exist (from create-task) before wait-task
--timeoutDerivableNo (wait)wait-task timeout in seconds; default 600, IntRange 1–3600
--dry-run—NoPreview without executing

Mutating operations (create-task / cancel-task) must prompt the user for confirmation before execution.

Reference Documents

Edge Cases

ScenarioHandling
Missing session_idIn current version session_id == workspace_id; obtain from cloudrobo workspace current
Missing robot_id / exec_model_idcreate-task requires both inside constraints; resolve from robot and the deployed model service (not the asset id)
exec_model_id is wrong (asset id used)For a service you deployed, exec_model_id equals that service's service_id (read from cloudrobo infer list); using the raw asset id (8b804b51-...) is a common failure. Prebuilt/external model-services use an ext_-prefixed handle. Verify against an existing successful task via list-tasks --content-match "<prompt>"
exec_model_name passed in create requestDo not include exec_model_name in constraints.model — the create API returns 400 Invalid parameter: exec_model_name. exec_model_name is response-only; drop it and retry with only exec_model_id
Robot offline / not connectedA task on an offline robot fails with failure_reason: "Robot offline". Bring the robot ONLINE first via cloudrobo-r2c (dummy/real edge client) before dispatching
Missing stop conditioncreate-task should set constraints.exec_constraints; default max_run_time=10, max_iter_num=100 to avoid unbounded tasks
Over-long taskRespect ranges: max_run_time 1–300 min, max_iter_num 1–300000 steps; don't exceed to keep debug tasks bounded
strict:true serviceIf the inference service was deployed with skill_config.strict:true, the task MUST match a predefined skill prompt; otherwise rejected
Task not foundshow/cancel/result return ResourceNotFoundError; verify task_id/session_id
Path traversalvalidate_safe_id(session_id) / validate_safe_id(task_id) block ../ input
Cancelling a finished taskbackend rejects; confirm status before cancel
Long-running taskPrefer wait-task (polls every 5s, returns once status leaves RUNNING); use show-task only to observe intermediate states, not in a tight manual loop
wait-task timeout--timeout max is 3600s (1h); on timeout the CLI prints [ERROR] and exits 1 — raise/inform the user and re-check with show-task
wait-task on a terminal taskReturns immediately (status already non-RUNNING); safe to call after a task finished
wait-task needs an existing taskIt does not create a task — call create-task first to obtain task_id, or it fails on an invalid/unknown task
Natural-language task contentSanitize/inject-protect; do not echo raw content into logs unescaped
AK/SK not setOperations fail at HTTP signing; set HUAWEI_CLOUD_AK/HUAWEI_CLOUD_SK
Deprecated interfacesDo not use old create-session/exec_task/create-session-task/list-sessions
session_id / task_id / robot_id / exec_model_idNever hardcoded; resolved dynamically (session_id from current workspace)
Cross-skill invocationThis skill does not call other skills; it consumes robot_id (robot) and exec_model_id (infer/asset) and reports task results
Mutating operationscreate-task / cancel-task should be confirmed by the user

Verification Method

Specification Compliance Verification

bash scripts/test-cli-commands.sh

Functional Testing

bash scripts/test-cli-commands.sh

Test Cases

See templates/test-vars.json for the full test case list covering dispatch, monitoring, wait-for-completion, cancellation, result retrieval, and safety scenarios.

Verification Checklist

  • After create-task, task appears in list-tasks with correct status
  • The created task carries a stop condition (exec_constraints.max_run_time / max_iter_num); when the user gave none, they default to 10 min / 100 steps
  • session_id used equals the current workspace's workspace_id
  • When the inference service is strict:true, the task matched the predefined skill prompt
  • After wait-task, the command blocked (polling every 5s) and returned only once status was non-RUNNING; no manual 20-30s polling loop was used
  • wait-task with an explicit --timeout respects the timeout and reports a clear error on expiry
  • wait-task was called with a task_id already created by create-task (it does not create tasks)
  • After show-task, detail returns the task with robot/model/status
  • After show-task-result, natural-language result and log_items are returned
  • After cancel-task, show-task reflects the cancelled state
  • Path traversal (../) is blocked by validate_safe_id
  • Deprecated interfaces (create-session/exec_task) are not used
  • Mutating operations prompt user confirmation before executing

Best Practices

  • Always resolve session_id from the current workspace (cloudrobo workspace current; in the current version session_id == workspace_id), and resolve robot_id / exec_model_id dynamically; never hardcode
  • Always set a stop condition (constraints.exec_constraints) when creating a task; if the user gives none, use the defaults max_run_time=10 (minutes) and max_iter_num=100 (steps) to keep debug tasks bounded (respect ranges 1–300 / 1–300000)
  • If the driving inference service was deployed with strict:true, make the task match the predefined skill prompt
  • Confirm before create-task (it triggers real robot action) and cancel-task
  • After create-task, wait with wait-task instead of manually polling show-task — it blocks (polling every 5s) until the status leaves RUNNING, then fetch the outcome with show-task-result. Use show-task only to inspect intermediate states when needed. In an agent setting, run wait-task as a background process and wait for it to return (it exits on its own once the task is terminal), rather than sleeping + show-task in a manual loop.
  • Set an explicit --timeout on wait-task when the task may run long; on timeout, re-check state with show-task and report the outcome rather than retrying blindly
  • constraints.model only takes exec_model_id — never pass exec_model_name in the create request (400 error); it is a response-only field
  • For a model service you deployed (cloudrobo infer create), exec_model_id = that service's service_id (see cloudrobo infer list); only platform prebuilt/external model-services use ext_-prefixed handles. Prefer cloudrobo infer list over guessing when resolving it
  • Use --dry-run on create-task/cancel-task to validate params before acting
  • Use list-tasks filters (--status, --robot-id, --infer-service-id, --content-match) to quickly locate tasks
  • Sanitize natural-language task content; do not echo raw content into logs unescaped
  • Combine with robot (cloudrobo robot list/show) and infer (cloudrobo infer list) skills to resolve robot/model IDs needed for task creation
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/ai/cloudrobo/huawei-cloud-cloudrobo-dispatch

默认分支

master

最新提交

f690d6e

Tree SHA

a8c0aba