@uipath/skills 1.201.0-preview.573 → 1.201.0-preview.591
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CODEOWNERS +4 -0
- package/package.json +1 -1
- package/skills/uipath-maestro-flow/references/author/CAPABILITY.md +3 -0
- package/skills/uipath-maestro-flow/references/author/references/brownfield.md +1 -0
- package/skills/uipath-maestro-flow/references/author/references/planning-arch.md +8 -0
- package/skills/uipath-maestro-flow/references/author/references/planning-impl.md +4 -0
- package/skills/uipath-maestro-flow/references/author/references/plugins/inline-voice-agent/impl.md +269 -0
- package/skills/uipath-maestro-flow/references/author/references/plugins/inline-voice-agent/planning.md +128 -0
- package/skills/uipath-maestro-flow/references/shared/node-output-wiring.md +1 -0
- package/version-manifest.json +1 -1
package/CODEOWNERS
CHANGED
|
@@ -141,6 +141,10 @@
|
|
|
141
141
|
/skills/uipath-maestro-flow/references/author/references/plugins/ixp/ @jcalero @constantinmuraru @scallaway-uipath @tommilligan @joe-prosser @vlad-crisan @richsilv @AWilcke
|
|
142
142
|
/tests/tasks/uipath-maestro-flow/ixp/ @jcalero @constantinmuraru @scallaway-uipath @tommilligan @joe-prosser @vlad-crisan @richsilv @AWilcke
|
|
143
143
|
|
|
144
|
+
# Voice — inline voice agent node + the trigger, dial, and end-call nodes
|
|
145
|
+
/skills/uipath-maestro-flow/references/author/references/plugins/inline-voice-agent/ @UiPath/jarvis @joshparksj @maxduu @scottcmg @andrewwan-uipath @norman-le
|
|
146
|
+
/tests/tasks/uipath-maestro-flow/voice/ @UiPath/jarvis @joshparksj @maxduu @scottcmg @andrewwan-uipath @norman-le
|
|
147
|
+
|
|
144
148
|
# Review skill
|
|
145
149
|
/skills/uipath-review/ @AlvinStanescu @gabrielavaduva @roalexandru
|
|
146
150
|
/skills/uipath-review/references/agents/guardrails/ @apetraru-uipath @valentinabojan @ctiliescuuipath
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/skills",
|
|
3
|
-
"version": "1.201.0-preview.
|
|
3
|
+
"version": "1.201.0-preview.591",
|
|
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"
|
|
@@ -31,6 +31,7 @@ Every node in a `.flow` file has exactly one author. The validator enforces this
|
|
|
31
31
|
| Human-in-the-loop | `uipath.human-in-the-loop.quick-form` (inline form), `uipath.human-in-the-loop.coded-action-app` (app-based) |
|
|
32
32
|
| Patterns | `uipath.pattern.batch-transform`, `uipath.pattern.deep-rag` |
|
|
33
33
|
| Agents | `uipath.agent.autonomous` (inline; after `uip agent init --inline-in-flow`) |
|
|
34
|
+
| Voice | `core.trigger.voice`, `uipath.agent.voice` (inline; after `uip agent init --inline-in-flow --conversational`), `uipath.conversational.voice.create-outgoing-call`, `uipath.conversational.voice.end-call` |
|
|
34
35
|
| Resource nodes | `uipath.core.rpa-workflow.*`, `uipath.core.agent.*`, `uipath.core.flow.*`, `uipath.core.agentic-process.*`, `uipath.core.api-workflow.*`, `uipath.core.human-task.*` |
|
|
35
36
|
| Document extraction | `uipath.ixp.*` — the extraction step must always land a node ([ixp/impl.md](references/plugins/ixp/impl.md#landing-the-node-when-you-cannot-fully-configure-it)) |
|
|
36
37
|
| Queue | `core.action.queue.create`, `core.action.queue.create-and-wait` |
|
|
@@ -103,6 +104,7 @@ If you find yourself hand-writing `inputs.detail`, a `=jsonString:` blob, or `bi
|
|
|
103
104
|
| **Wire one node's output into another node's input** | [shared/node-output-wiring.md](../shared/node-output-wiring.md) |
|
|
104
105
|
| **Orchestrate RPA, agents, apps** | Relevant resource plugin: [rpa](references/plugins/rpa/), [agent](references/plugins/agent/), [agentic-process](references/plugins/agentic-process/), [flow](references/plugins/flow/), [api-workflow](references/plugins/api-workflow/), [hitl](references/plugins/hitl/) |
|
|
105
106
|
| **Embed an AI agent tightly coupled to this flow** | [plugins/inline-agent/](references/plugins/inline-agent/) |
|
|
107
|
+
| **Build a voice agent flow (answer or place phone calls)** | [plugins/inline-voice-agent/](references/plugins/inline-voice-agent/) — `uipath.agent.voice` plus the nodes that start, place, and end the call |
|
|
106
108
|
| **Extract structured fields from documents** | [plugins/ixp/](references/plugins/ixp/) — IxP extraction models for PDFs, scanned forms, receipts, invoices, contracts |
|
|
107
109
|
| **List IxP models / runtime projects available in flow** | [plugins/ixp/impl.md — Listing Published Models](references/plugins/ixp/impl.md#listing-published-models) — read-only registry search, no `.flow` scaffold or edits |
|
|
108
110
|
| **Create a resource that doesn't exist yet** | Use `core.logic.mock` placeholder — see [Edit/Write: Replace a mock](references/editing-operations-json.md#replace-a-mock-with-a-real-resource-node) + relevant plugin's `impl.md` |
|
|
@@ -175,6 +177,7 @@ If you find yourself hand-writing `inputs.detail`, a `=jsonString:` blob, or `bi
|
|
|
175
177
|
- [hitl](references/plugins/hitl/) — human input via UiPath Apps
|
|
176
178
|
- [agent](references/plugins/agent/) — published AI agent resources
|
|
177
179
|
- [inline-agent](references/plugins/inline-agent/) — autonomous agent embedded in flow
|
|
180
|
+
- [inline-voice-agent](references/plugins/inline-voice-agent/) — voice agent on a live phone call (inbound/outbound) + the trigger, create-call, and end-call nodes
|
|
178
181
|
- [ixp](references/plugins/ixp/) — published IxP document-extraction models (PDFs, scanned forms, receipts, invoices, contracts)
|
|
179
182
|
- [queue](references/plugins/queue/) — Orchestrator queue item creation
|
|
180
183
|
|
|
@@ -47,6 +47,7 @@ When a single edit touches more than one top-level array (e.g. insert-a-node hit
|
|
|
47
47
|
| **Add a connector trigger** | Remove manual trigger, add connector trigger, configure with connection. | [CLI: Replace trigger](editing-operations-cli.md#replace-manual-trigger-with-connector-trigger) + [connector-trigger/impl.md](plugins/connector-trigger/impl.md) |
|
|
48
48
|
| **Add a resource node** | Discover via registry (`--local` for in-solution, or tenant registry for published), add via `Edit`, wire edges. | Relevant plugin's `impl.md` + [editing-operations-json.md](editing-operations-json.md) |
|
|
49
49
|
| **Add an inline agent node** | Embed a `uipath.agent.autonomous` node with an inline agent definition living inside the flow project. | [inline-agent/planning.md](plugins/inline-agent/planning.md) for selection vs a published agent, [inline-agent/impl.md](plugins/inline-agent/impl.md) for scaffolding, direct `.flow` JSON structure, and validation. |
|
|
50
|
+
| **Add voice nodes** | Turn a flow into a phone conversation: a `uipath.agent.voice` inline conversational agent wired to a live call, plus the trigger, create-call, and end-call nodes. Binding an inbound number happens at deploy time, not in the `.flow`. | [inline-voice-agent/planning.md](plugins/inline-voice-agent/planning.md) for the two topologies and trunk requirements, [inline-voice-agent/impl.md](plugins/inline-voice-agent/impl.md) for node JSON, `callContext` wiring, and number binding. |
|
|
50
51
|
| **Add a HITL QuickForm node** | Insert a human approval/review/enrichment checkpoint. Wire the `completed` port after adding. | [Edit/Write: Add a node](editing-operations-json.md) + [hitl/impl.md](plugins/hitl/impl.md) |
|
|
51
52
|
|
|
52
53
|
The table intentionally routes OOTB structural CRUD to Edit/Write only. There is no CLI opt-in path for non-carve-out flow graph edits.
|
|
@@ -121,6 +121,7 @@ Each plugin has a `planning.md` with full selection heuristics, ports, key input
|
|
|
121
121
|
| --- | --- | --- |
|
|
122
122
|
| `core.trigger.manual` | _(inline — no plugin)_ | Flow is started on demand by a user or API call |
|
|
123
123
|
| `core.trigger.scheduled` | [scheduled-trigger](plugins/scheduled-trigger/planning.md) | Flow runs on a recurring schedule |
|
|
124
|
+
| `core.trigger.voice` | [inline-voice-agent](plugins/inline-voice-agent/planning.md) | Flow starts when a phone call arrives on a bound number (inbound voice topology) |
|
|
124
125
|
| IS connector trigger | [connector-trigger](plugins/connector-trigger/planning.md) | Flow starts when an external event fires (e.g., email received, issue created). Node type: `uipath.connector.trigger.<key>.<trigger>` |
|
|
125
126
|
|
|
126
127
|
**Rules:**
|
|
@@ -143,6 +144,8 @@ Each plugin has a `planning.md` with full selection heuristics, ports, key input
|
|
|
143
144
|
| `core.action.queue.create` | [queue](plugins/queue/planning.md) | Distribute work to robots — fire-and-forget |
|
|
144
145
|
| `core.action.queue.create-and-wait` | [queue](plugins/queue/planning.md) | Distribute work to robots — wait for result |
|
|
145
146
|
| `uipath.human-in-the-loop.quick-form` | [hitl](plugins/hitl/planning.md) | Pause flow for a human to review, approve, or fill in data — inline schema, no app required |
|
|
147
|
+
| `uipath.conversational.voice.create-outgoing-call` | [inline-voice-agent](plugins/inline-voice-agent/planning.md) | Dial an outbound phone call and emit its `callContext` (outbound voice topology) |
|
|
148
|
+
| `uipath.conversational.voice.end-call` | [inline-voice-agent](plugins/inline-voice-agent/planning.md) | End the active call in a voice flow |
|
|
146
149
|
|
|
147
150
|
### Control Flow
|
|
148
151
|
|
|
@@ -174,6 +177,7 @@ Agent nodes invoke AI agents for reasoning, judgment, or natural language tasks.
|
|
|
174
177
|
| --- | --- | --- |
|
|
175
178
|
| `uipath.agent.autonomous` | [inline-agent](plugins/inline-agent/planning.md) | Low-code agent is defined **inside** this flow project (scaffolded via `uip agent init --inline-in-flow`), tightly coupled to this flow, no separate versioning or cross-flow reuse |
|
|
176
179
|
| `uipath.core.agent.{key}` | [agent](plugins/agent/planning.md) | Agent lives as a separate project — either in this solution (sibling of the flow) or as a **published tenant resource** (appears in the registry after `uip login` + `uip maestro flow registry pull`); reusable across flows, independently versioned |
|
|
180
|
+
| `uipath.agent.voice` | [inline-voice-agent](plugins/inline-voice-agent/planning.md) | AI agent that converses in real time on a live phone call — an inline conversational agent (`settings.voice` in its `agent.json`) wired to a `callContext` |
|
|
177
181
|
|
|
178
182
|
See [inline-agent/planning.md — Inline vs Published Agent Decision Table](plugins/inline-agent/planning.md#inline-vs-published-agent-decision-table) for the full decision matrix.
|
|
179
183
|
|
|
@@ -219,6 +223,7 @@ Use this when defining edges. Every edge requires a `sourcePort` and `targetPort
|
|
|
219
223
|
| --- | --- | --- |
|
|
220
224
|
| `core.trigger.manual` | — | `output` |
|
|
221
225
|
| `core.trigger.scheduled` | — | `output` |
|
|
226
|
+
| `core.trigger.voice` | — | `output` |
|
|
222
227
|
| `uipath.connector.trigger.*` | — | `output` |
|
|
223
228
|
| `uipath.connector.event.*` (Wait for events) | `input` | `output`, `error` |
|
|
224
229
|
| `core.action.script` | `input` | `success`, `error` |
|
|
@@ -236,6 +241,9 @@ Use this when defining edges. Every edge requires a `sourcePort` and `targetPort
|
|
|
236
241
|
| `core.subflow` | `input` | `output`, `error` |
|
|
237
242
|
| `core.logic.mock` | `input` | `output` |
|
|
238
243
|
| `uipath.agent.autonomous` | `input` | `success`, `error`, `tool`, `context`, `escalation` |
|
|
244
|
+
| `uipath.agent.voice` | `input` | `success`, `error`, `tool`, `context`, `escalation` |
|
|
245
|
+
| `uipath.conversational.voice.create-outgoing-call` | `input` | `success`, `error` |
|
|
246
|
+
| `uipath.conversational.voice.end-call` | `input` | `success`, `error` |
|
|
239
247
|
| `uipath.core.agent.*` | `input` | `output`, `error` |
|
|
240
248
|
| `uipath.core.rpa-workflow.*` | `input` | `output`, `error` |
|
|
241
249
|
| `uipath.core.human-task.*` | `input` | `output`, `error` |
|
|
@@ -48,8 +48,12 @@ uip maestro flow registry get <node-type> --output json
|
|
|
48
48
|
| `core.logic.terminate` | [terminate/impl.md](plugins/terminate/impl.md) |
|
|
49
49
|
| `core.subflow` | [subflow/impl.md](plugins/subflow/impl.md) |
|
|
50
50
|
| `core.trigger.scheduled` | [scheduled-trigger/impl.md](plugins/scheduled-trigger/impl.md) |
|
|
51
|
+
| `core.trigger.voice` | [inline-voice-agent/impl.md](plugins/inline-voice-agent/impl.md) |
|
|
51
52
|
| `core.action.queue.*` | [queue/impl.md](plugins/queue/impl.md) |
|
|
52
53
|
| `uipath.agent.autonomous` | [inline-agent/impl.md](plugins/inline-agent/impl.md) |
|
|
54
|
+
| `uipath.agent.voice` | [inline-voice-agent/impl.md](plugins/inline-voice-agent/impl.md) |
|
|
55
|
+
| `uipath.conversational.voice.create-outgoing-call` | [inline-voice-agent/impl.md](plugins/inline-voice-agent/impl.md) |
|
|
56
|
+
| `uipath.conversational.voice.end-call` | [inline-voice-agent/impl.md](plugins/inline-voice-agent/impl.md) |
|
|
53
57
|
| `uipath.core.agent.*` | [agent/impl.md](plugins/agent/impl.md) |
|
|
54
58
|
| `uipath.core.rpa-workflow.*` | [rpa/impl.md](plugins/rpa/impl.md) |
|
|
55
59
|
| `uipath.core.agentic-process.*` | [agentic-process/impl.md](plugins/agentic-process/impl.md) |
|
package/skills/uipath-maestro-flow/references/author/references/plugins/inline-voice-agent/impl.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Voice Nodes — Implementation
|
|
2
|
+
|
|
3
|
+
This plugin covers building the two voice topologies: scaffolding the voice agent's directory, the four node JSON shapes, `callContext` wiring, and what validate/pack/debug enforce. Inline-agent mechanics (the agent subdirectory, `inputs.source`, resource nodes, refresh) are identical to [inline-agent/impl.md](../inline-agent/impl.md) — the voice deltas below are complete on their own; open that file only when the voice agent has tools/contexts/escalations or prompt inputs (the two sections linked from here).
|
|
4
|
+
|
|
5
|
+
Node type: `uipath.agent.voice`, bound to a local subdirectory via `inputs.source = <projectId>` — the same BPMN contract as the autonomous inline agent. The create-call and end-call nodes serialize to `ConversationalService.CreateOutgoingCall` / `ConversationalService.EndCall` serviceTasks.
|
|
6
|
+
|
|
7
|
+
## Prerequisite — Scaffold the Voice Agent
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uip agent init "<FlowProjectDir>" --inline-in-flow --conversational --output json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Same layout as any inline agent (`<FlowProjectDir>/<projectId-uuid>/` with `agent.json`, `flow-layout.json`, `evals/`, `features/`, `resources/`). **Record the returned `ProjectId`** — the voice node's `inputs.source` must match it exactly.
|
|
14
|
+
|
|
15
|
+
The scaffold is a conversational agent but has **no `settings.voice` block** — adding it is mandatory (next section).
|
|
16
|
+
|
|
17
|
+
## Configure `agent.json`
|
|
18
|
+
|
|
19
|
+
`--conversational` already writes everything a conversational agent needs except the voice block (full `agent.json` shape and per-field rules: the `uipath-agents` skill's [`agent-definition.md`](../../../../../../uipath-agents/references/lowcode/agent-definition.md)). **`Edit` one key into the existing `settings` object — never `Write` the file.** The fragment below is the key you add, not a document:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
"voice": {
|
|
23
|
+
"model": "gemini-3.1-flash-live-preview",
|
|
24
|
+
"maxTokens": 65536,
|
|
25
|
+
"temperature": 0,
|
|
26
|
+
"persona": "Aoede"
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A full-file `Write` of that fragment drops `settings.model`, `settings.engine`, and `metadata.isConversational`. Two of those losses are silent: `flow validate` never reads `settings.engine` (rule 2 below), so the flow validates clean and every call fails.
|
|
31
|
+
|
|
32
|
+
Those are the current Studio Web defaults. **Nothing validates `model` or `persona`** — `flow validate` only applies the node manifest's bounds to the numbers (`temperature` 0-1, `maxTokens` >= 0), so a made-up model name or a persona that belongs to a different model passes validate and then fails when the call tries to connect. No CLI command lists the accepted values; the voice-settings dropdowns in Studio Web are the only place they are enumerated. `persona` is per-model — the personas offered for one realtime model are not accepted by another.
|
|
33
|
+
|
|
34
|
+
Field rules:
|
|
35
|
+
|
|
36
|
+
1. **`settings.voice` is required** — the realtime speech model, its token budget, and the spoken `persona`. This is a *second* model, separate from `settings.model`: `settings.model` is the conversational engine's LLM (reasoning, tool calls); `settings.voice.model` is the realtime audio model.
|
|
37
|
+
2. **Leave `settings.engine: "conversational-v1"` and `metadata.isConversational: true` exactly as scaffolded** — both are required at runtime. `flow validate` checks `metadata.isConversational` and errors with `is not a conversational agent` when it is off; a wrong `settings.engine` is *not* caught by validate and surfaces only as a failed call, so do not rely on validation to catch it. Never hand-flip `metadata.isConversational` to repair it; re-scaffold with `uip agent init --inline-in-flow --conversational` (`uipath-agents` critical rule 23).
|
|
38
|
+
3. **`outputSchema` is optional** — the scaffold leaves it empty (`{ "type": "object", "properties": {} }`) and a voice agent works that way, because the node already emits three fixed outputs on its own (`uipath__agent_response_messages`, `uipath__voice_call_context`, `uipath__voice_session`). Declare properties only when the flow needs typed data out of the call. Custom fields **merge with** the fixed three rather than replacing them — unlike an autonomous agent, whose typed schema replaces its manifest output. Both kinds land flat at `$vars.<nodeId>.output.<field>`. Keep the node's `inputs.agentOutputVariables[]` in sync (see step 4's sibling contract): Studio Web projects `outputSchema` properties into that array and flushes the array back on save, so a schema authored without it renders an empty Outputs list in the properties panel.
|
|
39
|
+
4. Author the system prompt in `messages[0].content` (empty is valid — voice agents have no required prompt field — but a real persona/goal prompt is what makes the call useful). Prompt inputs follow the inline-agent contract unchanged — all five pieces, including the node-side delivery binding:
|
|
40
|
+
|
|
41
|
+
- **Delivery** — `inputs.agentInputVariables[]` on the voice node: `{ "id": "start__output__callerName", "type": "string", "binding": "=$vars.start.output.callerName" }`
|
|
42
|
+
- **Contract** — the same key under `agent.json` `inputSchema.properties`
|
|
43
|
+
- **Resolution** — `{{input.start__output__callerName}}` in `messages[].content` (never a bare `$vars.…` — nothing rewrites agent.json prompt text, so it reaches the model literally)
|
|
44
|
+
- **Variable** — when the binding's source is a **trigger**, the field must be declared in `variables.globals[]` as `{ "id": "callerName", "direction": "in", "triggerNodeId": "start" }`. A binding sourced from any other node (a script or connector output) reads that node's own output and declares nothing
|
|
45
|
+
- **Tokens** — rebuild `contentTokens` via `uip agent refresh --inline-in-flow`; never hand-author them
|
|
46
|
+
|
|
47
|
+
Omit the Delivery binding and `flow debug` still works (it back-fills from `inputSchema`) while `flow pack` ships empty `JobArguments` — the published call gets no inputs. Full contract: [inline-agent/impl.md § Wiring Flow Variables into Agent Prompts](../inline-agent/impl.md#wiring-flow-variables-into-agent-prompts).
|
|
48
|
+
5. `settings.model`, `maxTokens`, `temperature`, `maxIterations` tune the engine LLM as for any conversational agent (`uip agent model list` for the tenant's models).
|
|
49
|
+
|
|
50
|
+
## Registry Validation
|
|
51
|
+
|
|
52
|
+
Read the node definitions during Phase 2 to copy into `definitions[]`. All four voice types ship in the CLI's bundled node registry, so `registry get` answers locally — no `uip login` and no `registry pull` required. Fetch only the three types your topology uses:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uip maestro flow registry get uipath.agent.voice --output json
|
|
56
|
+
uip maestro flow registry get uipath.conversational.voice.end-call --output json
|
|
57
|
+
# inbound only:
|
|
58
|
+
uip maestro flow registry get core.trigger.voice --output json
|
|
59
|
+
# outbound only:
|
|
60
|
+
uip maestro flow registry get uipath.conversational.voice.create-outgoing-call --output json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`uipath.agent.voice` confirms identically to the autonomous inline agent — ports, `model.source: true` hoisting onto `inputs.source`, and `model.serviceType` / `model.version` — see [inline-agent/impl.md § Registry Validation](../inline-agent/impl.md#registry-validation). Voice adds no port or model field to that set. On the create-call and end-call nodes, confirm `ConversationalService.CreateOutgoingCall` / `ConversationalService.EndCall` as `model.serviceType`. Never hand-write `definitions[]` entries — always copy them from `registry get`.
|
|
64
|
+
|
|
65
|
+
**`registry get` succeeding does not mean the tenant can place calls.** It answers from the bundled registry, so it succeeds offline and on any tenant. Whether a SIP trunk is provisioned can only be established at deploy/debug time — check with `uip conversational trunks list` rather than treating a clean `registry get` as proof.
|
|
66
|
+
|
|
67
|
+
## Adding / Editing
|
|
68
|
+
|
|
69
|
+
For step-by-step add, delete, and wiring procedures, see [editing-operations.md](../../editing-operations.md). Voice nodes are user-owned — author them directly in the `.flow` JSON with `Edit` / `Write` (same rule as the inline autonomous agent; they are not a Flow CLI carve-out).
|
|
70
|
+
|
|
71
|
+
### The `callContext` wiring rule
|
|
72
|
+
|
|
73
|
+
The node that originates the call emits `output.callContext`. Bind it into **both** the voice agent and the end-call node, as a structured `jsExpression` binding object (this is the persisted Studio Web shape — not a `=js:` string):
|
|
74
|
+
|
|
75
|
+
- Inbound: origin is the `core.trigger.voice` node
|
|
76
|
+
- Outbound: origin is the `uipath.conversational.voice.create-outgoing-call` node
|
|
77
|
+
- `fieldType` is `"object"` on the voice agent and `"string"` on the end-call node (a code-editor text field) — the two values Studio Web persists. Write them as given; do not derive them from the node definition's `inputDefinition` (both properties are declared `object` there). For `type: "jsExpression"` bindings the validator never reads `fieldType` — it only checks that `expression` is non-empty — so neither value can fail validation
|
|
78
|
+
|
|
79
|
+
### Node JSON — inbound trigger
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"id": "incomingCall1",
|
|
84
|
+
"type": "core.trigger.voice",
|
|
85
|
+
"typeVersion": "1.0",
|
|
86
|
+
"display": { "label": "Incoming call", "shape": "circle", "icon": "phoneIncoming" },
|
|
87
|
+
"inputs": { "entryPointId": "<generated-uuid>" }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`inputs.entryPointId` is a fresh UUID, same convention as other triggers ([shared/file-format.md](../../../../shared/file-format.md)). The phone number is bound to the process at deploy time, not in the `.flow`.
|
|
92
|
+
|
|
93
|
+
### Node JSON — create outgoing call (outbound only)
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"id": "createOutgoingCall1",
|
|
98
|
+
"type": "uipath.conversational.voice.create-outgoing-call",
|
|
99
|
+
"typeVersion": "1.0",
|
|
100
|
+
"display": { "label": "Create outgoing call", "icon": "phoneOutgoing" },
|
|
101
|
+
"inputs": {
|
|
102
|
+
"from": "<SIP-trunk-E164-number>",
|
|
103
|
+
"to": { "type": "literal", "expression": "<destination-E164-number>", "fieldType": "string" }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`from` is a **plain string** (an E.164 number provisioned as a SIP trunk on the tenant); `to` is a literal binding object. Both are required.
|
|
109
|
+
|
|
110
|
+
`from` comes from the tenant — `uip conversational trunks list --direction outbound --output json` enumerates the trunks it can be, each `phoneNumber` a usable value. `to` comes from the user; it is a destination, not a tenant fact. See [planning.md § Phone Numbers and SIP Trunks](planning.md#phone-numbers-and-sip-trunks).
|
|
111
|
+
|
|
112
|
+
### Node JSON — voice agent
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"id": "voiceAgent1",
|
|
117
|
+
"type": "uipath.agent.voice",
|
|
118
|
+
"typeVersion": "1.0",
|
|
119
|
+
"display": { "label": "Voice agent", "shape": "rectangle", "icon": "phone" },
|
|
120
|
+
"inputs": {
|
|
121
|
+
"source": "<projectId-uuid>",
|
|
122
|
+
"callContext": {
|
|
123
|
+
"type": "jsExpression",
|
|
124
|
+
"expression": "$vars.incomingCall1.output.callContext",
|
|
125
|
+
"fieldType": "object"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Two inputs when you author the node — `source` and `callContext`. Hand-author nothing else; see § What NOT to Do for the fields that hydrate on their own, and for the Studio-Web-authored flow where they are already populated and must be left in place.
|
|
132
|
+
|
|
133
|
+
### Node JSON — end call
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"id": "endCall1",
|
|
138
|
+
"type": "uipath.conversational.voice.end-call",
|
|
139
|
+
"typeVersion": "1.0",
|
|
140
|
+
"display": { "label": "End call", "icon": "phoneOff" },
|
|
141
|
+
"inputs": {
|
|
142
|
+
"callContext": {
|
|
143
|
+
"type": "jsExpression",
|
|
144
|
+
"expression": "$vars.incomingCall1.output.callContext",
|
|
145
|
+
"fieldType": "string"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Outbound flows bind from the create-outgoing-call node instead: `$vars.createOutgoingCall1.output.callContext`.
|
|
152
|
+
|
|
153
|
+
### Wire edges with Edit / Write
|
|
154
|
+
|
|
155
|
+
The trigger's source port is `output`; every other voice edge leaves `success`; targets are always `input`. Edge object shape: [editing-operations-json.md § Add an edge](../../editing-operations-json.md#add-an-edge).
|
|
156
|
+
|
|
157
|
+
**Inbound replaces the scaffolded trigger — it does not add beside it.** `flow init` scaffolds `start` / `core.trigger.manual` ([greenfield.md](../../greenfield.md)), and an inbound flow starts from `core.trigger.voice`. Delete the `start` node and any edge referencing it in the same edit that adds the voice trigger; leaving it in ships a two-trigger flow. Same replace-don't-append rule as [brownfield.md](../../brownfield.md)'s "Add a connector trigger" row. Outbound keeps the manual trigger — it is what starts the flow.
|
|
158
|
+
|
|
159
|
+
Outbound inserts the call node between trigger and agent: `manualTrigger1 (output) → createOutgoingCall1 (input)`, then `createOutgoingCall1 (success) → voiceAgent1 (input)`. Inbound wires straight through: `incomingCall1 (output) → voiceAgent1 (input)`. Tool/context/escalation resource nodes wire to the voice agent's artifact ports exactly as in [inline-agent/impl.md § Adding Resource Nodes](../inline-agent/impl.md#adding-resource-nodes).
|
|
160
|
+
|
|
161
|
+
## Accessing Output
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// In a Script node after the voice agent
|
|
165
|
+
const session = $vars.voiceAgent1.output.uipath__voice_session;
|
|
166
|
+
return { callEnded: session.callEnded, endedBy: session.endedBy };
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `$vars.{originNodeId}.output.callContext` — the live-call handle (`type`, `id`, `conversationId`); consumed by the voice agent and end-call bindings
|
|
170
|
+
- `$vars.{voiceAgentNodeId}.output.uipath__voice_session` — `callEnded` (bool), `endedBy` (`agent`/`user`/`system`/`error`), `reason`. The same node also emits `uipath__voice_call_context` and `uipath__agent_response_messages`
|
|
171
|
+
- `$vars.{voiceAgentNodeId}.output.<field>` — one entry per `agent.json` `outputSchema` property when you declared any (step 3). Flat, alongside the fixed `uipath__*` outputs, never nested under `.content.`
|
|
172
|
+
- `$vars.{endCallNodeId}.output.ended` — whether the call was ended
|
|
173
|
+
- `$vars.{nodeId}.error` — error details if one of the three action nodes fails (`core.trigger.voice` emits `output` only)
|
|
174
|
+
|
|
175
|
+
## Validate and Pack
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
uip maestro flow format <FlowName>.flow --output json
|
|
179
|
+
uip maestro flow validate <FlowName>.flow --output json
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Voice flows get extra validation on top of the standard checks: the agent directory must exist with a conversational `agent.json` carrying `settings.voice`, both `callContext` bindings must be present, and no voice agent node may sit inside a subflow. Failure modes and fixes are in § Debug.
|
|
183
|
+
|
|
184
|
+
Packing (`uip maestro flow pack`, or `uip solution pack` — see the operate capability) serializes the voice agent to an `Orchestrator.StartInlineAgentJob` serviceTask that **embeds the complete built agent definition** (`agentDefinition` in the BPMN context: agent.json + resources + features), and sets `runtimeOptions.isConversational: true` in the packed `operate.json`. That embedding is why pack and debug fail early when the agent directory is missing. Pack also re-checks the written BPMN and fails if the embedded definition is absent — a package without it deploys and then drops every call, so this never ships silently.
|
|
185
|
+
|
|
186
|
+
### Debug covers outbound only
|
|
187
|
+
|
|
188
|
+
`uip maestro flow debug` **rejects an inbound flow**: only a real call can raise a `core.trigger.voice`, so the run would never advance.
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
Inbound voice flows cannot be debugged from the CLI.
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The instructions on that error are the whole inbound test loop — publish, bind a number (§ Bind an Inbound Phone Number), then dial it. Swapping the trigger for a manual one lifts the rejection but leaves the inbound flow itself unexercised.
|
|
195
|
+
|
|
196
|
+
An **outbound** flow does run under `flow debug`, and it dials for real. The run's `--timeout` window has to outlast the conversation (default: 300 polls × the 2s poll interval = 10 minutes). Get user consent first and confirm the `to` number — the flow **places a real phone call**.
|
|
197
|
+
|
|
198
|
+
## Bind an Inbound Phone Number
|
|
199
|
+
|
|
200
|
+
An inbound flow does nothing until a trunk points at its deployed process. Nothing in the `.flow` carries the number — the binding is made against the **release key** after deploy.
|
|
201
|
+
|
|
202
|
+
> **Confirm with the user before running step 1.** `solution publish` and `solution deploy run` mutate the tenant, and this skill never defaults to an Orchestrator deploy — full flow and the Studio-Web alternative: [operate/ship.md § Path 2](../../../../operate/references/ship.md#path-2--orchestrator-deploy-explicit-only).
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# 1. ship the solution (the flow project alone is not deployable)
|
|
206
|
+
uip solution pack "<SolutionDir>" "<OutDir>" --output json
|
|
207
|
+
uip solution publish "<OutDir>/<SolutionName>_<version>.zip" --output json
|
|
208
|
+
uip solution deploy run --name <DEPLOYMENT_NAME> --folder-name <FOLDER_NAME> \
|
|
209
|
+
--package-name <SolutionName> --package-version <version> \
|
|
210
|
+
--parent-folder-path Shared --output json
|
|
211
|
+
|
|
212
|
+
# 2. read the release key + folder key back
|
|
213
|
+
uip or processes list --folder-path "Shared/<FOLDER_NAME>" --output json # Key, FolderKey
|
|
214
|
+
|
|
215
|
+
# 3. point the trunk at it
|
|
216
|
+
uip conversational trunks assign <E164-number> \
|
|
217
|
+
--process-key <Key> --folder-key <FolderKey> --yes --output json
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- `<FOLDER_NAME>` must be identical in step 1's `--folder-name` and step 2's `--folder-path` — deploy creates that folder under `--parent-folder-path`, and step 2 reads the process back out of it. `<DEPLOYMENT_NAME>` is independent and names the deployment only.
|
|
221
|
+
- `--process-key` is the **release `Key`** from `or processes list` (a GUID), not the package name and not the process id.
|
|
222
|
+
- `--entry-point` is optional and resolves automatically when the flow has exactly one incoming-call entry point — the normal case. Pass it explicitly only for a multi-entry-point package.
|
|
223
|
+
- `--yes` is required when the trunk already has a non-null `processKey`; it re-points the number and the previous process stops receiving calls.
|
|
224
|
+
- Verify with `uip conversational trunks list --direction inbound --output json` — `processName` should show your process and `entryPoint` should match the `core.trigger.voice` node's `inputs.entryPointId`. A mismatch there means the trunk is bound to a different build.
|
|
225
|
+
- To release a number, `uip conversational trunks assign <E164-number> --clear --yes` — after that the number rings nothing. Only run it when the user asks for the number back.
|
|
226
|
+
|
|
227
|
+
### Shipping an outbound flow
|
|
228
|
+
|
|
229
|
+
Outbound needs no binding step — `inputs.from` names the trunk directly, so the flow is complete once `flow debug` places its call. Two places it can go from there, both tenant-mutating (consent gate per SKILL.md rule #2):
|
|
230
|
+
|
|
231
|
+
- **Orchestrator**, to run it on a schedule or trigger it as a process — same `solution pack` → `publish` → `deploy run` sequence as above, minus step 3.
|
|
232
|
+
- **Studio Web**, to hand the flow to someone to open in the designer — `uip solution upload "<SolutionDir>"`. Note the `SolutionId` caveat in § Debug if `flow debug` already ran on this project.
|
|
233
|
+
|
|
234
|
+
## Debug
|
|
235
|
+
|
|
236
|
+
| Error | Cause | Fix |
|
|
237
|
+
| --- | --- | --- |
|
|
238
|
+
| `flow validate`: `agent.json not found at <path>` | `inputs.source` UUID doesn't match any subdirectory, or the agent directory was never created | Run `uip agent init "<FlowProjectDir>" --inline-in-flow --conversational`, set `inputs.source` to the returned `ProjectId` |
|
|
239
|
+
| `flow validate`: `` has no `settings.voice` `` | Scaffolded agent.json was not hand-edited | Add the `settings.voice` block (§ Configure `agent.json`) |
|
|
240
|
+
| `flow validate`: `is not a conversational agent` | `metadata.isConversational` is not `true` — usually the agent was scaffolded without `--conversational` | Re-scaffold with `uip agent init --inline-in-flow --conversational` and repoint `inputs.source` — do not hand-flip `metadata.isConversational` (`uipath-agents` critical rule 23) |
|
|
241
|
+
| `flow validate`: `[CONVERSATIONAL_VOICE_CALL_CONTEXT_REQUIRED]` (rule `conversational-voice-call-context`) | Voice agent node lacks the `inputs.callContext` binding | Bind `$vars.<originNodeId>.output.callContext` as a `jsExpression` object with `fieldType: "object"` |
|
|
242
|
+
| `flow validate` flags the end-call node's call context (rule `conversational-voice-end-call-context`) | End-call node lacks `inputs.callContext` | Same expression as the voice agent, `fieldType: "string"` |
|
|
243
|
+
| `flow validate`: `requires a source UUID at inputs.source` | Voice agent node has no `inputs.source` | Set it to the agent directory's UUID |
|
|
244
|
+
| `flow validate` / `flow pack`: `voice agent nodes are not supported inside subflows` | The voice agent node was placed in a `core.subflow`. Only top-level voice nodes get an embedded definition, so pack raises the same thing validate does | Move the node to the top-level flow. There is no flag for this and no partial support — a subflow voice agent would ship a serviceTask with no `agentDefinition` |
|
|
245
|
+
| `flow debug`: `Inbound voice flows cannot be debugged from the CLI.` | The flow starts from `core.trigger.voice`, which only a real call raises | Not a bug and not fixable locally — publish, bind a number, dial it (§ Bind an Inbound Phone Number). Do not swap in a manual trigger to force a run |
|
|
246
|
+
| `flow pack` / `flow debug`: `Missing agent definition for voice agent node …` | Agent directory deleted or moved after validate | Restore `<FlowProjectDir>/<projectId>/agent.json` or fix `inputs.source`; the BPMN is never written without the embedded definition |
|
|
247
|
+
| `flow pack` / `flow debug`: `Converted BPMN carries no agentDefinition for voice agent node(s) …` | Different failure from the row above — the agent directory is fine, but the CLI's bundled `@uipath/flow-converter` does not forward `voiceAgentDefinitions` to the BPMN serializer. Pack catches it rather than shipping a package that deploys and drops every call | `uip tools update` to a CLI whose converter supports voice, then re-pack. Nothing in the project can work around an old converter |
|
|
248
|
+
| `registry get` reports the voice type not found | The installed CLI predates voice support (the types ship in its bundled registry, so this is a CLI-version problem, not a tenant one) | `uip tools update`; re-run `registry get` |
|
|
249
|
+
| `uip conversational trunks …`: `unknown command 'trunks'` (and `uip conversational --help` lists no `trunks`) | The CLI predates the trunk commands. Independent of node support: the voice node types ship in the bundled registry, so authoring, `registry get`, and `validate` all work on a CLI whose `conversational` tool has no `trunks` | Tool packages resolve on the CLI's own `N.Nx` minor line, so `uip tools update` cannot pull a `trunks` that only exists on a later line — the CLI itself has to be on one that ships it (`uip --version`, and `which -a uip` when more than one is installed). A trunk's number and direction flags are also readable from the Phone numbers page. Note a tool's `-dev.<run>` number is a global CI counter, not a per-line one: a tool run number higher than the CLI's says nothing about which line it came from |
|
|
250
|
+
| Call never connects on a tenant that packs and deploys fine | No SIP trunk provisioned, or the number lacks the direction your topology needs — not detectable from the CLI at author time | `uip conversational trunks list` to see whether the tenant has any trunk at all. Adding a number, enabling a direction on it, and releasing it are portal-only — send the user to `{baseUrl}/{orgName}/agents_/phone-numbers` (e.g. `https://alpha.uipath.com/conversationalagents/agents_/phone-numbers`). Raise it as an Open Question rather than re-authoring the flow |
|
|
251
|
+
| Call connects but the agent is silent / call drops immediately | Package built without the embedded `agentDefinition` (hand-rolled pack pipeline), or `settings.voice` removed after pack | Re-pack with the CLI; verify the staged `.bpmn` has `name="agentDefinition"` on the voice serviceTask |
|
|
252
|
+
| Outbound call never dials | `from` is not a SIP trunk number on the tenant, or `to` is malformed, or the trunk exists but is not outbound-enabled | `uip conversational trunks list --direction outbound --output json`; use a number with `outboundEnabled: true` for `from`; `to` must be E.164 in a literal binding. Turning outbound *on* for an existing number is portal-only — the Phone numbers page, `{baseUrl}/{orgName}/agents_/phone-numbers` |
|
|
253
|
+
| Inbound number rings but nothing runs | Trunk not bound, bound to a different process, or bound to an older build | `uip conversational trunks list --direction inbound --output json` — check `processName` and that `entryPoint` matches the trigger's `inputs.entryPointId`; re-run `trunks assign` (§ Bind an Inbound Phone Number) |
|
|
254
|
+
| `solution deploy run`: `DraftDeploymentHasDifferentPackageVersion` | An earlier failed deploy left a draft under that deployment name, pinned to the version it first tried | Deploy under a new `--name`/`--folder-name`, or clear the stale draft |
|
|
255
|
+
| `solution upload`: `Studio Web already has a solution with SolutionId … Refusing to overwrite without --force` | `flow debug` stamped its staging `SolutionId` into the local `.uipx`, so upload now targets that cloud solution | Re-run with `--force` to update that project in place (this discards its Studio Web version history), or remove `SolutionId` from the `.uipx` to upload as a new solution |
|
|
256
|
+
|
|
257
|
+
## What NOT to Do
|
|
258
|
+
|
|
259
|
+
- **Do not scaffold a standalone voice agent** — there is no such thing; `uip agent init` without `--inline-in-flow` builds text agents. A voice agent exists only as an inline conversational agent inside a flow project.
|
|
260
|
+
- **Do not set an `isVoice` input flag on the node** — deprecated contract. The converter derives voice mode from the `uipath.agent.voice` node type; the `{"isVoice":true}` job body is emitted for you at pack time.
|
|
261
|
+
- **Do not hand-author a `model` block, `systemPrompt`/`userPrompt`, or `inputs.voice` on the voice node instance** — author it as a shell carrying `inputs.source` + `inputs.callContext` (plus `inputs.agentInputVariables[]` when the prompt reads flow data — that binding is the node's job, see step 4). Prompts live in the sidecar `agent.json`; flow-core hoists `model.source` onto `inputs.source`; validate/pack hydrate `voice` from `agent.json` `settings.voice`. **A Studio-Web-authored flow is the other case:** self-contained flows embed the agent's config inline, so `inputs.voice.model` / `persona` / `temperature` / `maxTokens` and `inputs.systemPrompt` are legitimately populated there — **leave them alone, never delete them as stray fields**. `uip agent refresh --inline-in-flow` shell-ifies the node back to structural inputs from your sidecar edits — see [inline-agent/impl.md § Refresh and Validate](../inline-agent/impl.md#refresh-and-validate).
|
|
262
|
+
- **Do not declare `outputSchema` properties on a voice agent and forget `inputs.agentOutputVariables[]`** — the schema is legal and optional (step 3), but the two are one fact in two places. Author neither, or both. Session data needs no schema: it always arrives at `$vars.<nodeId>.output.uipath__voice_session`.
|
|
263
|
+
- **Do not collapse `settings.voice.model` into `settings.model`** — they are two different models (realtime speech vs engine LLM) and both are read.
|
|
264
|
+
- **Do not `Write` a whole `agent.json` to add `settings.voice`** — `Edit` the key into the scaffolded file. A full-file write drops `settings.model`, `settings.engine`, and `metadata.isConversational`, and validate catches only the last of the three.
|
|
265
|
+
- **Do not leave the scaffolded `core.trigger.manual` in an inbound flow** — `core.trigger.voice` replaces it. Two triggers is not a topology; delete `start` and its edges (§ Wire edges with Edit / Write).
|
|
266
|
+
- **Do not put a voice agent node inside a subflow** — only top-level voice nodes get their agent definition embedded at pack time, so both `flow validate` and pack reject one in a `core.subflow`. Keep the whole call — trigger/dial, agent, end-call — in the top-level flow.
|
|
267
|
+
- **Do not run `uip maestro flow eval` on a voice flow** — the platform blocks voice agents from eval runs; the CLI rejects it with a clear error.
|
|
268
|
+
- **Do not try to `flow debug` an inbound flow, or rewrite it as outbound to get a local run** — the CLI rejects an incoming-call trigger by design (§ Debug covers outbound only). Inbound is tested by publishing, binding a number, and dialing it.
|
|
269
|
+
- **Do not hand-write `definitions[]` entries** — copy verbatim from `uip maestro flow registry get <node-type>`.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Voice Nodes — Planning
|
|
2
|
+
|
|
3
|
+
Voice nodes let a flow hold a real-time AI voice conversation on a live phone call. The centerpiece is `uipath.agent.voice` — an **inline conversational agent** whose `agent.json` carries a `settings.voice` block. Around it sit three nodes that start, place, and end the call. There is no standalone voice agent — a voice agent only runs inside a Maestro Flow.
|
|
4
|
+
|
|
5
|
+
For inline-agent fundamentals (the agent subdirectory, `inputs.source` binding, resource nodes on artifact ports), see [inline-agent/planning.md](../inline-agent/planning.md) — everything there applies to the voice agent node too. This plugin covers what voice adds on top: the node set, the two call topologies, and the `callContext` wiring rule.
|
|
6
|
+
|
|
7
|
+
## Node Types
|
|
8
|
+
|
|
9
|
+
| Node Type | Role | When to Select |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `uipath.agent.voice` | Agent | AI agent that converses in real time on a live call. Backed by an inline conversational agent directory (`<uuid>/agent.json` with `settings.voice`) |
|
|
12
|
+
| `core.trigger.voice` | Trigger | Start the flow when a phone call arrives on a number bound to the process (inbound topology) |
|
|
13
|
+
| `uipath.conversational.voice.create-outgoing-call` | Action | Dial an outbound call and wait until the media stream is open; emits the `callContext` (outbound topology) |
|
|
14
|
+
| `uipath.conversational.voice.end-call` | Action | End the active call |
|
|
15
|
+
|
|
16
|
+
All four are fixed OOTB node types. They ship in the CLI's bundled registry, so `registry get` resolves them offline on any tenant — a clean `registry get` confirms the *node shapes*, not that the tenant can place calls. SIP trunk provisioning is only observable at deploy/debug time — check it with `trunks list` below. Commands: [impl.md § Registry Validation](impl.md#registry-validation).
|
|
17
|
+
|
|
18
|
+
## Phone Numbers and SIP Trunks
|
|
19
|
+
|
|
20
|
+
Both topologies need a SIP trunk on the tenant, and **direction is a separate flag from existence** — a number that exists may still be unusable for your topology:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
uip conversational trunks list --direction outbound --output json # outbound `from`
|
|
24
|
+
uip conversational trunks list --direction inbound --output json # inbound binding
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- **Outbound `inputs.from`** — one of the tenant's outbound-enabled trunks. `trunks list --direction outbound` enumerates the candidates; each trunk's `phoneNumber` is a usable value. A number that is only inbound-enabled fails at dial time, not at validate.
|
|
28
|
+
- **Outbound `inputs.to`** — the user's to give. Who gets called is not a tenant fact and not the agent's call to make.
|
|
29
|
+
- **Inbound** — the number you bind must have `inboundEnabled: true`. A tenant can easily have several trunks where only one qualifies.
|
|
30
|
+
- A trunk already showing a non-null `processKey` is bound to another process; re-pointing it needs `--yes` and **silently takes the number away from that process**. Confirm with the user before reusing one.
|
|
31
|
+
- **`trunks list` returning nothing is not something you can fix from the CLI.** The CLI can read trunks and bind one to a process — it cannot add a number, enable a direction on one, or release one back. Those are portal-only, on the **Phone numbers** page:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
{baseUrl}/{orgName}/agents_/phone-numbers
|
|
35
|
+
# e.g. https://alpha.uipath.com/conversationalagents/agents_/phone-numbers
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It is org-scoped (no tenant segment) — build it from `uip login status --output json` (`Data.BaseUrl` + `Data.Organization`). There is no `trunks create`.
|
|
39
|
+
|
|
40
|
+
Numbers referenced in older examples go stale — always re-list rather than copying a number out of a doc or an existing flow. Binding an inbound number is a deploy-time step, not a `.flow` edit: [impl.md § Bind an Inbound Phone Number](impl.md#bind-an-inbound-phone-number).
|
|
41
|
+
|
|
42
|
+
## When to Use
|
|
43
|
+
|
|
44
|
+
Use voice nodes when the flow's job is a phone conversation — answering an inbound support line, placing an outbound notification/collection call — and an AI agent should hold that conversation.
|
|
45
|
+
|
|
46
|
+
### Voice vs Text Agent Decision Table
|
|
47
|
+
|
|
48
|
+
| Situation | Voice (`uipath.agent.voice`) | Inline autonomous ([`uipath.agent.autonomous`](../inline-agent/planning.md)) |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| The interaction is a live phone call | Yes | No |
|
|
51
|
+
| Reasoning/judgment step over flow data, no call involved | No | Yes |
|
|
52
|
+
| Needs typed `outputSchema` consumed by downstream nodes | Optional — the node emits three fixed `uipath__*` outputs regardless; custom schema properties merge with them | Yes |
|
|
53
|
+
| Needs eval runs (`uip maestro flow eval`) | No — the platform blocks voice agents from eval runs | Yes |
|
|
54
|
+
|
|
55
|
+
### When NOT to Use
|
|
56
|
+
|
|
57
|
+
- **No live call in the process** — use [inline-agent](../inline-agent/planning.md) or a published [agent](../agent/planning.md)
|
|
58
|
+
- **The "conversation" is text chat, not audio** — voice nodes are call-media-specific
|
|
59
|
+
|
|
60
|
+
## Topologies
|
|
61
|
+
|
|
62
|
+
Exactly two supported shapes. The `callContext` originates at the trigger (inbound) or the create-outgoing-call node (outbound) and must reach both the voice agent and the end-call node. **Both shapes live at the top level of the `.flow`** — a voice agent node inside a `core.subflow` is rejected by `flow validate` and by pack; see [impl.md § What NOT to Do](impl.md#what-not-to-do).
|
|
63
|
+
|
|
64
|
+
**Inbound** — agent answers a call:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
core.trigger.voice (output) → uipath.agent.voice (success) → uipath.conversational.voice.end-call
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Outbound** — flow places a call first:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
core.trigger.manual (output) → uipath.conversational.voice.create-outgoing-call (success) → uipath.agent.voice (success) → uipath.conversational.voice.end-call
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Picking a topology changes how the flow is tested
|
|
77
|
+
|
|
78
|
+
Only a real inbound call can raise a `core.trigger.voice`, so **`uip maestro flow debug` refuses an inbound flow outright** (`Inbound voice flows cannot be debugged from the CLI.`). Testing it means the full deploy path — publish, bind a number, then dial it — while an outbound flow runs under `flow debug` directly and places its call from the CLI.
|
|
79
|
+
|
|
80
|
+
| | Inbound | Outbound |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| Trigger | `core.trigger.voice` | `core.trigger.manual` (or any other trigger) |
|
|
83
|
+
| `uip maestro flow debug` | **Rejected** — publish + bind + dial the number | Runs, and places a real call |
|
|
84
|
+
| Phone number | Bound to the deployed release ([impl.md § Bind an Inbound Phone Number](impl.md#bind-an-inbound-phone-number)) | Named directly in `inputs.from` |
|
|
85
|
+
| Needs a deploy to test at all | Yes | No |
|
|
86
|
+
|
|
87
|
+
Outbound is the only shape with a local test loop; inbound cannot be exercised at all until it is deployed and a number is bound to it.
|
|
88
|
+
|
|
89
|
+
## Ports
|
|
90
|
+
|
|
91
|
+
`uipath.agent.voice` (same artifact ports as the inline autonomous agent):
|
|
92
|
+
|
|
93
|
+
| Port | Position | Direction | Use |
|
|
94
|
+
| --- | --- | --- | --- |
|
|
95
|
+
| `input` | left | target | Flow sequence input |
|
|
96
|
+
| `success` | right | source | Normal flow output (agent session ended) |
|
|
97
|
+
| `error` | right | source | Implicit error port (shared with all action nodes) — see [Implicit error port on action nodes](../../../../shared/file-format.md#implicit-error-port-on-action-nodes) |
|
|
98
|
+
| `tool` | bottom | source (artifact) | Connect tool resource nodes |
|
|
99
|
+
| `context` | bottom | source (artifact) | Connect context resource nodes |
|
|
100
|
+
| `escalation` | top | source (artifact) | Connect escalation resource nodes |
|
|
101
|
+
|
|
102
|
+
`core.trigger.voice`: single `output` source port (right). `uipath.conversational.voice.create-outgoing-call` and `uipath.conversational.voice.end-call`: `input` (left, target) + `success` (right, source) + the implicit `error` port.
|
|
103
|
+
|
|
104
|
+
## Output Variables
|
|
105
|
+
|
|
106
|
+
- `$vars.{originNodeId}.output.callContext` — the live-call handle (`{ type: "phone"|"web", id, conversationId }`). Origin is the trigger (inbound) or the create-outgoing-call node (outbound); it must be bound into **both** the voice agent and the end-call node.
|
|
107
|
+
- `$vars.{voiceAgentNodeId}.output` — end-of-session data (`uipath__voice_session`, `uipath__voice_call_context`, `uipath__agent_response_messages`), not a typed result object. Field shapes: [impl.md § Accessing Output](impl.md#accessing-output).
|
|
108
|
+
- `$vars.{endCallNodeId}.output.ended` — whether the call was ended.
|
|
109
|
+
- `$vars.{nodeId}.error` — error details (`code`, `message`, `detail`, `category`, `status`) on the three action nodes: `uipath.agent.voice`, create-outgoing-call, end-call. `core.trigger.voice` has no `error` — its outputDefinition is `output` only.
|
|
110
|
+
|
|
111
|
+
## Scaffolding Prerequisite
|
|
112
|
+
|
|
113
|
+
The voice agent's backing directory is created with the same command as any inline agent, plus the conversational flag:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
uip agent init "<FlowProjectDir>" --inline-in-flow --conversational --output json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Record the returned `ProjectId` — the voice node's `inputs.source` must match it exactly. The scaffold produces a conversational agent (`settings.engine: "conversational-v1"`, `metadata.isConversational: true`) **without** a `settings.voice` block — adding it by hand is mandatory, or `flow validate` fails. Shape and defaults: [impl.md § Configure `agent.json`](impl.md#configure-agentjson).
|
|
120
|
+
|
|
121
|
+
## Planning Annotation
|
|
122
|
+
|
|
123
|
+
In the architectural plan:
|
|
124
|
+
|
|
125
|
+
- `voice-topology: inbound | outbound` — which of the two shapes
|
|
126
|
+
- `voice-agent: <description>` with a `<projectId-placeholder>` — the UUID is assigned during Phase 2 when `uip agent init --inline-in-flow --conversational` runs
|
|
127
|
+
- Outbound only: `voice-from: <SIP trunk E.164 number>` — one of the tenant's outbound-enabled trunks (§ Phone Numbers and SIP Trunks) — and `voice-to: <destination E.164 number>`, which the user supplies
|
|
128
|
+
- Tools/contexts/escalations on the voice agent reuse the [inline-agent](../inline-agent/planning.md) annotations
|
|
@@ -71,6 +71,7 @@ Three failure modes observed in agent-generated `.flow` files:
|
|
|
71
71
|
| **Loop nodes** (`core.logic.loop`) | `inputs.collection` | **YES** |
|
|
72
72
|
| **Subflow nodes** (`core.subflow`) | `inputs.<inputId>.source` | **YES** |
|
|
73
73
|
| **Script nodes** (`core.action.script`) | `inputs.script` body — `$vars.*` is read inside JS, no `=js:` wrapping | **NO** — the body is already JS |
|
|
74
|
+
| **Voice `callContext`** (`uipath.agent.voice`, `uipath.conversational.voice.end-call`) | `inputs.callContext` — a structured binding object `{ "type": "jsExpression", "expression": "$vars.<originNodeId>.output.callContext", "fieldType": ... }`, never a bare string. `fieldType` is `"object"` on the voice agent and `"string"` on the end-call node. | **NO** — the expression sits unprefixed inside the object's `expression` field. See [author/plugins/inline-voice-agent/impl.md § The `callContext` wiring rule](../author/references/plugins/inline-voice-agent/impl.md#the-callcontext-wiring-rule). |
|
|
74
75
|
| **Inline-agent prompt** (`uipath.agent.autonomous` `agent.json` `messages[].content`) | Tokens reference upstream flow nodes directly: `{{ $vars.<flowNodeId>.output[.<field>] }}` (spaced braces). Mirror in `contentTokens[]` as `{ "type": "variable", "rawString": " $vars.<flowNodeId>.output[.<field>] " }` — `rawString` must include leading and trailing space. Never `{{input.<id>}}` and never bare `{{name}}`. | **NO** — `{{ ... }}` tokens, not `=js:`. See [author/references/plugins/inline-agent/impl.md § Wiring Flow Variables into Agent Prompts](../author/references/plugins/inline-agent/impl.md#wiring-flow-variables-into-agent-prompts). Encoding note: a read `agent.json` may use the flat `__` input keys or a newer nested (dotted-key) form — author flat, read both (see the impl.md encoding note). |
|
|
75
76
|
|
|
76
77
|
**Rule of thumb:** If the field is *value-typed* (anything other than a hardcoded condition), `=js:` is required for `$vars`/`$metadata`/`$self` references. The two condition fields (Decision, Switch) and the script body are the only exceptions — they are always parsed as JS regardless.
|
package/version-manifest.json
CHANGED