diff --git a/skills/uipath-rpa/SKILL.md b/skills/uipath-rpa/SKILL.md index f6255e1f09..de99447102 100644 --- a/skills/uipath-rpa/SKILL.md +++ b/skills/uipath-rpa/SKILL.md @@ -154,7 +154,7 @@ On Windows PowerShell, `&` doesn't background — use `Start-Process powershell. 7. **[UIA] Before writing ANY UIA activity (XAML `` or coded `uiAutomation.*` / `Descriptors.*`), MUST read [references/uia-starter-guide.md](references/uia-starter-guide.md) — via a two-step read, never a plain full Read: (1) Grep `^## Conditional Policies` on it, (2) Read with `limit` set to that line; the two policy sections below the marker load only when their stated condition applies.** Then the UIA package's core guide it mandates (`{PROJECT_DIR}/.local/docs/packages/UiPath.UIAutomation.Activities/ui-automation-guide.md`) IN FULL, and — before authoring — your mode's authoring guide IN FULL (routed from the core guide's § Documentation). No exceptions for "simple" UIs. Skipping this rule is the most common cause of hallucinated selectors, wrong target XML, and missing OR descriptors. NEVER hand-write selectors — use `uia-configure-target` exclusively (the package guide explains how). The package guide exists only after the package is installed — verify [uia-starter-guide.md § UIA Prerequisites](references/uia-starter-guide.md) first (Rule 7a); if the package is installed but the guide file is absent, the installed version predates it — treat as below the minimum version. The starter guide owns the skill-side UIA policies: run/debug procedure + runtime selector recovery, the stub-mode deliverable pattern, and UI Library publishing. 7a. **[UIA] Verify UIA prerequisites before invoking `uia-configure-target`.** The minimum version and the prerequisite check live in [uia-starter-guide.md § UIA Prerequisites](references/uia-starter-guide.md) — run that check first (do not hardcode the version from memory; that section is the only source of truth). If `UiPath.UIAutomation.Activities` is below the minimum or `{PROJECT_DIR}/.local/docs/packages/UiPath.UIAutomation.Activities/ui-automation-guide.md` is absent (Rule 7 treats a missing guide as below-minimum), the `uip rpa uia` CLI is unavailable — and **both** target capture and indication depend on it, so indication is *not* a fallback when the package itself is missing. Ask the user to install/upgrade per that section. If they decline or the package cannot be installed, fall back to the **Placeholder-Selector Stub Pattern** (§ above) — real activities with `TODO Indicate` markers need no CLI. Never silently route to a non-existent skill path. Use indication capture only when a compatible UIA package *is* installed but `uia-configure-target` cannot see the element; record `UI capture: indication-only` in the plan header to skip `uia-configure-target` in that case. **Runtime failure counts too:** when the package is present but the UIA snapshot CLI's live scans fail persistently (driver/COM errors on every scan), first rule out a locked or non-interactive Windows session (`LogonUI` running = lock screen) — that needs an unlock, not a fallback. Only if scans still fail on an unlocked interactive session, treat capture as unavailable and use the Placeholder-Selector Stub Pattern. 8. **Use `--output json`** on all CLI commands whose output is parsed programmatically. -8a. **A `run` / `debug start` verdict comes from `Data.errors` AND `Data.output` together — NEVER from the outer `Result`, and NEVER from any log entry's `level`.** A completed run passed only when `Data.errors` is empty **and** `Data.output` is `"Session ended"`. The outer `Result` qualifies the CLI invocation, not the workflow: it stays `"Success"` through unhandled exceptions, compile failures, and a missing entry point, so reading it as a verdict reports broken workflows as green. Both `Data` conditions are required, because `errors` stays empty for a missing entry point and for a debug session suspended on an exception, which report the failure in `output` instead. A successful workflow may emit `Log Message` activities at `Error` or `Warning` level as observability — those are workflow-emitted data, not failures, and treating log-entry levels as a failure signal flips green runs to "failed" and burns retries on healthy workflows. Once a run has failed, `logEntries` at `Error` level carry the most specific root cause. **Capture the verdict with `--output-filter` on the run command; never `| tail` the raw payload — `output` and `errors` precede the hundreds of `logEntries` lines, so tailing drops exactly the two fields this rule adjudicates on.** Copy-paste filter: [cli-reference.md § Capturing the verdict](references/cli-reference.md#capturing-the-verdict). See also [cli-reference.md § Reading run / debug results](references/cli-reference.md#reading-run--debug-results) and [debugging.md § Output Format](references/debugging.md#output-format). +8a. **A `run` / `debug start` verdict comes from `Data` — NEVER from the outer `Result` alone, and NEVER from a log line's level — and `Data`'s shape depends on the backend that ran the workflow; identify it by its keys.** Headless Studio (Helm — no Studio Desktop instance has the project open): `Data` is `{output, hasErrors, errorMessage, profiling, debugState, debugDetails}`; passed only when `hasErrors` is `false`, `errorMessage` is `null`, and `debugState` is `null` or `"Completed"`; a faulted `run` returns outer `Result: "Failure"` with those fields JSON-encoded in `Message`; a faulted `debug start` returns `Result: "Success"` with `debugState: "Suspended"` and the exception in `debugDetails` — the session is still alive and must be cancelled or continued. Studio Desktop (the project is open in a running Studio): `Data` is `{output, errors, logEntries, debugState}`; passed only when `errors` is empty AND `output` is `"Session ended"` — a missing entry point returns `Result: "Success"` with `errors: []` and `output: "Failed to open the file "`, so both conditions are needed. Reading `Result: "Success"` as a verdict reports broken workflows as green on both backends. A successful workflow may emit `Log Message` activities at `Error` or `Warning` level as observability — on Helm they stream as `[Level]` lines above the envelope, on Desktop they are `logEntries` entries — and they are workflow-emitted data, not failures; treating them as a failure signal flips green runs to "failed" and burns retries on healthy workflows. **Read the verdict from the envelope as printed: no `--output-filter` on `run` / `debug start` (the two backends have different keys, and a filter naming a key the current backend lacks fails the call after the workflow has already run), and never `| tail` / `| head` the payload — on Helm the log lines precede the envelope, on Desktop the verdict fields precede a long `logEntries`, so either cut drops something this rule needs** ([cli-reference.md § Capturing the verdict](references/cli-reference.md#capturing-the-verdict)). Field meanings: [cli-reference.md § Reading run / debug results](references/cli-reference.md#reading-run--debug-results) and [debugging.md § Output Format](references/debugging.md#output-format). 9. **For "leverage / reuse / find shared libraries" requests, search the tenant feed — not the local filesystem, NuGet.org, or keyword-permutation loops.** Run `uip or libraries list --limit 500 --output-filter "" --output json`. On zero results from the filtered call, take the fallback branch — do not re-keyword. Skip when an SDD already records §16 "Shared libraries referenced" or the user has said "no shared libraries" earlier in the session. See [tenant-library-search-guide.md](references/tenant-library-search-guide.md) for the full procedure. 10. **Register every test case file in `project.json` → `designOptions.fileInfoCollection`.** Applies to both XAML and coded test cases. Required keys, GUID format, JSON snippet, and full schema (including `dataVariationFilePath` for data-driven and `publishAsTestCase` for coded): [references/testing-guide.md § project.json Registration](references/testing-guide.md) and [assets/json-template.md](assets/json-template.md). diff --git a/skills/uipath-rpa/references/cli-reference.md b/skills/uipath-rpa/references/cli-reference.md index f83a677a2c..a607cfef80 100644 --- a/skills/uipath-rpa/references/cli-reference.md +++ b/skills/uipath-rpa/references/cli-reference.md @@ -69,7 +69,7 @@ To create a project, see [environment-setup.md](environment-setup.md); `--target `uip rpa` connects to one of two Studio flavors behind the same IPC contract: - **Headless Studio (Helm) — default.** Ships as a NuGet package and auto-launches on first use. **No Studio Desktop install needed.** First call on a cold NuGet cache may sit near-silent for 30–90 s while `dotnet restore` runs — the default shell timeout covers this; raise `timeoutSeconds` only behind a slow feed. -- **Studio Desktop.** The interactive UI. Used automatically only by verbs with **UI side effects** — those that open a window or highlight something in the designer (discover them via `--help`; they don't work headless). For such a verb, ensure Desktop is up first (`uip rpa studio start --project-dir ""`), then run it. Force Desktop for any command with `UIPATH_RPA_TOOL_USE_STUDIO=1` (not recommended for the standard authoring loop). +- **Studio Desktop.** The interactive UI. A running Studio Desktop instance that has the project open handles that project's `uip rpa` calls — `run` and `debug start` included — and `uip rpa instances list --output json` shows which instance holds which project. Verbs with **UI side effects** (open a window, highlight something in the designer; discover them via `--help`) work only here: ensure Desktop is up first (`uip rpa studio start --project-dir ""`), then run them. Force Desktop for any command with `UIPATH_RPA_TOOL_USE_STUDIO=1` (not recommended for the standard authoring loop). **The two backends return different `run` / `debug start` payloads** — see [Reading run / debug results](#reading-run--debug-results). `--studio-dir` is consulted **only when Studio Desktop is in use**; headless ignores it. When Desktop auto-detection fails, resolution falls back to `UIPATH_STUDIO_DIR`, then the default install path, then a dev build output. Errors like `"does not have interop support"` / `"Requires Studio 26.2+"` mean the detected Desktop is too old — tell the user to update it; this affects only the Desktop-only verbs. @@ -93,33 +93,56 @@ When a package is installed, its activity docs land under `{PROJECT_DIR}/.local/ `uip rpa run` runs a workflow with no debugging; the `debug` group drives breakpoints, stepping, and exception handling (see [debugging.md](debugging.md)). For UI automation, prefer `debug start` over `run` so the app is preserved for selector repair on error. Cancel an active run or session with `uip rpa execution cancel`. Pass workflow inputs as repeatable `--input-arguments key=value` pairs (see [Passing structured inputs](#passing-structured-inputs)); discover the remaining flags (log level, skip-build, profiling) via `--help`. -Both wrap the result in `{Result, Code, Data}`. **`Data`'s inner shape varies by CLI build and run state — read it by key presence, never by assumed schema.** A completed run returns the fields flat (`output`, `errors`, `logEntries` — the workflow's own `Log Message` output arrives in `logEntries`); suspended and stepping debug sessions, and older builds, nest a JSON-encoded string on `Data.runResult` (`HasErrors`, `ErrorMessage`, `DebugState`, `DebugDetails`, `Profiling`). Field-by-field meaning for both shapes: [debugging.md § Output Format](debugging.md#output-format). +Both wrap the result in `{Result, Code, Data}`. **`Data`'s shape is set by the backend that ran the workflow** ([§ Headless Studio (Helm) vs Studio Desktop](#headless-studio-helm-vs-studio-desktop)) — identify it by the keys present: -> **A completed run passed only when `Data.errors` is empty AND `Data.output` is `"Session ended"`.** The outer `Result` qualifies the CLI invocation, not the workflow — it stays `Success` through unhandled exceptions, compile failures, and a missing entry point, so **never read `Result: "Success"` as a passing run**. Both conditions are required, because `errors` stays empty for a missing entry point and for a debug session suspended on an exception. **DO NOT infer failure from a log entry's `level`** — a clean run that logs at `Error` still returns `errors: []` and `output: "Session ended"`; treating log levels as a verdict flips green runs to "failed" and burns retries. Field-by-field behavior per scenario: [debugging.md § Output Format](debugging.md#output-format). +| Backend | `Data` keys | Where the workflow's `Log Message` output is | +|---|---|---| +| **Headless Studio (Helm)** — no Studio Desktop instance has the project open | `output` (serialized output arguments, `"{}"` when none), `hasErrors`, `errorMessage`, `profiling`, `debugState`, `debugDetails` | streamed to stdout as `[] …` lines (`[Information]`, `[Error]`, …) **above** the JSON envelope; nothing inside `Data` | +| **Studio Desktop** — the project is open in a running Studio Desktop | `output` (status string: `"Session ended"` on completion), `errors` (array), `logEntries` (array of `{source, level, message}`, `source` = `Compile` or `Debug`), `debugState` (`"Completed"` on completion; absent when the file could not be opened) | inside `Data.logEntries`; nothing streams above the envelope | + +Field-by-field meaning for both: [debugging.md § Output Format](debugging.md#output-format). + +> **Verdict, Helm shape: passed only when `hasErrors` is `false` AND `errorMessage` is `null` AND `debugState` is `null` or `"Completed"`.** A `run` that faulted, failed validation, or named a missing entry point returns outer `Result: "Failure"` with the same field set JSON-encoded in `Message` (`hasErrors: true`, `errorMessage` = the failure text). A faulted `debug start` returns `Result: "Success"` with `hasErrors: false`, `debugState: "Suspended"`, the exception in `debugDetails` and command guidance in `errorMessage` — the session is still alive; cancel or continue it. +> +> **Verdict, Studio Desktop shape: passed only when `errors` is empty AND `output` is `"Session ended"`.** Both are required: a missing entry point returns outer `Result: "Success"` with `errors: []`, `logEntries: []` and `output: "Failed to open the file "`. An `--input-arguments` key the workflow does not declare is accepted silently (`"Session ended"`). +> +> **On either backend: never read the outer `Result: "Success"` as a passing run, and never infer failure from a `Warning` / `Error` log level** — `Log Message` activities emit at any level, and treating log levels as a verdict flips green runs to "failed" and burns retries. ### Capturing the verdict -**Always pass `--output-filter` on `run` / `debug start`.** It applies a JMESPath expression to `Data` server-side, so one call returns the verdict and the workflow's own `Log Message` output in ~14 lines: +**Run `run` / `debug start` with no `--output-filter` and read the envelope as printed.** The two backends return different key sets, so a filter written for one names keys the other does not have; the CLI then rejects the whole call with `Filter '…' failed to evaluate: Invalid type … received type null` *after* the workflow has already run (`length(errors)` on Helm, any function on `hasErrors` on Desktop), and the retry re-drives the application and costs a turn. On Helm the filter cannot reach the log lines at all — they are outside `Data`. ```bash -uip rpa debug start --file-path "" --project-dir "" --output json \ - --output-filter "{output: output, errorCount: length(errors), errors: errors, runtimeLog: logEntries[?source=='Debug' && level!='Trace'].message | [-8:]}" +uip rpa run --file-path "" --project-dir "" --skip-build --output json ``` -```json +Helm: + +```text +[Information] Starting execution... +[Information] execution started +[Information] Sum: 10 +[Information] execution ended in: 00:00:00 { "Result": "Success", "Code": "ToolResult", "Data": { - "output": "Session ended", "errorCount": 0, "errors": [], - "runtimeLog": ["... execution started", "5 + 5 = 10", "... execution ended in: 00:00:08"] } } + "output": "{}", "hasErrors": false, "errorMessage": null, "profiling": null, "debugState": null, "debugDetails": null } } ``` -Adjudicate straight off `output` and `errorCount` per the rule above; `runtimeLog` carries the workflow's own messages. The `source=='Debug'` term drops compile-phase noise (`Compiling files`, `Registering activities metadata`, dozens of `Unregistered service requested`); widen the slice past `[-8:]` for a chattier workflow. +Studio Desktop (same command, project open in Studio): -**Never `| tail -N` (or `| head`) the unfiltered payload.** `logEntries` runs to hundreds of trace lines, so tailing is the reflex — but `output` and `errors` are emitted *above* it, so tailing keeps the noise and drops the verdict. Recovering them means re-running, which re-drives the application; a workflow that is not re-run-safe behaves differently the second time. +```json +{ "Result": "Success", "Code": "ToolResult", "Data": { + "output": "Session ended", "errors": [], + "logEntries": [ { "source": "Debug", "level": "Information", "message": " execution started" }, + { "source": "Debug", "level": "Information", "message": "Sum: 10" }, + { "source": "Debug", "level": "Information", "message": " execution ended in: 00:00:06" } ], + "debugState": "Completed" } } +``` -When a failure needs more than the filter shows (compile-phase error, root cause older than the slice), redirect the full payload — `> run.json` — and query the file. `jq` is absent on a standard Windows agent host; use PowerShell: `(Get-Content run.json -Raw | ConvertFrom-Json).Data.logEntries | Where-Object level -ne Trace`. +Adjudicate per the two rules above. The workflow's logged values are the `[Information]` lines above the envelope on Helm — read them there and do not strip them (`grep -v '^\['`) — and the `logEntries` entries on Desktop, where `Trace`-level entries (`Unregistered service requested …`, `Audit: …`) outnumber the workflow's own lines. On `debug start` through Helm, `debugState` / `debugDetails` carry the suspended-state exception that selector recovery needs. -> **A style diagnostic can fail the verdict.** `Data.errors` carries analyzer/IDE diagnostics, not just runtime faults — `IDE0063` ("'using' statement can be simplified") sets `output` to `"Execution aborted. See attached errors for more information"` though the body ran and logged normally. When `errors` holds a diagnostic ID rather than an exception, fix the code style and re-run; do not hunt for a runtime failure that did not happen. +**Never `| tail -N` or `| head -N` the payload.** On Helm the log lines precede the envelope, so either cut drops one of the two things you need; on Desktop `output` and `errors` precede a long `logEntries`, so `tail` drops the verdict. Recovering either means re-running, which re-drives the application; a workflow that is not re-run-safe behaves differently the second time. On a Helm `Result: "Failure"` envelope there is no `Data`: read `Message` — the `Data` fields JSON-encoded (`hasErrors: true`) for a `run` that faulted, failed validation, or named a missing entry point; `{"success": false, "errorMessage": "…"}` for a project directory that cannot be opened or an executor that is still busy. +When a failure needs more than the envelope shows (compile-phase error, a stack older than the visible lines), redirect the whole stdout — `> run.log` — and read it from the file: on Helm the `[Error]` lines plus the envelope's `errorMessage`, on Desktop the `errors` and `logEntries` arrays. `jq` is absent on a standard Windows agent host; the envelope is the last JSON object in the file. --- ## Passing structured inputs diff --git a/skills/uipath-rpa/references/debugging.md b/skills/uipath-rpa/references/debugging.md index 4ef5bce872..5648fbb490 100644 --- a/skills/uipath-rpa/references/debugging.md +++ b/skills/uipath-rpa/references/debugging.md @@ -88,7 +88,7 @@ On the headless backend, debugging is a synchronous request/response loop: **eve |---|---|---| | `Paused` | Stopped at a breakpoint or after a step/break. `DebugDetails` carries the current activity (name, id, workflow file) and a snapshot of in-scope variables, arguments, and properties | Inspect `DebugDetails`, then `step-over` / `step-into` / `step-out` / `continue`, or `execution cancel` | | `Suspended` | Stopped on an unhandled exception; the session is still alive. `DebugDetails` carries the exception type, message, faulting activity, and locals | `continue` to propagate the exception, `continue-retry` to re-run the faulted activity, `continue-ignore` to skip it, or `execution cancel` | -| `Completed` | The run finished. The response is the normal run result (`Output`, `HasErrors`, `ErrorMessage`) | Read the run result; the session is gone | +| `Completed` | The run finished. The response is the normal run result (§ Output Format) | Read the run result; the session is gone | | `Running` | The wait timed out before a stable state was reached — execution is still going | Poll with `debug state`, send `debug break` to pause at the next activity, or `execution cancel` | | `None` | No debug session is active | Start one with `debug start` | @@ -178,50 +178,44 @@ For `debug test-activity` and `debug start-from-here`, both `--input-arguments` ## Output Format -`run` and `debug start` both return `{Result, Code, Data}`. **`Data`'s inner shape varies by CLI build and run state — read it by key presence, never by assumed schema.** +`run` and `debug start` both return `{Result, Code, Data}`. **`Data`'s shape is set by the backend that ran the workflow** — Headless Studio (Helm) when no Studio Desktop instance has the project open, Studio Desktop when one does ([cli-reference.md § Headless Studio (Helm) vs Studio Desktop](cli-reference.md#headless-studio-helm-vs-studio-desktop)). Identify the shape by the keys present. -A completed run on the current CLI returns the fields flat, with the workflow's own log output included: +### Helm shape -```json -{ - "Result": "Success", - "Code": "ToolResult", - "Data": { - "output": "Session ended", - "errors": [], - "logEntries": [ { "source": "Debug", "level": "Information", "message": "5 + 5 = 10" } ] - } -} -``` +A clean `run`, then the same workflow under `debug start`: -| Field | Type | Meaning | -|-------|------|---------| -| `output` | `string` or `array` | Terminal status when the run ended: `"Session ended"` on clean completion, `"Execution aborted. See attached errors for more information"` on failure, `"Failed to open the file "` when the entry point does not exist. A JSON array of `{category, type, name, value}` locals when a debug session is suspended on an exception. **Never the workflow's output arguments.** | -| `errors` | `array` | `{errorName, errorMessage, lineNumber}` per entry. Populated for an unhandled exception (`errorName` is the exception type) and for a compile failure (`errorName: "ERROR"`). **Empty does not mean success** — a missing entry point and a suspended session both report `[]`. | -| `logEntries` | `array` | `{source, level, message}` per entry, `source` one of `Compile` / `Debug`. **The workflow's `Log Message` output lands here** — this is where a logged value is read back to confirm runtime behavior. Compile failures also land here at `Error` level with the root cause (e.g. `Cannot set unknown member ...`), which `errors` reports only as `This activity is missing or could not be loaded.` | - -**Output arguments are not in the envelope.** A workflow that assigns its `out_*` arguments still returns `output: "Session ended"`; the values appear nowhere in `Data`. Read them from the workflow's own `Log Message` output in `logEntries`, or from artifacts the workflow wrote. +```text +[Information] Starting execution... +[Information] execution started +[Information] Sum: 10 +[Information] execution ended in: 00:00:00 +{ "Result": "Success", "Code": "ToolResult", + "Data": { "output": "{}", "hasErrors": false, "errorMessage": null, "profiling": null, "debugState": null, "debugDetails": null } } +``` -Older builds nest the same information as a JSON-encoded string on `Data.runResult`. When that key is present, parse it and read these fields instead: +```json +{ "Result": "Success", "Code": "ToolResult", + "Data": { "output": "{}", "hasErrors": false, "errorMessage": null, "profiling": null, "debugState": "Completed", "debugDetails": null } } +``` | Field | Type | Meaning | |-------|------|---------| -| `Output` | `string` | Workflow's serialized output arguments JSON, populated when the run completes. **Carries the workflow's data, not a verdict.** | -| `HasErrors` | `bool` | `true` iff execution finished without `Succeeded` (compile failure, validation failure, unhandled exception that ended the run, cancellation, timeout). `false` otherwise — including while `Suspended` on an exception, because the session is still alive and the outcome undecided. | -| `ErrorMessage` | `string?` | Formatted error chain when `HasErrors: true`. On debug responses it may instead carry **guidance** (e.g. which commands apply in a `Suspended` state) with `HasErrors: false`. `null` otherwise. | -| `DebugState` | `string?` | Debug sessions only (`null` on plain `run`): `Paused`, `Suspended`, `Running`, `Completed`, or `None`. See [The stable-state debug loop](#the-stable-state-debug-loop-headless). | -| `DebugDetails` | `string?` | Debug sessions only: JSON snapshot for the state — current activity + locals when `Paused`; exception type/message/activity + locals when `Suspended`; `null` otherwise. | -| `Profiling` | `object?` | Present only when `--profiling` was passed on a start command and collection succeeded. Single field `OutputDirectory` — absolute path to the run's `*.uistat` and screenshot folder (verifies UI automation correctness and workflow performance). `null` / omitted otherwise. See [Profiling Workflow Performance](#profiling-workflow-performance). | +| `output` | `string` | Workflow's serialized output arguments JSON once the run ends — `{"out_Sum":10}` for an entry point with `out_Sum`, `"{}"` for one that declares none, also on a run that faulted inside an activity. `""` while a session is `Paused`, `Suspended` or `Running`, on `debug state`, and when the run never started (validation failure, missing entry point). **Carries the workflow's data, not a verdict.** | +| `hasErrors` | `bool` | `true` when the run ended without succeeding: an unhandled exception that ended a `run`, a compile/validation failure, a missing entry point. `false` otherwise — including while `Suspended` on an exception, because the session is still alive and the outcome undecided. | +| `errorMessage` | `string?` | The failure text when `hasErrors: true`: an activity fault gives `Source: `, `Message: …`, `Exception Type: …` and the stack; a compile/validation failure gives `Validation failed with N error(s):` and the diagnostics; a missing entry point gives `Message: The workflow cannot be found …`. On the response that reports a `Suspended` session it carries **guidance** (which commands apply) with `hasErrors: false`. `null` otherwise. | +| `debugState` | `string?` | Debug sessions only (`null` on plain `run`): `Paused` (breakpoint), `Suspended` (unhandled exception), `Running` (`debug state` polled mid-run), `Completed`, or `None` (`debug state` with no session). See [The stable-state debug loop](#the-stable-state-debug-loop-headless). | +| `debugDetails` | `string?` | Debug sessions only: JSON snapshot for the state — `Activity`, `ActivityId`, `WorkflowFile`, `CurrentActivity` and locals when `Paused`; `ExceptionType`, `Message`, `Activity`, `CurrentActivity` and locals when `Suspended`; `""` while `Running`; `null` otherwise. | +| `profiling` | `object?` | `null` unless `--profiling` was passed on a start command; then `{"outputDirectory": ""}` — the run's `*.uistat` and screenshot folder (verifies UI automation correctness and workflow performance). See [Profiling Workflow Performance](#profiling-workflow-performance). | -Workflow log output (`Log Message` activity, system traces) arrives on `Data.logEntries` when that key is present; when the response nests `runResult` instead, the logs are streamed live on a separate channel and are not embedded in `runResult`. Either way the logs are diagnostic data, never the verdict. +**On Helm the workflow's log output is not in the envelope.** `Log Message` activities and system traces stream to stdout as `[Level] message` lines *above* the JSON envelope, live, while the run executes. That is where a logged value is read back to confirm runtime behavior — do not strip those lines. Output arguments are read from `output`, from the workflow's own log lines, or from artifacts the workflow wrote. -> **The outer `Result` reports the CLI invocation, NOT the workflow.** It is `ValidationError` for an unknown flag and `Failure` for an unopenable project directory, but `Success` as soon as the runtime was invoked — including when the workflow threw an unhandled exception, failed to compile, or the entry point did not exist. **Never treat `Result: "Success"` as a passing run.** +> **The outer `Result` reports the CLI invocation, NOT the workflow.** On Helm it is `ValidationError` for an unknown flag or a filter that failed to evaluate; `Failure` **for a `run` whose workflow faulted, failed validation, or named a missing entry point** (`Message` holds the `Data` fields JSON-encoded, `hasErrors: true`) and for a project directory that cannot be opened or an executor that is still busy (`Message` holds `{"success": false, "errorMessage": "…"}`); and `Success` for every `debug start` that reached the runtime — including one suspended on an unhandled exception. **Never treat `Result: "Success"` as a passing run.** > -> **A completed run passed only when `Data.errors` is empty AND `Data.output` is `"Session ended"`.** Both conditions are required: `errors` is populated for exceptions and compile failures, while a missing entry point and a suspended debug session leave it empty and report the failure in `output` instead. +> **Helm verdict: a run passed only when `Data.hasErrors` is `false` AND `Data.errorMessage` is `null` AND `Data.debugState` is `null` or `"Completed"`.** All three are required: a suspended debug session reports `hasErrors: false` with `debugState: "Suspended"` and guidance in `errorMessage`; a completed failure reports `hasErrors: true` with the chain in `errorMessage`. > -> **Do NOT use log entries' `level` as a failure signal** — workflow `Log Message` activities emit at any level, and a clean run that logs at `Error` still returns `errors: []` with `output: "Session ended"`. Treating log levels as a verdict flips green runs to "failed". Conversely, when a run has failed, `logEntries` at `Error` level carry the most specific diagnosis — read them for the root cause after the verdict is already established. +> **Do NOT use a log line's level as a failure signal** — workflow `Log Message` activities emit at any level, and a clean run that logs at `Error` still returns `hasErrors: false`. Treating log levels as a verdict flips green runs to "failed". Conversely, when a run has failed, `errorMessage` and the `[Error]` lines above the envelope carry the most specific diagnosis — read them for the root cause after the verdict is already established. -Examples: +Helm examples: ```jsonc // Successful completed run — workflow logged a warning, but hasErrors is false @@ -241,6 +235,30 @@ Examples: "debugDetails": "{\"ExceptionType\":\"System.InvalidOperationException\",\"Message\":\"...\",\"Activity\":\"Throw\",\"Locals\":{...}}" } ``` +### Studio Desktop shape + +The same clean `run` (or `debug start`) with the project open in Studio Desktop: + +```json +{ "Result": "Success", "Code": "ToolResult", + "Data": { "output": "Session ended", "errors": [], + "logEntries": [ { "source": "Compile", "level": "Information", "message": "Restoring nuget packages" }, + { "source": "Debug", "level": "Information", "message": " execution started" }, + { "source": "Debug", "level": "Trace", "message": "Unregistered service requested: UiPath.UIAutomationNext.Contracts.IStudioService)" }, + { "source": "Debug", "level": "Information", "message": "Sum: 10" }, + { "source": "Debug", "level": "Information", "message": " execution ended in: 00:00:06" } ], + "debugState": "Completed" } } +``` + +| Field | Type | Meaning | +|-------|------|---------| +| `output` | `string` | Status string: `"Session ended"` when the run completed; `"Failed to open the file "` when the entry point does not exist. Not the output arguments. | +| `errors` | `array` | Empty on a passing run and on a missing entry point. | +| `logEntries` | `array` | `{source, level, message}` per entry, `source` = `Compile` (restore/build phase) or `Debug` (execution). **The workflow's `Log Message` output lands here**, among `Trace`-level runtime entries (`Unregistered service requested …`, `Audit: …`). Nothing streams above the envelope. Empty when the file could not be opened. | +| `debugState` | `string` | `"Completed"` on a completed `run` or `debug start`. Absent when the file could not be opened. | + +> **Studio Desktop verdict: a run passed only when `Data.errors` is empty AND `Data.output` is `"Session ended"`.** Both are required: a missing entry point returns outer `Result: "Success"` with `errors: []`, `logEntries: []` and `output: "Failed to open the file "`. An `--input-arguments` key the workflow does not declare is accepted silently and the run completes. Log-entry `level` is not a failure signal here either. + --- ## Choosing the Right Verb @@ -306,7 +324,7 @@ uip rpa debug test-activity \ --output json # 3. Check the output: -# - HasErrors / ErrorMessage → compile/validation issues, unhandled exceptions +# - hasErrors / errorMessage → compile/validation issues, unhandled exceptions # - Streamed log entries → runtime messages from the activity (observability, not a verdict) # - Output → workflow's serialized output args on success ``` @@ -377,10 +395,11 @@ uip rpa debug start --file-path "MyWorkflow.xaml" --output json uip rpa debug continue --output json # 4. Check the response for: -# - Data.errors empty AND Data.output == "Session ended" (nested shape: HasErrors false) — -# the pass/fail signal; the outer Result stays "Success" even through failures -# - Output (workflow's serialized output args) carries the expected values -# - Streamed log entries during the run are diagnostic context, NOT a failure signal — +# - Helm: Data.hasErrors false AND Data.errorMessage null AND Data.debugState null/"Completed"; +# Studio Desktop: Data.errors empty AND Data.output == "Session ended" — +# the pass/fail signal; the outer Result stays "Success" for a suspended debug session +# - Data.output (workflow's serialized output args) carries the expected values +# - Streamed [Level] log lines above the envelope are diagnostic context, NOT a failure signal — # Error/Warning levels there are workflow-emitted observability, not CLI failures # 5. Cancel @@ -405,7 +424,7 @@ uip rpa debug start --file-path "ProcessOrder.xaml" \ ## Profiling Workflow Performance -Use `--profiling` on a start verb to collect per-activity timings **and runtime screenshots** — the same data Studio's **Profile Execution** tool surfaces. Profiling serves two purposes that can be addressed in a single run: **verifying UI automation correctness** (via the captured screenshots — confirm clicks landed on the right element, forms filled as expected, screens transitioned correctly) **and verifying workflow performance** (via the per-activity timings). The executor writes `*.uistat` files plus screenshots into `%LOCALAPPDATA%\UiPath\ProfiledRuns\HHmmss_yyyy-MM-dd__\` and the response carries the absolute path on `Profiling.OutputDirectory` — flat on `Data`, or inside the parsed string when the response nests `runResult` (§ Output Format). +Use `--profiling` on a start verb to collect per-activity timings **and runtime screenshots** — the same data Studio's **Profile Execution** tool surfaces. Profiling serves two purposes that can be addressed in a single run: **verifying UI automation correctness** (via the captured screenshots — confirm clicks landed on the right element, forms filled as expected, screens transitioned correctly) **and verifying workflow performance** (via the per-activity timings). The executor writes `*.uistat` files plus screenshots into `%LOCALAPPDATA%\UiPath\ProfiledRuns\HHmmss_yyyy-MM-dd__\` and the response carries the absolute path on `Data.profiling.outputDirectory` (§ Output Format). ### When to enable profiling @@ -438,7 +457,7 @@ Only start verbs collect profiling — `--profiling` is silently ignored on step uip rpa run --file-path "ProcessOrders.xaml" --profiling --output json ``` -Read `Data.Profiling.OutputDirectory` — flat on `Data` when the response is flat, inside the parsed string when the response nests `runResult` (§ Output Format): +Read `Data.profiling.outputDirectory`: ```jsonc { @@ -460,11 +479,11 @@ The directory contains `*.uistat` files — one per workflow file executed in th ### Caveats -- `Profiling` field is **absent** if the run did not reach the executor (compile failure surfaces in `ErrorMessage` instead) or if the active Studio profile does not support profiling (non-Develop profiles register a no-op profiling service). Treat the field as optional — never assume it is populated. +- `profiling` is `null` when the run did not reach the executor (compile failure surfaces in `errorMessage` instead) or when the active Studio profile does not support profiling (non-Develop profiles register a no-op profiling service). Check it before reading `outputDirectory`. - Numbers from a `debug start` profile run differ from a `run` profile run — the debugger adds tracking overhead. For perf comparisons, always use `run`. - Files are not auto-cleaned. After an investigation, manually clear `%LOCALAPPDATA%\UiPath\ProfiledRuns\` if disk usage matters. - Profiling is per run, not aggregated across runs. To compare two implementations, run each with `--profiling` separately and diff the `*.uistat` reports. -- Studio's profiling tool window does **not** auto-focus on agent-triggered runs (intentional — profiling panel and Autopilot pane share a dock slot). Direct the user to `Profiling.OutputDirectory` on disk; do not tell them "open the profiling panel". +- Studio's profiling tool window does **not** auto-focus on agent-triggered runs (intentional — profiling panel and Autopilot pane share a dock slot). Direct the user to `profiling.outputDirectory` on disk; do not tell them "open the profiling panel". > **Activity-targeted profiling needs Studio Desktop.** `debug test-activity` and `debug start-from-here` collect profiling fine, but they depend on `focus-activity` — which only runs against Studio Desktop. `run` and `debug start` profile on both Studio Desktop and headless (Helm). See [Studio Desktop vs headless](#studio-desktop-vs-headless). @@ -472,18 +491,18 @@ The directory contains `*.uistat` files — one per workflow file executed in th ## Reading Debug Output Effectively -Read the response in this order, resolving each field by key presence per § Output Format. **Verdict comes from `Data.errors` and `Data.output` together (nested shape: `HasErrors`) — never from the outer `Result`, and never from log-entry levels.** +Read the response in this order (fields per § Output Format; the Helm shape is described — on the Studio Desktop shape the verdict is `errors` empty AND `output == "Session ended"`, and the log lines are the `logEntries` array). **Verdict comes from `Data` — never from the outer `Result` alone, and never from log-line levels.** -1. **`Data.errors` and `Data.output` together** — the success/failure signal. Passed only when `errors` is empty AND `output` is `"Session ended"`. The outer `Result` qualifies the CLI call, not the run, and stays `Success` through exceptions, compile failures, and a missing entry point. -2. **`ErrorMessage` (when `HasErrors: true`)** — formatted chain with the source activity, exception type, message, and stack trace. This is the canonical failure diagnostic. -3. **`Output` (when `HasErrors: false`)** — workflow's serialized output arguments JSON for `run` / `debug start` completions. Empty string `""` for debug-command responses (step / continue / cancel) and on failure. The flat shape's `output` is a status string instead, so read output arguments from the workflow's own logging or its written artifacts when `runResult` is absent. -4. **Log entries** — diagnostic context, on `Data.logEntries` when present, otherwise streamed live on a separate channel. Use them to read variable values the workflow logged, trace ordering, or correlate context with an `ErrorMessage` that already failed the run. **Do NOT use log-entry `Level` as a failure signal.** +1. **`hasErrors` + `errorMessage` + `debugState`** — the success/failure signal. Passed only when `hasErrors` is `false`, `errorMessage` is `null`, and `debugState` is `null` or `"Completed"`. The outer `Result` qualifies the CLI call, not the run: `Failure` for a faulted `run` (fields JSON-encoded in `Message`), `Success` for a suspended debug session. +2. **`errorMessage` (when `hasErrors: true`)** — formatted chain with the source activity, exception type, message, and stack trace. This is the canonical failure diagnostic. With `hasErrors: false` and `debugState: "Suspended"` it carries command guidance instead; the exception is in `debugDetails`. +3. **`output` (when `hasErrors: false`)** — workflow's serialized output arguments JSON for `run` / `debug start` completions (`"{}"` when none are declared). `""` while a session is `Paused` / `Suspended` / `Running`, on `debug state`, and when the run never started (validation failure, missing entry point); `"{}"` on a run that faulted inside an activity. +4. **Log lines** — diagnostic context, streamed live as `[Level] message` lines above the envelope. Use them to read variable values the workflow logged, trace ordering, or correlate context with an `errorMessage` that already failed the run. **Do NOT use a log line's level as a failure signal.** ### Identifying the Root Cause from Debug Output A practical example — a workflow makes an HTTP request and tries to deserialize the response as JSON, but fails: -- **`HasErrors: true`** with `ErrorMessage` carrying `JsonReaderException: Unexpected character encountered while parsing value: T` — the deserializer tried to parse a non-JSON response +- **`hasErrors: true`** with `errorMessage` carrying `JsonReaderException: Unexpected character encountered while parsing value: T` — the deserializer tried to parse a non-JSON response - **Streamed log entries** (or workflow `Log Message` activities) reveal the HTTP response variable had `StatusCode: "TooManyRequests"` and `TextContent: "Too Many Requests\r\n"` — the API returned a 429, not JSON - **Fix**: Add status code checking before deserialization, or add retry logic with backoff to the HTTP request @@ -504,4 +523,4 @@ A practical example — a workflow makes an HTTP request and tries to deserializ - **Cancel the session when done** — always issue `execution cancel` to cleanly end the run or debug session. - **Use `--log-level Verbose`** when you need maximum detail about what the workflow is doing between steps. - **Remember expression syntax for variables** — when using `debug test-activity` or `debug start-from-here`, string values need VB/C# string literal quotes inside the JSON value (e.g., `"\"hello\""` not `"hello"`). -- **Reach for `--profiling` when investigating performance or verifying UI automation correctness** — pair it with `run` for production-like numbers (the debugger adds overhead). Read the response's `Profiling.OutputDirectory`: open the `*.uistat` files starting with activities holding the largest cumulative percentage, and inspect the captured screenshots to confirm each UI interaction landed on the expected screen / element. See [Profiling Workflow Performance](#profiling-workflow-performance). +- **Reach for `--profiling` when investigating performance or verifying UI automation correctness** — pair it with `run` for production-like numbers (the debugger adds overhead). Read the response's `profiling.outputDirectory`: open the `*.uistat` files starting with activities holding the largest cumulative percentage, and inspect the captured screenshots to confirm each UI interaction landed on the expected screen / element. See [Profiling Workflow Performance](#profiling-workflow-performance). diff --git a/skills/uipath-rpa/references/uia-starter-guide.md b/skills/uipath-rpa/references/uia-starter-guide.md index 68bcba157f..5df99f21a3 100644 --- a/skills/uipath-rpa/references/uia-starter-guide.md +++ b/skills/uipath-rpa/references/uia-starter-guide.md @@ -48,9 +48,9 @@ Omit `,version=` to resolve the latest compatible build (at or abov **Every debug run** must follow this procedure to prevent stale windows from accumulating or being reused in a dirty state: 1. **Record the window baseline** — list top-level windows via the UIA snapshot CLI and note which w-refs and titles are already present. Procedure: the package guide's § Window Baseline (`{PROJECT_DIR}/.local/docs/packages/UiPath.UIAutomation.Activities/ui-automation-guide.md`). -2. **Run the workflow** — always with `--output-filter`, so one call returns the verdict and the workflow's own log instead of hundreds of trace lines (filter expression and the `| tail` trap: [cli-reference.md § Capturing the verdict](cli-reference.md#capturing-the-verdict)): +2. **Run the workflow** — no `--output-filter`; the envelope is the verdict, and the workflow's own `Log Message` output streams above it (Helm) or sits in `Data.logEntries` (Studio Desktop) — shapes and verdict rules in [cli-reference.md § Capturing the verdict](cli-reference.md#capturing-the-verdict): ```bash - uip rpa debug start --file-path "" --project-dir "" --output json --output-filter "" + uip rpa debug start --file-path "" --project-dir "" --output json ``` If the run fails, follow [Runtime Selector Failure Recovery](#runtime-selector-failure-recovery) — this is the **only** correct recovery path. Do not hand-edit selectors in the XAML file. 3. **When done** (success or failure) — **cancel the debug session:**