Skip to content

feat: workspace persistence across conversational exchanges via content-parts#145

Open
radu-mocanu wants to merge 1 commit into
mainfrom
feat/conversational-advanced-workspace
Open

feat: workspace persistence across conversational exchanges via content-parts#145
radu-mocanu wants to merge 1 commit into
mainfrom
feat/conversational-advanced-workspace

Conversation

@radu-mocanu

@radu-mocanu radu-mocanu commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • persist conversational workspaces as marked CAS attachment content-parts on the final assistant message
  • preserve all execute options, propagate persistence failures, and allow hydration retry
  • compose suspend storage with conversation persistence so HITL resumes restore state without re-uploading unchanged files

Copilot AI review requested due to automatic review settings July 6, 2026 14:49
@radu-mocanu radu-mocanu requested a review from a team as a code owner July 6, 2026 14:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new runtime wrapper to persist a workspace across conversational exchanges by hydrating from the last assistant message’s file content-parts and (on success) emitting workspace files back as content-part attachments.

Changes:

  • Introduces ConversationalWorkspaceRuntime to hydrate from conversation history and dehydrate workspace files as file content-parts before the final assistant endMessage.
  • Adds CAS URI helpers (build_cas_uri, parse_attachment_id) and WorkspaceHydrator.hydrate_files to support registry-less hydration from history.
  • Adds comprehensive tests for hydration/dehydration behavior and bumps package version to 0.12.2.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
uv.lock Bumps locked package version to 0.12.2.
pyproject.toml Bumps project version to 0.12.2.
src/uipath/runtime/workspace/hydrator.py Adds hydrate_files() to download attachments and build a registry without a preexisting registry.
src/uipath/runtime/workspace/conversational.py Adds ConversationalWorkspaceRuntime that hydrates from history and emits workspace content-parts on success.
src/uipath/runtime/workspace/cas_uri.py Adds helpers to build/parse CAS attachment URIs used by conversational workspace persistence.
src/uipath/runtime/workspace/init.py Exposes the new conversational runtime and CAS URI helpers from the workspace package.
src/uipath/runtime/init.py Re-exports ConversationalWorkspaceRuntime from the top-level runtime package.
tests/workspace/test_conversational_workspace.py Adds tests covering ordering, hydration rules, relinking vs reupload, and disposal behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/uipath/runtime/workspace/conversational.py Outdated
Comment thread src/uipath/runtime/workspace/cas_uri.py Outdated
@radu-mocanu radu-mocanu force-pushed the feat/conversational-advanced-workspace branch 4 times, most recently from 359f08f to ed1ce54 Compare July 15, 2026 09:46
@radu-mocanu radu-mocanu force-pushed the feat/conversational-advanced-workspace branch from ed1ce54 to 13bd8fe Compare July 15, 2026 11:03
@sonarqubecloud

Copy link
Copy Markdown

Comment on lines +52 to +58
for message in reversed(messages):
if isinstance(message, UiPathConversationMessage):
if message.role == "assistant":
return message
elif isinstance(message, Mapping) and message.get("role") == "assistant":
return UiPathConversationMessage.model_validate(message)
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quite surprised we have no existing helper for "get last message of type X". Pretty sure we had similar needs for the tool node

Comment on lines +110 to +112
if conversation_event is None:
yield event
return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there is a technical edge case here, but I'm not sure how much of a real concern it is yet:

Suppose the original event order would be:

  • Message Start
  • Message End
  • some kind of langgraph event not related to the conversation messages

Under the new buffer, message end will get buffered while the non-conversation events will be yielded, so the non-conversational events will get mixed between:

  • Message Start
  • Other events
  • Message End

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants