@uipath/skills 1.197.2 → 1.198.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.
Files changed (144) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CODEOWNERS +18 -11
  4. package/README.md +1 -0
  5. package/assets/skill-status.json +8 -0
  6. package/hooks/hooks.json +44 -8
  7. package/hooks/send-telemetry.ps1 +392 -0
  8. package/hooks/send-telemetry.sh +118 -86
  9. package/hooks/set-session-env.ps1 +72 -0
  10. package/hooks/set-session-env.sh +64 -0
  11. package/hooks/suggest-permissions.ps1 +45 -0
  12. package/hooks/suggest-permissions.sh +4 -0
  13. package/package.json +1 -1
  14. package/skills/uipath-admin/references/audit-commands.md +2 -2
  15. package/skills/uipath-admin/references/audit-workflow-guide.md +4 -4
  16. package/skills/uipath-agents/references/coded/capabilities/batch-transform/planning.md +1 -1
  17. package/skills/uipath-agents/references/coded/capabilities/deeprag/planning.md +1 -1
  18. package/skills/uipath-agents/references/coded/capabilities/guardrails/guardrails-recommend.md +5 -2
  19. package/skills/uipath-agents/references/coded/capabilities/guardrails/guardrails.md +8 -4
  20. package/skills/uipath-agents/references/coded/embedding-in-flows.md +1 -1
  21. package/skills/uipath-agents/references/coded/flow-integration.md +2 -2
  22. package/skills/uipath-agents/references/coded/lifecycle/build.md +0 -1
  23. package/skills/uipath-agents/references/coded/lifecycle/setup.md +0 -1
  24. package/skills/uipath-agents/references/coded/quickstart.md +1 -1
  25. package/skills/uipath-agents/references/lowcode/agent-definition.md +24 -5
  26. package/skills/uipath-agents/references/lowcode/capabilities/built-in-tools/batch-transform/planning.md +1 -1
  27. package/skills/uipath-agents/references/lowcode/capabilities/built-in-tools/deeprag/planning.md +1 -1
  28. package/skills/uipath-agents/references/lowcode/capabilities/context/attachments.md +1 -0
  29. package/skills/uipath-agents/references/lowcode/capabilities/guardrails/guardrails-recommend.md +1 -0
  30. package/skills/uipath-api-workflow/references/cli-reference.md +1 -1
  31. package/skills/uipath-api-workflow/references/connector-activity-discovery.md +1 -1
  32. package/skills/uipath-api-workflow/references/troubleshooting.md +1 -1
  33. package/skills/uipath-automation-discovery/SKILL.md +26 -1
  34. package/skills/uipath-automation-discovery/assets/templates/estimation-worksheet-template.md +80 -0
  35. package/skills/uipath-automation-discovery/references/estimation-guide.md +104 -0
  36. package/skills/uipath-connector-builder/SKILL.md +6 -4
  37. package/skills/uipath-connector-builder/references/auth.md +137 -13
  38. package/skills/uipath-connector-builder/references/configuration.md +29 -7
  39. package/skills/uipath-connector-builder/references/debugging.md +1 -1
  40. package/skills/uipath-connector-builder/references/standard-resources.md +162 -13
  41. package/skills/uipath-feedback/SKILL.md +12 -6
  42. package/skills/uipath-governance/references/cli-cheatsheet.md +3 -3
  43. package/skills/uipath-governance/references/diagnose/references/failure-modes.md +5 -5
  44. package/skills/uipath-insights/SKILL.md +277 -0
  45. package/skills/uipath-insights/references/investigation-playbook-guide.md +145 -0
  46. package/skills/uipath-insights/references/jobs-commands-guide.md +144 -0
  47. package/skills/uipath-ixp/SKILL.md +6 -3
  48. package/skills/uipath-ixp/references/cli-reference.md +19 -4
  49. package/skills/uipath-maestro-bpmn/references/cli-conventions.md +2 -0
  50. package/skills/uipath-maestro-bpmn/validator/README.md +12 -2
  51. package/skills/uipath-maestro-case/SKILL.md +27 -13
  52. package/skills/uipath-maestro-case/assets/templates/sdd-template-examples.md +37 -4
  53. package/skills/uipath-maestro-case/assets/templates/sdd-template.md +20 -9
  54. package/skills/uipath-maestro-case/assets/templates/sdd-viewer.html +8 -7
  55. package/skills/uipath-maestro-case/references/bindings-v2-sync.md +5 -1
  56. package/skills/uipath-maestro-case/references/brownfield.md +86 -0
  57. package/skills/uipath-maestro-case/references/case-commands.md +8 -0
  58. package/skills/uipath-maestro-case/references/case-editing-operations.md +230 -21
  59. package/skills/uipath-maestro-case/references/case-schema.md +29 -11
  60. package/skills/uipath-maestro-case/references/connector-integration.md +1 -1
  61. package/skills/uipath-maestro-case/references/connector-trigger-common.md +1 -1
  62. package/skills/uipath-maestro-case/references/entry-points-sync.md +204 -0
  63. package/skills/uipath-maestro-case/references/implementation.md +19 -9
  64. package/skills/uipath-maestro-case/references/phase-0-interview.md +10 -8
  65. package/skills/uipath-maestro-case/references/phased-execution.md +11 -4
  66. package/skills/uipath-maestro-case/references/placeholder-tasks.md +24 -2
  67. package/skills/uipath-maestro-case/references/planning.md +9 -3
  68. package/skills/uipath-maestro-case/references/plugins/case/planning.md +2 -0
  69. package/skills/uipath-maestro-case/references/plugins/sla/impl-json.md +1 -1
  70. package/skills/uipath-maestro-case/references/plugins/sla/planning.md +1 -1
  71. package/skills/uipath-maestro-case/references/plugins/stages/impl-json.md +11 -10
  72. package/skills/uipath-maestro-case/references/plugins/stages/planning.md +13 -14
  73. package/skills/uipath-maestro-case/references/plugins/tasks/agent/impl-json.md +3 -1
  74. package/skills/uipath-maestro-case/references/plugins/tasks/agent/planning.md +91 -2
  75. package/skills/uipath-maestro-case/references/plugins/tasks/api-workflow/impl-json.md +3 -1
  76. package/skills/uipath-maestro-case/references/plugins/tasks/api-workflow/planning.md +87 -2
  77. package/skills/uipath-maestro-case/references/plugins/tasks/connector-activity/planning.md +1 -1
  78. package/skills/uipath-maestro-case/references/plugins/triggers/event/impl-json.md +1 -1
  79. package/skills/uipath-maestro-case/references/plugins/triggers/manual/impl-json.md +3 -1
  80. package/skills/uipath-maestro-case/references/plugins/triggers/timer/impl-json.md +2 -1
  81. package/skills/uipath-maestro-case/references/plugins/variables/bindings/impl-json.md +2 -0
  82. package/skills/uipath-maestro-case/references/plugins/variables/global-vars/impl-json.md +20 -10
  83. package/skills/uipath-maestro-case/references/plugins/variables/global-vars/planning.md +9 -8
  84. package/skills/uipath-maestro-case/references/plugins/variables/io-binding/impl-json.md +1 -1
  85. package/skills/uipath-maestro-case/references/plugins/variables/io-binding/planning.md +1 -1
  86. package/skills/uipath-maestro-case/references/registry-discovery.md +87 -10
  87. package/skills/uipath-maestro-case/references/sdd-generation-rules.md +34 -26
  88. package/skills/uipath-maestro-flow/SKILL.md +4 -1
  89. package/skills/uipath-maestro-flow/references/author/CAPABILITY.md +1 -2
  90. package/skills/uipath-maestro-flow/references/author/references/editing-operations-json.md +3 -3
  91. package/skills/uipath-maestro-flow/references/author/references/greenfield.md +4 -2
  92. package/skills/uipath-maestro-flow/references/author/references/planning-arch.md +0 -1
  93. package/skills/uipath-maestro-flow/references/author/references/planning-impl.md +0 -1
  94. package/skills/uipath-maestro-flow/references/author/references/plugins/connector/impl.md +1 -0
  95. package/skills/uipath-maestro-flow/references/author/references/plugins/connector-trigger/impl.md +7 -7
  96. package/skills/uipath-maestro-flow/references/author/references/plugins/ixp/impl.md +14 -14
  97. package/skills/uipath-maestro-flow/references/author/references/plugins/script/impl.md +10 -6
  98. package/skills/uipath-maestro-flow/references/shared/cli-conventions.md +7 -0
  99. package/skills/uipath-maestro-flow/references/shared/file-format.md +1 -1
  100. package/skills/uipath-mcp-servers/references/is-activity-workflow.md +3 -3
  101. package/skills/uipath-planner/SKILL.md +1 -1
  102. package/skills/uipath-platform/SKILL.md +4 -14
  103. package/skills/uipath-platform/references/data-fabric/data-fabric.md +1 -1
  104. package/skills/uipath-platform/references/integration-service/agent-workflow.md +4 -4
  105. package/skills/uipath-platform/references/integration-service/reference-resolution.md +1 -1
  106. package/skills/uipath-platform/references/integration-service/resources.md +5 -5
  107. package/skills/uipath-platform/references/integration-service/triggers.md +10 -9
  108. package/skills/uipath-platform/references/orchestrator/setup-environment.md +2 -0
  109. package/skills/uipath-review/SKILL.md +8 -4
  110. package/skills/uipath-review/references/agents/agent-review-checklist.md +1 -22
  111. package/skills/uipath-review/references/agents/agents-coded-rules.md +24 -7
  112. package/skills/uipath-review/references/agents/agents-lowcode-rules.md +0 -1
  113. package/skills/uipath-review/references/agents/guardrails/coded-guardrails-review.md +231 -0
  114. package/skills/uipath-review/references/rule-catalog-workflow.md +4 -2
  115. package/skills/uipath-rpa/SKILL.md +2 -2
  116. package/skills/uipath-rpa/references/activity-docs/UiPath.DataService.Activities/guides/data-service-filter-builder-guide.md +1 -1
  117. package/skills/uipath-rpa/references/activity-docs/UiPath.Web.Activities/2.5/coded/coded-api.md +1 -1
  118. package/skills/uipath-rpa/references/activity-docs/UiPath.Web.Activities/2.5/coded/curl-import.md +3 -3
  119. package/skills/uipath-rpa/references/activity-docs/UiPath.Web.Activities/2.5/coded/http-request-upgrade.md +3 -3
  120. package/skills/uipath-rpa/references/activity-docs/UiPath.Web.Activities/2.5/coded/service-discovery.md +2 -2
  121. package/skills/uipath-rpa/references/coded/coding-guidelines.md +1 -1
  122. package/skills/uipath-rpa/references/ui-automation-guide.md +7 -7
  123. package/skills/uipath-rpa/references/uia-configure-target-workflows.md +5 -5
  124. package/skills/uipath-rpa/references/uia-elements-interaction-guide.md +19 -10
  125. package/skills/uipath-rpa/references/uia-prerequisites.md +7 -7
  126. package/skills/uipath-rpa/references/validation-guide.md +2 -2
  127. package/skills/uipath-rpa/references/xaml/common-pitfalls.md +4 -0
  128. package/skills/uipath-rpa/references/xaml/csharp-activity-binding-guide.md +3 -1
  129. package/skills/uipath-rpa/references/xaml/csharp-expression-pitfalls.md +9 -4
  130. package/skills/uipath-rpa/references/xaml/workflow-guide.md +2 -2
  131. package/skills/uipath-rpa/references/xaml/xaml-basics-and-rules.md +1 -1
  132. package/skills/uipath-solution/SKILL.md +4 -4
  133. package/skills/uipath-solution/references/activate-and-manage.md +6 -1
  134. package/skills/uipath-solution/references/develop-solution.md +24 -5
  135. package/skills/uipath-solution/references/pack-and-deploy.md +5 -2
  136. package/skills/uipath-solution/references/scenarios/manual-edits.md +2 -2
  137. package/skills/uipath-solution/references/solution-overview.md +2 -2
  138. package/skills/uipath-troubleshoot/SKILL.md +3 -3
  139. package/skills/uipath-troubleshoot/references/products/agents/playbooks/context-grounding-index-not-found.md +0 -2
  140. package/skills/uipath-troubleshoot/references/products/maestro/playbooks/personal-automation-quota.md +1 -1
  141. package/version-manifest.json +3 -3
  142. package/hooks/ensure-uip.sh +0 -220
  143. package/skills/uipath-maestro-flow/references/author/references/plugins/connector/data-fabric/impl.md +0 -683
  144. package/skills/uipath-maestro-flow/references/author/references/plugins/connector/data-fabric/planning.md +0 -45
