feat(action-center): extend taskSourceMetadata on CreateTask/CreateEscalation - #1873
feat(action-center): extend taskSourceMetadata on CreateTask/CreateEscalation#1873dushyant-uipath wants to merge 1 commit into
Conversation
c3aa950 to
a400801
Compare
…sk/CreateEscalation HITL tasks created via interrupt(CreateEscalation(...)) have no way to carry caller-supplied context (e.g. a conversational-agent id) in taskSource.taskSourceMetadata today; it is built entirely from UiPathConfig state with no extension point. Add an optional task_source_metadata dict to CreateTask (inherited by CreateEscalation) and TasksService.create/create_async, threaded through _create_spec and merged into taskSourceMetadata (as custom_metadata) on top of the built-in InstanceId/FolderKey/JobKey/ProcessKey keys. Additive only; no change for existing callers.
a400801 to
48b2250
Compare
There was a problem hiding this comment.
🟡 Changes recommended
A few small but user-facing issues remain (metadata merge can raise an opaque TypeError on invalid keys, collision behavior isn’t asserted, and docs should clarify when taskSource is populated).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Extends the Action Center task creation surface so callers of CreateTask / CreateEscalation (including resume-trigger flows) can attach arbitrary additional key/value context into taskSource.taskSourceMetadata, merged on top of the SDK’s built-in correlation keys.
Changes:
- Added
task_source_metadatato theCreateTaskinterrupt model and threaded it through resume triggers intoTasksService.create/create_async. - Extended task request spec building to merge caller-provided metadata into
taskSource.taskSourceMetadata(caller wins on collision). - Added tests to validate metadata merging behavior and bumped
uipath-platformversion.
File summaries
| File | Description |
|---|---|
| packages/uipath-platform/src/uipath/platform/common/interrupt_models.py | Adds task_source_metadata to CreateTask (inherited by CreateEscalation). |
| packages/uipath-platform/src/uipath/platform/resume_triggers/_protocol.py | Passes interrupt-provided task_source_metadata into tasks.create_async(...). |
| packages/uipath-platform/src/uipath/platform/action_center/_tasks_service.py | Plumbs task_source_metadata through create/create_async into request payload taskSourceMetadata. |
| packages/uipath-platform/tests/services/test_actions_service.py | Adds tests covering merge/omit behavior for extra task-source metadata. |
| packages/uipath-platform/tests/services/test_hitl.py | Updates interrupt construction to include the new field in the test setup. |
| packages/uipath-platform/pyproject.toml | Bumps package version to 0.2.24. |
| packages/uipath-platform/uv.lock | Updates lockfile version entry for uipath-platform. |
Review details
Suppressed comments (1)
packages/uipath-platform/src/uipath/platform/action_center/_tasks_service.py:627
- Same as
create_async:task_source_metadatais ignored unless_apply_task_sourcepopulates thetaskSourceblock (requiresUiPathConfig.project_idandUiPathConfig.trace_id). Adding that note here would prevent confusion for callers.
task_source_metadata: Optional extra keys merged into taskSource.taskSourceMetadata,
on top of the built-in InstanceId/FolderKey/JobKey/ProcessKey (e.g. a
conversational-agent id a HITL task should carry downstream)
- Files reviewed: 6/8 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| "InstanceId": trace_id, | ||
| "FolderKey": UiPathConfig.folder_key, | ||
| "JobKey": UiPathConfig.job_key, | ||
| "ProcessKey": UiPathConfig.process_uuid, | ||
| **(custom_metadata or {}), |
| task_source_metadata: Optional extra keys merged into taskSource.taskSourceMetadata, | ||
| on top of the built-in InstanceId/FolderKey/JobKey/ProcessKey (e.g. a | ||
| conversational-agent id a HITL task should carry downstream) |
| service.create( | ||
| title="Test Action", | ||
| app_key="test-app-key", | ||
| data={"test": "data"}, | ||
| task_source_metadata={"ConversationalAgentId": "agent-1"}, | ||
| ) | ||
|
|
||
| task_source_metadata = _posted_body(httpx_mock, create_task_url)["taskSource"][ | ||
| "taskSourceMetadata" | ||
| ] | ||
| assert task_source_metadata["ConversationalAgentId"] == "agent-1" | ||
| # The built-in correlation keys are still populated alongside the extra one. | ||
| assert task_source_metadata["InstanceId"] == "trace-1" | ||
|
|
|