@@ -1,18 +1,25 @@
1
1
  #!/bin/bash
2
- # PostToolUse telemetry hook for the UiPath skills plugin.
2
+ # Telemetry hook for the UiPath skills plugin (Claude Code).
3
3
  #
4
- # Reads the hook JSON payload from stdin, decides whether the tool call is
5
- # attributable to THIS plugin (skill gate), resolves the UiPath environment
6
- # (alpha / staging / prod), and pipes one flat JSON object to `uip track`,
7
- # which forwards it through the CLI's own telemetry tracker as a single
8
- # uip.skills.tool-use Application Insights event. Calls from other plugins or
9
- # bare Claude Code are dropped.
4
+ # Registered on multiple Claude Code hook events (PostToolUse, SessionStart,
5
+ # SessionEnd, Stop, StopFailure). Reads the hook JSON payload from stdin, maps
6
+ # the event to a canonical eventName, and pipes one flat JSON object to
7
+ # `uip track`, which forwards it through the CLI's own telemetry tracker as a
8
+ # single uip.skills.<event> Application Insights event.
9
+ #
10
+ # tool-use is per-call and gated on plugin attribution (skill gate) — calls from
11
+ # other plugins or bare Claude Code are dropped. Lifecycle events (session-start,
12
+ # session-end, completion) are session-scoped and fire for every session where
13
+ # this plugin is installed.
10
14
  #
11
15
  # The CLI (see UiPath/cli#2600) owns transport, the App Insights connection,
12
- # the event name, the authenticated cloud identity, and the `source:
13
- # "skills-plugin"` dimension. This hook only derives + sanitizes fields and
14
- # gates on the opt-out flag; value sanitization stays the hook's responsibility
15
- # because the CLI and skills ship co-versioned.
16
+ # the event name, the authenticated cloud identity, the `source:
17
+ # "skills-plugin"` dimension, and since UiPath/cli#2806 the
18
+ # environment/base_url/region base dimensions stamped fresh on every event
19
+ # from its own auth context (so this hook sends no environment info). This
20
+ # hook only derives + sanitizes fields and gates on the opt-out flag; value
21
+ # sanitization stays the hook's responsibility because the CLI and skills
22
+ # ship co-versioned.
16
23
  #
17
24
  # REGION-SCOPED EXTRACTION (see extract_fields): the payload embeds free-form
18
25
  # customer content (prompts, command lines, stdout/stderr, file contents). A
@@ -20,8 +27,11 @@
20
27
  # contains JSON-shaped text (`"success":false`, `uip solution publish`,
21
28
  # `.flow"`, `"resolvedModel":"..."`). So a single string-aware awk pass walks
22
29
  # the JSON once and pulls each field ONLY from the region it lives in:
23
- # ENVELOPE (top-level) -> toolName, toolUseId, sessionId, permissionMode,
24
- # durationMs, effortLevel (effort.level), agentType
30
+ # ENVELOPE (top-level) -> toolName, toolUseId, session_id, permissionMode,
31
+ # durationMs, effortLevel (effort.level), agentType,
32
+ # source (-> session_source), reason (session-end),
33
+ # model (-> agent_model; Claude sends it on
34
+ # SessionStart, Codex on every event)
25
35
  # tool_input -> skillName, uipSubcommand (command), fileExtension
26
36
  # (file_path), subagentType (subagent_type, or
27
37
  # agent_type for a Codex spawn_agent call)
@@ -39,11 +49,19 @@
39
49
  # interrupted / resolvedModel are absent and outcome is ok|unknown only.
40
50
  # Only derived, low-cardinality, PII-free values ever leave the machine.
41
51
  #
52
+ # TWIN SCRIPT: hooks/send-telemetry.ps1 is the PowerShell twin of this file —
53
+ # any behavioral change here MUST be mirrored there in the same PR (see
54
+ # CLAUDE.md). hooks.json runs whichever twin matches the executing shell via a
55
+ # bash/PowerShell polyglot command.
56
+ #
42
57
  # Non-blocking by contract: registered as an async hook in hooks.json
43
- # ("async": true), so Claude Code runs it in the background and never waits for
44
- # it. Always exits 0, swallows every error, and pipes to `uip track` in a
45
- # detached subshell. Cross-platform (macOS, Linux, Windows via Git Bash /
46
- # MSYS). Pure bash + grep/sed/awk no jq, node, or python.
58
+ # ("async": true) on every event EXCEPT SessionEnd, so Claude Code runs it in
59
+ # the background and never waits for it. SessionEnd is registered
60
+ # SYNCHRONOUSLY (30s timeout): async hooks still running at session teardown
61
+ # are killed after a short grace window, which would silently drop the
62
+ # session-end event. Always exits 0, swallows every error, and pipes to
63
+ # `uip track` in a detached subshell. Cross-platform (macOS, Linux, Windows
64
+ # via Git Bash / MSYS). Pure bash + grep/sed/awk — no jq, node, or python.
47
65
  #
48
66
  # Structure: pure helpers + side-effecting procedures (below), driven by main()
49
67
  # (bottom). Configuration is env only:
@@ -55,8 +73,12 @@
55
73
  set +e
56
74
 
57
75
  # schemaVersion of the emitted event. Bump on ANY change to the key set so App
58
- # Insights can segment events emitted with older/churned schemas.
59
- SCHEMA_VERSION=1
76
+ # Insights can segment events emitted with older/churned schemas. v2: adds the
77
+ # eventName / session_source / reason / agent_model keys, renames
78
+ # sessionId -> session_id (canonical casing, matches the CLI command stream,
79
+ # UiPath/cli#2800), and drops environment/baseUrl (the CLI stamps fresh
80
+ # environment/base_url/region base dimensions itself, UiPath/cli#2806).
81
+ SCHEMA_VERSION=2
60
82
 
61
83
  # --- extraction ------------------------------------------------------------
62
84
 
@@ -73,7 +95,7 @@ extract_fields() {
73
95
  if (d == 1)
74
96
  return (k=="tool_name"||k=="tool_use_id"||k=="session_id"|| \
75
97
  k=="permission_mode"||k=="duration_ms"||k=="agent_type"|| \
76
- k=="hook_event_name")
98
+ k=="hook_event_name"||k=="source"||k=="reason"||k=="model")
77
99
  if (d == 2 && c == "input")
78
100
  return (k=="skill"||k=="command"||k=="file_path"||k=="subagent_type"|| \
79
101
  k=="agent_type")
@@ -173,7 +195,8 @@ read_fields() {
173
195
  event=""; tool=""; tool_use_id=""; session_id=""; permission_mode=""
174
196
  duration_ms=""; agent_type=""; skill=""; command=""; file_path=""
175
197
  subagent_type=""; interrupted=""; success=""; resolved_model=""
176
- effort_level=""; response_seen=""
198
+ effort_level=""; response_seen=""; session_source=""; reason=""
199
+ agent_model=""
177
200
  local k v
178
201
  while IFS="$(printf '\t')" read -r k v; do
179
202
  case "$k" in
@@ -184,6 +207,9 @@ read_fields() {
184
207
  permission_mode) permission_mode="$v" ;;
185
208
  duration_ms) duration_ms="$v" ;;
186
209
  agent_type) agent_type="$v" ;;
210
+ source) session_source="$v" ;;
211
+ reason) reason="$v" ;;
212
+ model) agent_model="$v" ;;
187
213
  skill) skill="$v" ;;
188
214
  command) command="$v" ;;
189
215
  file_path) file_path="$v" ;;
@@ -233,54 +259,6 @@ is_uipath_call() {
233
259
  return 1
234
260
  }
235
261
 