Problem
taskSource.taskSourceMetadatais assembled inside_apply_task_source(action_center/_tasks_service.py) fromUiPathConfigstate:InstanceId,FolderKey,JobKey,ProcessKey.CreateTask's other fields (data,actionable_message_metadata,labels, etc.) each map onto a parameter of_create_spec.taskSourceMetadatadoes not, since it is built entirely fromUiPathConfigrather than from aCreateTaskfield.Decision
Add an optional
task_source_metadata: dict[str, Any] | Nonefield toCreateTask(inherited byCreateEscalation), merged intotaskSourceMetadataon top of the built-in keys. Caller keys win on collision.Usecase
Any caller of
CreateTask/CreateEscalationcan attach arbitrary key/value context totaskSource.taskSourceMetadata, the same block that already carries job/process correlation ids (InstanceId,FolderKey,JobKey,ProcessKey). Anything reading the task record downstream, Orchestrator, Plugins, or another resume-trigger consumer, gets that context alongside the built-in keys.The concrete case behind this (ACTN-123): Verticals' Purchase Request solution routes HITL reviews through a unified Teams interface, where a reviewer can ask questions to a conversational agent tied to that task. The escalation is created by a coded agent (
decision-router), viainterrupt(CreateEscalation(...)), as an inner step of the BPMN's decision-router node, rather than through a dedicated HITL node with its own resource picker. That puts the conversational-agent choice for a given step in the coded agent itself, not in Studio Web. The interim fix hardcodes aconversationalAgentIdindecision-routerand passes it on the task, so the Plugins service can read it offtaskSourceMetadataand attach the right conversational agent to the actionable card.sequenceDiagram participant Agent as decision-router (coded agent) participant Trig as UiPathResumeTriggerCreator participant Tasks as TasksService.create_async participant Orch as Orchestrator (CreateAppTask) participant Plugins as Plugins service Agent->>Agent: interrupt(CreateEscalation(task_source_metadata={"ConversationalAgentId": id})) Agent->>Trig: job suspends on the CreateEscalation value Trig->>Tasks: create_async(..., task_source_metadata=value.task_source_metadata) Tasks->>Orch: POST taskSource.taskSourceMetadata = {InstanceId, FolderKey, JobKey, ProcessKey, ConversationalAgentId} Orch-->>Plugins: task record carries taskSource.taskSourceMetadata Plugins->>Plugins: reads ConversationalAgentId, attaches the conversational agent to the actionable cardThis is a draft for the platform team's review; open to folding
task_source_metadataintoactionable_message_metadatainstead, if that fits the wire contract better.Changes
common/interrupt_models.py: newtask_source_metadatafield onCreateTask.resume_triggers/_protocol.py:_handle_task_triggerpassesvalue.task_source_metadatainto thetasks.create_async(...)call it makes when a job suspends onCreateTask/CreateEscalation. Without this, a value set on the interrupt object would never reach the API call.action_center/_tasks_service.py:TasksService.create/create_asyncaccepttask_source_metadata, pass it to_create_spec, which passes it to_apply_task_source, where it merges intotaskSourceMetadata.Compatibility
New parameter, defaults to
None. Pydantic's generated__init__forCreateTasktakes**data, so its fields are keyword-only;create/create_asyncalready require keyword arguments pastdata. Existing callers ofCreateTask,CreateEscalation,TasksService.create, andTasksService.create_asyncsee no behavior change unless they start passingtask_source_metadatathemselves.Test plan
test_create_merges_task_source_metadata,test_create_async_merges_task_source_metadata,test_create_omits_extra_task_source_metadata_when_unsetinpackages/uipath-platform/tests/services/test_actions_service.py.packages/uipath-platform, including the three new tests above.