236
- # --- environment resolution ------------------------------------------------
237
-
238
- # cache_val <file> <key>: emit a cached value stripped to a safe charset. Parses
239
- # the cache as DATA — never `source` it, so a tampered cache can't execute
240
- # arbitrary shell in this hook's context.
241
- cache_val() {
242
- grep -E "^$2=" "$1" 2>/dev/null | head -1 | cut -d= -f2- | tr -cd 'A-Za-z0-9:._/-'
243
- }
244
-
245
- # resolve_environment: set env_name + base_url from `uip login status` (~0.5s),
246
- # cached per-user for 1h so only one tool call per hour pays the cost. The cache
247
- # dir is per-user, owner-only (NOT world-writable /tmp), so another local user
248
- # can't pre-create the file. chmod is a no-op on Windows but harmless.
249
- resolve_environment() {
250
- local cache_dir cache ttl now _ts status_json
251
- cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/uipath-telemetry"
252
- mkdir -p "$cache_dir" 2>/dev/null && chmod 700 "$cache_dir" 2>/dev/null
253
- cache="$cache_dir/env.cache"
254
- ttl=3600
255
- now="$(date +%s 2>/dev/null || echo 0)"
256
-
257
- env_name="unknown"; base_url=""; _ts=0
258
- if [ -f "$cache" ]; then
259
- _ts="$(cache_val "$cache" _ts)"
260
- env_name="$(cache_val "$cache" env_name)"
261
- base_url="$(cache_val "$cache" base_url)"
262
- case "$_ts" in *[!0-9]*|"") _ts=0 ;; esac # non-numeric -> treat as stale
263
- fi
264
-
265
- [ "$(( now - _ts ))" -ge "$ttl" ] || return 0
266
-
267
- status_json="$(uip login status --output json 2>/dev/null)"
268
- base_url="$(printf '%s' "$status_json" \
269
- | grep -oE '"BaseUrl"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')"
270
- case "$base_url" in
271
- *alpha.uipath.com*) env_name="alpha" ;;
272
- *staging.uipath.com*) env_name="staging" ;;
273
- *cloud.uipath.com*) env_name="prod" ;;
274
- "") env_name="unknown" ;;
275
- *) env_name="other" ;;
276
- esac
277
- {
278
- echo "_ts=$now"
279
- echo "env_name=$env_name"
280
- echo "base_url=$base_url"
281
- } > "$cache" 2>/dev/null
282
- }
283
-
284
262
  # --- field derivation ------------------------------------------------------
285
263
 
286
264
  # derive_fields: set skill_name, uip_subcommand, file_ext from the parsed
@@ -321,6 +299,36 @@ compute_outcome() {
321
299
  fi
322
300
  }
323
301
 
302
+ # map_event_name: translate the agent hook event into the canonical eventName
303
+ # token the CLI's `uip track` maps to a uip.skills.<event> event. An
304
+ # unrecognized event prints empty so main() drops it. Stop and StopFailure both
305
+ # map to `completion`, distinguished by outcome (see lifecycle_outcome).
306
+ # CROSS-AGENT: Codex fires SessionStart and Stop under these SAME names with a
307
+ # matching envelope (session_id/source/model; docs: developers.openai.com/
308
+ # codex/hooks), so both map here unchanged. Codex has NO SessionEnd (completion
309
+ # is its terminal signal) and no StopFailure (its API-error turns are not
310
+ # distinguished). Gemini/Cursor use different hook names — separate follow-ups.
311
+ map_event_name() {
312
+ case "$event" in
313
+ PostToolUse) printf 'tool-use' ;;
314
+ SessionStart) printf 'session-start' ;;
315
+ SessionEnd) printf 'session-end' ;;
316
+ Stop|StopFailure) printf 'completion' ;;
317
+ *) printf '' ;;
318
+ esac
319
+ }
320
+
321
+ # lifecycle_outcome: outcome for the non-tool events. A normal turn end (Stop)
322
+ # is `ok`; an API-error turn end (StopFailure) is `failure`. session-start and
323
+ # session-end carry no turn outcome (session-end's `reason` conveys the why).
324
+ lifecycle_outcome() {
325
+ case "$event" in
326
+ Stop) printf 'ok' ;;
327
+ StopFailure) printf 'failure' ;;
328
+ *) printf '' ;;
329
+ esac
330
+ }
331
+
324
332
  # model_family <resolvedModel>: print the low-cardinality family and drop the
325
333
  # context-window marker (e.g. claude-opus-4-8[1m] -> opus). Empty when absent
326
334
  # (plain main-loop call); `other` for an unrecognized family.
@@ -357,21 +365,23 @@ san() { printf '%s' "$1" | tr -c 'A-Za-z0-9:._/ -' '_' | cut -c1-120; }
357
365
  build_event_json() {
358
366
  local spec json sep fkey ftyp fval
359
367
  spec="schemaVersion|n|$SCHEMA_VERSION
368
+ eventName|s|$event_name
360
369
  toolName|s|$tool
361
370
  skillName|s|$skill_name
362
371
  uipSubcommand|s|$uip_subcommand
363
372
  fileExtension|s|$file_ext
364
- environment|s|$env_name
365
- baseUrl|s|$base_url
366
373
  outcome|s|$outcome
367
374
  permissionMode|s|$permission_mode
368
375
  effortLevel|s|$effort_level
369
376
  skillsVersion|s|$skills_ver
370
377
  toolUseId|s|$tool_use_id
371
- sessionId|s|$session_id
378
+ session_id|s|$session_id
372
379
  subagentModel|s|$subagent_model
373
380
  subagentType|s|$subagent_type
374
381
  agentType|s|$agent_type
382
+ agent_model|s|$agent_model
383
+ session_source|s|$session_source
384
+ reason|s|$reason
375
385
  durationMs|n|$dur_json"
376
386
  json="{"; sep=""
377
387
  while IFS='|' read -r fkey ftyp fval; do
@@ -397,27 +407,46 @@ main() {
397
407
  payload="$(cat)"
398
408
  read_fields "$(printf '%s' "$payload" | extract_fields)"
399
409
 
400
- [ "$event" = "PostToolUse" ] || exit 0
401
- is_uipath_call || exit 0
410
+ # Map the hook event to a canonical eventName; drop unrecognized events.
411
+ event_name="$(map_event_name)"
412
+ [ -n "$event_name" ] || exit 0
402
413
 
403
- resolve_environment
404
- derive_fields
414
+ # Derived only on tool-use; keep defined so the fixed key set always assembles.
415
+ skill_name=""; uip_subcommand=""; file_ext=""; subagent_model=""
416
+
417
+ if [ "$event_name" = "tool-use" ]; then
418
+ # tool-use is per-call: gate on plugin attribution, then derive tool fields.
419
+ is_uipath_call || exit 0
420
+ derive_fields
421
+ outcome="$(compute_outcome)"
422
+ subagent_model="$(model_family "$resolved_model")"
423
+ else
424
+ # Lifecycle events are session-scoped — they fire for every session where
425
+ # this plugin is installed (the activation-rate denominator), so they skip
426
+ # the per-call attribution gate and tool-field derivation.
427
+ outcome="$(lifecycle_outcome)"
428
+ fi
429
+
430
+ # Enforce the per-event field scoping the contract documents: session_source
431
+ # only on session-start, reason only on session-end. The awk pass extracts
432
+ # `source`/`reason` from ANY event's envelope, so a future payload that adds
433
+ # either key to another event must not bleed into these dimensions.
434
+ [ "$event_name" = "session-start" ] || session_source=""
435
+ [ "$event_name" = "session-end" ] || reason=""
436
+
437
+ skills_ver="$(read_skills_version)"
405
438
 
406
- outcome="$(compute_outcome)"
407
439
  # durationMs is a JSON number. Emit JSON null (not 0) when absent, so a missing
408
440
  # value doesn't skew latency aggregations. The CLI drops a null-valued
409
441
  # property, so a missing duration records as "no data". Stays unquoted.
410
442
  case "$duration_ms" in ''|*[!0-9]*) dur_json="null" ;; *) dur_json="$duration_ms" ;; esac
411
- subagent_model="$(model_family "$resolved_model")"
412
- skills_ver="$(read_skills_version)"
413
443
 
414
444
  # Sanitize every string field before assembly.
445
+ event_name="$(san "$event_name")"
415
446
  tool="$(san "$tool")"
416
447
  skill_name="$(san "$skill_name")"
417
448
  uip_subcommand="$(san "$uip_subcommand")"
418
449
  file_ext="$(san "$file_ext")"
419
- env_name="$(san "$env_name")"
420
- base_url="$(san "$base_url")"
421
450
  outcome="$(san "$outcome")"
422
451
  permission_mode="$(san "$permission_mode")"
423
452
  effort_level="$(san "$effort_level")"
@@ -427,12 +456,15 @@ main() {
427
456
  subagent_model="$(san "$subagent_model")"
428
457
  subagent_type="$(san "$subagent_type")"
429
458
  agent_type="$(san "$agent_type")"
459
+ agent_model="$(san "$agent_model")"
460
+ session_source="$(san "$session_source")"
461
+ reason="$(san "$reason")"
430
462
 
431
- # Hand off to the CLI telemetry tracker. The CLI hard-codes the event name
432
- # (uip.skills.tool-use), stamps source: "skills-plugin", attaches the
433
- # authenticated cloud identity + CLI app version, and owns transport + flush;
434
- # it drops any non-scalar value (so a null durationMs disappears). Send no
435
- # `event` key, no envelope, and no `source` (the CLI overrides it).
463
+ # Hand off to the CLI telemetry tracker. The CLI maps our eventName token to
464
+ # the uip.skills.<event> name, stamps source: "skills-plugin", attaches the
465
+ # authenticated cloud identity + CLI app version, owns transport + flush,
466
+ # redacts PII, and drops any non-scalar value (so a null durationMs
467
+ # disappears). Send no envelope and no `source` (the CLI overrides it).
436
468
  #
437
469
  # Detached subshell ( cmd & ) survives this hook's exit so the agent never
438
470
  # waits. `uip track` is never-fail (exits 0, emits nothing when telemetry is
@@ -0,0 +1,72 @@
1
+ # SessionStart step: export the agent's session id to the uip CLI.
2
+ #
3
+ # TWIN SCRIPT: hooks/set-session-env.sh is the bash twin of this file — any
4
+ # behavioral change here MUST be mirrored there in the same PR (see CLAUDE.md).
5
+ #
6
+ # Reads the SessionStart payload on stdin, takes its top-level `session_id`,
7
+ # and appends `export UIPATH_SESSION_ID='<id>'` to $env:CLAUDE_ENV_FILE so
8
+ # every subsequent shell tool subprocess — and therefore every `uip` command
9
+ # the agent runs — inherits it. The CLI stamps that value as the `session_id`
10
+ # dimension on native command telemetry (UiPath/cli#2800), which joins the
11
+ # command stream with the skills events emitted by send-telemetry.ps1: both
12
+ # streams then carry the same session id.
13
+ #
14
+ # Registered SYNCHRONOUSLY in hooks.json (no "async": true): the write must
15
+ # complete before the session's first shell call, or early `uip` commands
16
+ # would miss the id. Costs a few ms (regex only, no network, no uip call).
17
+ #
18
+ # Deliberately NOT gated on UIPATH_TELEMETRY_DISABLED: writing a variable
19
+ # transmits nothing — whether any event carrying it is ever sent stays
20
+ # governed by the CLI's own telemetry gate.
21
+ #
22
+ # Safety:
23
+ # - host wins: no-op when UIPATH_SESSION_ID is already set in the env;
24
+ # - idempotent: no-op when the env file already exports it;
25
+ # - injection-safe: $env:CLAUDE_ENV_FILE is sourced by the agent, so the
26
+ # value is stripped to [A-Za-z0-9._-] and length-capped before being
27
+ # written inside single quotes (agent session ids are UUIDs, so a
28
+ # legitimate value is never altered);
29
+ # - never-fail: always exits 0, never blocks the session.
30
+ #
31
+ # Runs under Windows PowerShell 5.1 and PowerShell 7+ (pwsh).
32
+
33
+ $ErrorActionPreference = 'SilentlyContinue'
34
+
35
+ function Main {
36
+ $envFile = $env:CLAUDE_ENV_FILE
37
+ if (-not $envFile) { exit 0 }
38
+ if ($env:UIPATH_SESSION_ID) { exit 0 }
39
+
40
+ $existing = ''
41
+ if (Test-Path -LiteralPath $envFile -PathType Leaf) {
42
+ try { $existing = [System.IO.File]::ReadAllText($envFile) } catch { $existing = '' }
43
+ if ($existing -cmatch '(?m)^export UIPATH_SESSION_ID=') { exit 0 }
44
+ }
45
+
46
+ # Top-level `session_id` from the SessionStart payload. The payload for this
47
+ # event is small and carries no tool output, and the value is hard-sanitized
48
+ # anyway, so a plain regex is sufficient here (no full JSON parse needed).
49
+ $payload = ''
50
+ try { $payload = [Console]::In.ReadToEnd() } catch { exit 0 }
51
+ $sid = ''
52
+ $m = [regex]::Match($payload, '"session_id"\s*:\s*"([^"]*)"')
53
+ if ($m.Success) { $sid = $m.Groups[1].Value }
54
+ $sid = $sid -replace '[^A-Za-z0-9._-]', ''
55
+ if ($sid.Length -gt 64) { $sid = $sid.Substring(0, 64) }
56
+ if (-not $sid) { exit 0 }
57
+
58
+ # If the file exists but doesn't end with a newline (another hook's partial
59
+ # write), appending directly would concatenate onto its last line and could
60
+ # break the sourced env file for the whole session — repair it first.
61
+ $prefix = ''
62
+ if ($existing -and -not $existing.EndsWith("`n")) { $prefix = "`n" }
63
+
64
+ try {
65
+ [System.IO.File]::AppendAllText($envFile, "${prefix}export UIPATH_SESSION_ID='$sid'`n")
66
+ }
67
+ catch { }
68
+
69
+ exit 0
70
+ }
71
+
72
+ Main
@@ -0,0 +1,64 @@
1
+ #!/bin/bash
2
+ # SessionStart step: export the agent's session id to the uip CLI.
3
+ #
4
+ # TWIN SCRIPT: hooks/set-session-env.ps1 is the PowerShell twin of this file —
5
+ # any behavioral change here MUST be mirrored there in the same PR (see
6
+ # CLAUDE.md).
7
+ #
8
+ # Reads the SessionStart payload on stdin, takes its top-level `session_id`,
9
+ # and appends `export UIPATH_SESSION_ID='<id>'` to $CLAUDE_ENV_FILE so every
10
+ # subsequent Bash tool subprocess — and therefore every `uip` command the
11
+ # agent runs — inherits it. The CLI stamps that value as the `session_id`
12
+ # dimension on native command telemetry (UiPath/cli#2800), which joins the
13
+ # command stream with the skills events emitted by send-telemetry.sh: both
14
+ # streams then carry the same session id.
15
+ #
16
+ # Registered SYNCHRONOUSLY in hooks.json (no "async": true): the write must
17
+ # complete before the session's first Bash call, or early `uip` commands would
18
+ # miss the id. Costs a few ms (grep/sed/tr only, no network, no uip call).
19
+ #
20
+ # Deliberately NOT gated on UIPATH_TELEMETRY_DISABLED: writing a variable
21
+ # transmits nothing — whether any event carrying it is ever sent stays
22
+ # governed by the CLI's own telemetry gate.
23
+ #
24
+ # Safety:
25
+ # - host wins: no-op when UIPATH_SESSION_ID is already set in the env;
26
+ # - idempotent: no-op when the env file already exports it;
27
+ # - injection-safe: $CLAUDE_ENV_FILE is sourced by the agent, so the value
28
+ # is stripped to [A-Za-z0-9._-] and length-capped before being written
29
+ # inside single quotes (agent session ids are UUIDs, so a legitimate
30
+ # value is never altered);
31
+ # - never-fail: always exits 0, never blocks the session.
32
+
33
+ set +e
34
+
35
+ main() {
36
+ [ -n "$CLAUDE_ENV_FILE" ] || exit 0
37
+ [ -z "$UIPATH_SESSION_ID" ] || exit 0
38
+ if [ -f "$CLAUDE_ENV_FILE" ] \
39
+ && grep -q '^export UIPATH_SESSION_ID=' "$CLAUDE_ENV_FILE" 2>/dev/null; then
40
+ exit 0
41
+ fi
42
+
43
+ # Top-level `session_id` from the SessionStart payload. The payload for this
44
+ # event is small and carries no tool output, and the value is hard-sanitized
45
+ # anyway, so a plain grep is sufficient here (no region-scoped pass needed).
46
+ sid="$(grep -oE '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' \
47
+ | head -1 | sed 's/.*"\([^"]*\)"$/\1/' | tr -cd 'A-Za-z0-9._-' | cut -c1-64)"
48
+ [ -n "$sid" ] || exit 0
49
+
50
+ # If the file exists but doesn't end with a newline (another hook's partial
51
+ # write), appending directly would concatenate onto its last line and could
52
+ # break the sourced env file for the whole session — repair it first.
53
+ # `tail -c 1` in a $() strips a trailing newline, so "" means the file is
54
+ # newline-terminated.
55
+ if [ -s "$CLAUDE_ENV_FILE" ] && [ -n "$(tail -c 1 "$CLAUDE_ENV_FILE" 2>/dev/null)" ]; then
56
+ printf '\n' >> "$CLAUDE_ENV_FILE" 2>/dev/null
57
+ fi
58
+
59
+ printf "export UIPATH_SESSION_ID='%s'\n" "$sid" >> "$CLAUDE_ENV_FILE" 2>/dev/null
60
+
61
+ exit 0
62
+ }
63
+
64
+ main
@@ -0,0 +1,45 @@
1
+ # Detects whether Claude Code has an allowlist for `uip` subcommands.
2
+ # If none is found, prints a one-line nudge pointing at /uipath:install-permissions.
3
+ # Non-blocking — never fails the session, even if detection fails.
4
+ # Runs under Windows PowerShell 5.1 and PowerShell 7+ (pwsh).
5
+ #
6
+ # TWIN SCRIPT: hooks/suggest-permissions.sh is the bash twin of this file —
7
+ # any behavioral change here MUST be mirrored there in the same PR (see
8
+ # CLAUDE.md).
9
+
10
+ $ErrorActionPreference = 'SilentlyContinue'
11
+
12
+ # Only run inside a Claude Code plugin context.
13
+ if (-not $env:CLAUDE_PLUGIN_ROOT) { exit 0 }
14
+
15
+ # Codex exposes Claude-compatible plugin environment variables for hook
16
+ # compatibility. This nudge is Claude-specific, so keep Codex sessions silent.
17
+ if ($env:PLUGIN_ROOT) { exit 0 }
18
+
19
+ # Candidate settings files, most-to-least specific.
20
+ $candidates = @()
21
+ if ($env:CLAUDE_PROJECT_DIR) {
22
+ $candidates += Join-Path $env:CLAUDE_PROJECT_DIR '.claude/settings.local.json'
23
+ $candidates += Join-Path $env:CLAUDE_PROJECT_DIR '.claude/settings.json'
24
+ }
25
+ $cwd = (Get-Location).Path
26
+ $candidates += Join-Path $cwd '.claude/settings.local.json'
27
+ $candidates += Join-Path $cwd '.claude/settings.json'
28
+ $candidates += Join-Path $HOME '.claude/settings.json'
29
+
30
+ # If any candidate already mentions Bash(uip...) in its permissions, stay silent.
31
+ # Intentional simplification: this matches `allow`, `ask`, AND `deny` blocks.
32
+ # Any explicit `uip` rule means the user has made a decision about this CLI —
33
+ # we don't second-guess by nudging them toward a permissive allowlist.
34
+ foreach ($f in $candidates) {
35
+ if (-not (Test-Path -LiteralPath $f -PathType Leaf)) { continue }
36
+ try {
37
+ if (Select-String -LiteralPath $f -Pattern 'Bash(uip' -SimpleMatch -Quiet) { exit 0 }
38
+ }
39
+ catch { }
40
+ }
41
+
42
+ # No allowlist detected — print a one-line nudge to stderr (the Claude Code
43
+ # SessionStart convention for status messages).
44
+ [Console]::Error.WriteLine('uipath: To skip 25+ approval prompts per uip build, run: /uipath:install-permissions')
45
+ exit 0
@@ -3,6 +3,10 @@
3
3
  # If none is found, prints a one-line nudge pointing at /uipath:install-permissions.
4
4
  # Non-blocking — never fails the session, even if detection fails.
5
5
  # Cross-platform (macOS, Linux, Windows via Git Bash / MSYS / Cygwin).
6
+ #
7
+ # TWIN SCRIPT: hooks/suggest-permissions.ps1 is the PowerShell twin of this
8
+ # file — any behavioral change here MUST be mirrored there in the same PR (see
9
+ # CLAUDE.md).
6
10
 
7
11
  # Only run inside a Claude Code plugin context.
8
12
  if [ -z "${CLAUDE_PLUGIN_ROOT:-}" ]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/skills",
3
- "version": "1.197.2",
3
+ "version": "1.198.0",
4
4
  "description": "UiPath agent skills for Claude Code, Codex, Cursor, Copilot, Gemini and OpenCode — RPA, UI automation, UI testing, coded agents/apps/workflows, and troubleshooting. Distributed as the UiPath Claude Code plugin.",
5
5
  "author": {
6
6
  "name": "UiPath"
@@ -200,8 +200,8 @@ uip admin audit tenant export \
200
200
  **Implementation notes (worth knowing for diagnostic conversations):**
201
201
 
202
202
  - Both formats share the same fetch: the CLI issues **one HTTP call per UTC day** inside `[from, to]` and aggregates the per-day responses. Mirrors the `audit-dowload-from-longterm-store.sh` pattern in the AuditService repo.
203
- - **JSON (default):** a uniquely-named `audit_<from>_<to>_<generated-at>` **folder** is created under `--output-path`, holding one file per UTC day named `<YYYY-MM-DD>.json` (nested-ZIP entries from the server are flattened to `<inner>_<outer>.json`; same-name collisions get an iso-day suffix). The server names the per-day payloads `.txt`; the CLI writes them with a `.json` extension since each is a JSON array of events with PascalCase keys (`Id`, `CreatedOn`, `EventType`, …). Entry names are validated as safe basenames and confirmed to resolve inside the folder before any write (no path traversal / Zip-Slip).
204
- - **CSV:** the same per-day JSON arrays are parsed and merged into **one** RFC 4180 CSV (CRLF line endings, header row first). Columns follow the long-term-store field order — `Id, CreatedOn, OrganizationId, TenantId, ActorId, ActorName, ActorEmail, ActorDetails, EventType, EventSource, EventTarget, EventDetails, Status, ClientInfo` — with any extra server fields appended (union across events) so no data is dropped. `Status` is the numeric enum (`0`=Success, `1`=Failure); nested objects (e.g. `ClientInfo`) are JSON-stringified into the cell. String cells beginning with `= + - @` (or TAB/CR) are prefixed with a single quote to neutralize spreadsheet formula injection.
203
+ - **JSON (default):** a uniquely-named `audit_<from>_<to>_<generated-at>` **folder** is created under `--output-path`, holding one file per UTC day named `<YYYY-MM-DD>.json` (nested-ZIP entries from the server are flattened to `<inner>_<outer>.json`; same-name collisions get an iso-day suffix). The server names the per-day payloads `.txt`; the CLI writes them with a `.json` extension since each is a JSON array of events with LTS-schema keys (`Identifier`, `DateCreatedUtc`, `Action`, …). Entry names are validated as safe basenames and confirmed to resolve inside the folder before any write (no path traversal / Zip-Slip).
204
+ - **CSV:** the same per-day JSON arrays are parsed and merged into **one** RFC 4180 CSV (CRLF line endings, header row first). Columns follow the long-term-store field order — `OrganizationId, TenantId, ActorId, ActorEmail, ActorDetails, EventDetails, Status, Identifier, DateCreatedUtc, User, Action, Source, Category, ClientInformation` — with any extra server fields appended (union across events) so no data is dropped. `Status` is the numeric enum (`0`=Success, `1`=Failure); nested objects (e.g. `ClientInformation`) are JSON-stringified into the cell. String cells beginning with `= + - @` (or TAB/CR) are prefixed with a single quote to neutralize spreadsheet formula injection.
205
205
  - On any single-day HTTP failure (or, for CSV, a day whose payload is not valid JSON), **nothing is written** — for `json` the output folder isn't even created — and the error message identifies which day failed. Earlier successful chunks are not preserved (atomic export).
206
206
  - `Days` reports the total number of UTC days requested; `NonEmptyDays` reports how many actually had data. A long export with `NonEmptyDays: 0` means the window was entirely idle, not that the export failed. For `json`, `Files` counts the day-wise files written; for `csv`, `Events: 0` yields a header-only file.
207
207
 
@@ -226,17 +226,17 @@ audit-exports/
226
226
  └── 2026-01-31.json
227
227
  ```
228
228
 
229
- Each `.json` file is a JSON array of audit events with **PascalCase** keys (`Id`, `CreatedOn`, `OrganizationId`, `ActorId`, `ActorName`, `EventType`, …) — different from the camelCase shape returned by the live `events` endpoint. Note this in the user's hand-off if they're going to feed the dump into other tooling.
229
+ Each `.json` file is a JSON array of audit events with **LTS-schema** keys (`Identifier`, `DateCreatedUtc`, `OrganizationId`, `ActorId`, `User`, `Action`, …) — different from the camelCase shape returned by the live `events` endpoint. Note this in the user's hand-off if they're going to feed the dump into other tooling.
230
230
 
231
231
  **CSV** — find the generated file, then inspect the header and row count:
232
232
 
233
233
  ```bash
234
234
  csv=$(ls ./audit-exports/audit_*.csv | head -1) # the generated audit_<from>_<to>_<generatedAt>.csv
235
- head -1 "$csv" # shared header (PascalCase columns)
235
+ head -1 "$csv" # shared header (LTS-schema columns)
236
236
  python3 -c "import csv,sys; print(sum(1 for _ in csv.reader(open(sys.argv[1]))) - 1, 'rows')" "$csv"
237
237
  ```
238
238
 
239
- One header row, then every event across all days as a data row (same PascalCase column names as the JSON files' keys). The row count should match `Events` in the result envelope.
239
+ One header row, then every event across all days as a data row (same LTS-schema column names as the JSON files' keys). The row count should match `Events` in the result envelope.
240
240
 
241
241
  Edge cases the CLI handles automatically — surface in your hand-off only if they appear:
242
242
 
@@ -302,7 +302,7 @@ Two or more signals? Run them in sequence and stitch the results in the final re
302
302
  - **`tenant` events without an active tenant fail loudly.** If `uip login` has no tenant selected, every tenant-scoped command throws. Either re-`uip login` and pick a tenant, or pass `--tenant-id <guid>` on every call.
303
303
  - **`events` cursor pagination is chronologically reversed from intuition.** `next` = newer (often null), `previous` = older (the typical "load more"). The CLI tool follows `previous` automatically when you bump `--limit > 200` — don't re-implement this in the agent.
304
304
  - **Date-only ISO strings are interpreted as UTC midnight.** `--from-date 2026-01-01` means `2026-01-01T00:00:00Z`. To capture the full final day in `--to-date`, use `2026-02-01` (exclusive next day) or `2026-01-31T23:59:59.999Z`.
305
- - **Export format depends on `--file-format`.** The default `json` writes one **JSON** file per UTC day (named `<YYYY-MM-DD>.json`) into a generated subfolder under `--output-path`, with **PascalCase** keys; `--file-format csv` produces a single merged **CSV** whose header uses those same PascalCase field names. Both differ from the camelCase live `events` endpoint — don't paste an export into a parser expecting the live shape. In the CSV, `Status` is numeric (`0`/`1`) and `ClientInfo` is a JSON-stringified cell.
305
+ - **Export format depends on `--file-format`.** The default `json` writes one **JSON** file per UTC day (named `<YYYY-MM-DD>.json`) into a generated subfolder under `--output-path`, with **LTS-schema** keys; `--file-format csv` produces a single merged **CSV** whose header uses those same LTS-schema field names. Both differ from the camelCase live `events` endpoint — don't paste an export into a parser expecting the live shape. In the CSV, `Status` is numeric (`0`/`1`) and `ClientInformation` is a JSON-stringified cell.
306
306
  - **Org sources and tenant sources are different sets.** Don't reuse a GUID from `org sources` in a `tenant events` query — the filter will silently match nothing.
307
307
 
308
308
  ## Output Etiquette — after an audit query or export
@@ -11,7 +11,7 @@ Pick this when:
11
11
 
12
12
  Confirm BatchTransform is the right mode first — see [../../../context-grounding-patterns.md](../../../context-grounding-patterns.md).
13
13
 
14
- For Studio Web Agent Builder → [../../lowcode/capabilities/built-in-tools/batch-transform/planning.md](../../lowcode/capabilities/built-in-tools/batch-transform/planning.md).
14
+ For Studio Web Agent Builder → [../../../lowcode/capabilities/built-in-tools/batch-transform/planning.md](../../../lowcode/capabilities/built-in-tools/batch-transform/planning.md).
15
15
 
16
16
  ## Inputs You Need Before Building
17
17
 
@@ -11,7 +11,7 @@ Pick this when:
11
11
 
12
12
  Confirm DeepRAG is the right mode first — see [../../../context-grounding-patterns.md](../../../context-grounding-patterns.md).
13
13
 
14
- For Studio Web Agent Builder → [../../lowcode/capabilities/built-in-tools/deeprag/planning.md](../../lowcode/capabilities/built-in-tools/deeprag/planning.md).
14
+ For Studio Web Agent Builder → [../../../lowcode/capabilities/built-in-tools/deeprag/planning.md](../../../lowcode/capabilities/built-in-tools/deeprag/planning.md).
15
15
 
16
16
  ## Inputs You Need Before Building
17
17
 
@@ -191,6 +191,9 @@ Map catalog parameter shapes to Python:
191
191
  | `enum-list` (e.g. `entities`) | List of enum members (e.g. `[PIIDetectionEntityType.EMAIL, PIIDetectionEntityType.PHONE_NUMBER]`) — names taken from SDK docs |
192
192
  | `map-enum` (e.g. `entityThresholds`) | Dict from enum member → number (e.g. `{PIIDetectionEntityType.EMAIL: 0.5}`) — keys must exactly match the `enum-list` parameter's values |
193
193
  | `number` (e.g. `threshold`) | Plain `float` / `int` constructor argument |
194
+ | `text` (e.g. `guardrailText`) | Plain `str` constructor argument |
195
+ | `enum` (e.g. `model`) | `str` value from the allowed options list. When the catalog shows an empty options list (as with `llm_as_judge`'s `model`), ask the user which model ID to use — the available values depend on the LLM Gateway configuration in their tenant. |
196
+ | `text-list` (e.g. `positiveExamples`, `negativeExamples`) | `List[str]` constructor argument |
194
197
 
195
198
  Use `BlockAction(...)`, `LogAction(severity_level=...)`, or `EscalateAction(app_name=..., app_folder_path=..., recipient=...)` for human-in-the-loop review — or any other action the SDK docs expose. Never invent action class names. For `EscalateAction`, the fetched SDK docs must expose the class/parameters, and the Action App must be deployed and declared in `bindings.json` using [../../lifecycle/bindings-reference.md](../../lifecycle/bindings-reference.md) (see [guardrails.md § Escalation action (HITL)](guardrails.md#escalation-action-human-in-the-loop)).
196
199
 
@@ -204,7 +207,7 @@ Write the recommended guardrails into the Python file using the patterns from [g
204
207
  ```bash
205
208
  python3 -c "import ast; ast.parse(open('graph.py').read())"
206
209
  ```
207
- 2. **Runtime wiring (mandatory)** — the guardrails are actually attached. A guardrail whose symbols were imported from the wrong module parses fine but **silently never fires**. Run the adapter-registration and `_GuardedLLM` / `_GuardedTool` wrap checks from [guardrails.md § Verify Guardrails Are Actually Wired](guardrails.md#verify-guardrails-are-actually-wired-mandatory-after-writing). Do not report the guardrails as added until these pass.
210
+ 2. **Runtime wiring (mandatory)** — the guardrails are actually attached. A guardrail whose symbols were imported from the wrong module parses fine but **silently never fires**. Run the adapter-registration and `_GuardedLLM` / `_GuardedTool` wrap checks from [guardrails.md § Verify Guardrails Are Actually Wired](guardrails.md#verify-guardrails-are-actually-wired-mandatory-after-writing-for-langchain-ml-guardrails). Do not report the guardrails as added until these pass.
208
211
 
209
212
  (Replace `graph.py` with the actual entrypoint file from Step 1.)
210
213
 
@@ -279,7 +282,7 @@ python3 -c "import ast; ast.parse(open('graph.py').read())"
279
282
  5. **Never recommend two validators with the same `security_category` at the same scope and stage** (e.g. `prompt_injection` + `user_prompt_attacks` at LLM PRE). De-duplicate per Step 3: drop catalog-deprecated entries, keep the best fit, mention the alternative. Derive the grouping and deprecation from the catalog's own fields — do not hardcode validator names.
280
283
  6. **Default the action to the catalog example's `action_type`; never silently downgrade Block → Log.** Security-critical guardrails (`adversarial_input`, `content_safety`) default to `Block`. If you use `LogAction` for a guardrail whose catalog default is `Block`, state it and the reason in the report (Step 6).
281
284
  7. **Block as early as possible — pick the outermost scope the validator allows.** For input protection (PII, jailbreak, injection) prefer `GuardrailScope.AGENT` · PRE over Llm over Tool, so the run halts before the LLM call. PII meant to stop the agent handling personal data goes at **Agent**, not Llm. Only narrow when the validator is scope-restricted (e.g. `prompt_injection` / `user_prompt_attacks` are Llm-only) or the user asks for a narrower scope. See Step 5.
282
- 8. **For LangChain / LangGraph agents, import guardrail symbols from `uipath_langchain.guardrails`, not `uipath.platform.guardrails`.** Only `uipath_langchain.guardrails` registers the LangChain adapter as an import side effect; the platform module exposes identical names but registers nothing, so guardrails silently no-op. For any other framework (LlamaIndex, OpenAI Agents, plain Python), no UiPath framework adapter is published yet — use `uipath.platform.guardrails` (the framework-agnostic SDK) directly. After writing for LangChain, verify runtime wiring (adapter registered + `_GuardedLLM`/`_GuardedTool` wrap), not just `ast.parse`. See [guardrails.md § Imports Pattern](guardrails.md#imports-pattern) and [§ Verify Guardrails Are Actually Wired](guardrails.md#verify-guardrails-are-actually-wired-mandatory-after-writing).
285
+ 8. **For LangChain / LangGraph agents, import guardrail symbols from `uipath_langchain.guardrails`, not `uipath.platform.guardrails`.** Only `uipath_langchain.guardrails` registers the LangChain adapter as an import side effect; the platform module exposes identical names but registers nothing, so guardrails silently no-op. For any other framework (LlamaIndex, OpenAI Agents, plain Python), no UiPath framework adapter is published yet — use `uipath.platform.guardrails` (the framework-agnostic SDK) directly. After writing for LangChain, verify runtime wiring (adapter registered + `_GuardedLLM`/`_GuardedTool` wrap), not just `ast.parse`. See [guardrails.md § Imports Pattern](guardrails.md#imports-pattern) and [§ Verify Guardrails Are Actually Wired](guardrails.md#verify-guardrails-are-actually-wired-mandatory-after-writing-for-langchain-ml-guardrails).
283
286
  9. **For Tool scope**: verify the tool exists as a `@tool` function in the agent code before adding the guardrail. If the agent has no tools, do not add a Tool-scoped guardrail.
284
287
  10. **For LLM-scope decorator**: the LLM must be inside a named factory function. If it is assigned directly (`llm = UiPathChat(...)`), refactor into a factory first — never decorate a module-level assignment.
285
288
  11. **For Agent-scope decorator**: `create_agent(...)` must be inside a named factory function. If it is called at module level, refactor into a factory first.