Skip to content

feat: scaffold MemoryService for Agent Episodic Memory (URT migration)#1467

Merged
mjnovice merged 18 commits intomainfrom
feat/memory-service-scaffold
Apr 17, 2026
Merged

feat: scaffold MemoryService for Agent Episodic Memory (URT migration)#1467
mjnovice merged 18 commits intomainfrom
feat/memory-service-scaffold

Conversation

@mjnovice
Copy link
Copy Markdown
Contributor

@mjnovice mjnovice commented Mar 20, 2026

Summary

Adds MemoryService to uipath-platform — the SDK client for Agent Memory Spaces. This enables programmatic access to memory space CRUD, dynamic few-shot search, and escalation memory operations used by the UiPath agentic loop.

What's included

  • MemoryService exposed as sdk.memory on the UiPath class
  • 5 methods (sync + async): create, list, search, escalation_search, escalation_ingest
  • Pydantic models matching ECS v2 and LLMOps swagger contracts: MemorySpace, MemorySpaceCreateRequest, MemorySearchRequest/Response, EscalationMemoryIngestRequest, etc.
  • 13 unit tests with pytest-httpx HTTP mocking
  • E2E test suite for alpha environment validation
  • Two gateways: ECS v2 (/ecs_/v2/episodicmemories) for CRUD, LLMOps (/llmopstenant_/api/Agent/memory) for search and escalation
  • Folder-scoped operations with serverless folder_path resolution

SDK Methods → Agents Repo References

create() — POST /ecs_/v2/episodicmemories/create

Layer File Component
Backend External.Clients/Ecs/EcsClient.cs:30 CreateMemorySpaceAsync()
Backend External.Clients/Ecs/AgentMemoryService.cs:20 CreateNamespaceAsync() (wrapper)
Frontend frontend/src/stores/memoryStore.ts:108 useCreateMemorySpace()
Frontend frontend/src/stores/memoryStore.ts:462 useCreateEpisodicMemory()
Frontend-SW frontend-sw/src/api/hooks/memory.ts:93 useCreateMemorySpace()

list() — GET /ecs_/v2/episodicmemories

Layer File Component
Backend External.Clients/Ecs/EcsClient.cs:186 GetEpisodicMemorySpaceAsync() (with $filter)
Frontend frontend/src/stores/memoryStore.ts:129 useFetchMemorySpaces()
Frontend-SW frontend-sw/src/api/hooks/memory.ts:37 useFetchMemorySpaces()

search() — POST /llmopstenant_/api/Agent/memory/{id}/search

Layer File Component
Backend External.Clients/LlmOps/LlmOpsClient.cs:238 GetDynamicFewShotExamplesFromTracesAsync()
Backend Execution.Shared/MemorySpaces/MemorySpacesExecutor.cs:44 QueryDynamicFewShotPromptsWithDetailsAsync()agentic loop
Interface Common/Clients/ILlmOpsClient.cs:33 ILlmOpsClient contract

escalation_search() — POST /llmopstenant_/api/Agent/memory/{id}/escalation/search

Layer File Component
Backend External.Clients/LlmOps/LlmOpsClient.cs:259 SearchEscalationMemoryAsync()
Backend Execution.Shared/Tools/EscalationTool/EscalationToolExecutor.cs:642 FetchFromMemory()escalation tool
Interface Common/Clients/ILlmOpsClient.cs:40 ILlmOpsClient contract

escalation_ingest() — POST /llmopstenant_/api/Agent/memory/{id}/escalation/ingest

Layer File Component
Backend External.Clients/LlmOps/LlmOpsClient.cs:296 IngestEscalationMemoryAsync()
Backend Execution.Shared/Tools/EscalationTool/EscalationToolExecutor.cs:518 GetEscalationOutcomeAsync()escalation tool
Interface Common/Clients/ILlmOpsClient.cs:47 ILlmOpsClient contract

API Contract References

Test plan

  • Unit tests with pytest-httpx mocking (13 tests)
  • Lint (ruff check), format (ruff format), type check (mypy) all pass
  • Verify endpoint URLs match ECS v2 and LLMOps swagger contracts
  • Verify models serialize/deserialize correctly with camelCase aliases
  • E2E integration test on alpha environment

🤖 Generated with Claude Code

@github-actions github-actions bot added the test:uipath-langchain Triggers tests in the uipath-langchain-python repository label Mar 20, 2026
@mjnovice mjnovice marked this pull request as draft March 20, 2026 18:03
@mjnovice mjnovice force-pushed the feat/memory-service-scaffold branch 2 times, most recently from 44bd0a8 to 239b787 Compare March 23, 2026 22:06
@mjnovice mjnovice marked this pull request as ready for review March 23, 2026 22:11
Comment thread packages/uipath-platform/src/uipath/platform/memory/memory.py
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
Comment thread packages/uipath-platform/src/uipath/platform/memory/_memory_service.py Outdated
@mjnovice mjnovice force-pushed the feat/memory-service-scaffold branch from 1dcb374 to a0ea814 Compare March 30, 2026 23:24
@smflorentino smflorentino self-requested a review April 15, 2026 00:12
mjnovice and others added 12 commits April 17, 2026 10:10
Add MemoryService client backed by ECS (/ecs_/memory/...) endpoints for
Agent Episodic Memory. This enables dynamic few-shot retrieval where
agents query past episodes at execution start and inject them as
examples into the system prompt.

New files:
- memory.py: Pydantic models (MemoryField, MemoryItem, MemoryQueryRequest, etc.)
- _memory_service.py: MemoryService with create, ingest, query, retrieve, delete, list
- __init__.py: Module exports

Also registers sdk.memory on the UiPath class.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tract

The original scaffold was based on a different/older API spec. This rewrites
models and endpoints to match the actual ECS v2 episodicmemories contract:
- Paths: /ecs_/v2/episodicmemories (not /ecs_/memory)
- Resources identified by GUID key (not name)
- Field model uses keyPath[] + value (not fieldName/fieldValue)
- Search replaces query, with structured SearchSettings and per-field settings
- Ingest now returns EpisodicMemoryIngestResponse with memory ID
- Added missing operations: delete_index, patch_memory (status active/inactive)
- EpisodicMemoryIndex includes all server fields (memoriesCount, folderKey, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per PR review feedback: ingestion should go to LLMOps, which extracts
fields from traces/feedback before forwarding to ECS.

Architecture:
- Index CRUD (create/list/get/delete) → ECS /ecs_/v2/episodicmemories
- Ingest → LLMOps /llmops_/api/Agent/memory/{id}/ingest (feedbackId-based)
- Search → LLMOps /llmops_/api/Agent/memory/{id}/search (returns systemPromptInjection)
- Patch/delete items → LLMOps /llmops_/api/Memory/{id}/items/{itemId}

LLMOps search returns systemPromptInjection — the formatted string
ready to inject into the agent's system prompt for few-shot retrieval.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full lifecycle test: create index → create feedback → ingest via
LLMOps → search → verify response shape → delete index.

Tests are marked @pytest.mark.e2e and excluded from default runs.
Run with: uv run pytest -m e2e -v (requires UIPATH_URL,
UIPATH_ACCESS_TOKEN, UIPATH_FOLDER_KEY env vars).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- LLMOps endpoints use llmopstenant_ prefix (not llmops_) through
  the platform gateway — llmops_ returns 302, llmopstenant_ routes
  correctly
- SearchField.settings is now required (default FieldSettings()) per
  LLMOps API contract which requires the settings field on each field
- Fixed E2E test feedback endpoint to use llmopstenant_ prefix

E2E results: 5 passed, 1 skipped (ingest skipped because synthetic
trace/span IDs don't exist in LLMOps trace store — needs real agent
trace for full lifecycle test)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Adds e2e-uipath-platform job to test-packages.yml
- Runs on uipath-platform changes, Python 3.11, ubuntu-latest
- Uses ALPHA_TEST_CLIENT_ID/CLIENT_SECRET for auth (same as integration tests)
- Reads memory folder from UIPATH_MEMORY_FOLDER secret
- E2E results are non-blocking in the test gate (informational)
- Test supports both token-based (local) and client credentials (CI) auth

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per PR review: _resolve_folder now matches ContextGroundingService
pattern — resolves folder_key from folder_path via FolderService
when UIPATH_FOLDER_KEY is not set (serverless/robot environments
only have UIPATH_FOLDER_PATH).

MemoryService now takes a FolderService dependency, wired through
the UiPath class.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove methods not used by any frontend or backend flow:
- get(), delete_index() (neither frontend uses; backend uses v1.1)
- ingest() (IM-internal, requires feedback_id from trace pipeline)
- patch_memory(), delete_memory() (wrong endpoints, IM admin ops)

Remove unused models: FeedbackMemoryStatus, EpisodicMemoryPatchRequest,
MemoryIngestRequest/Response, MemoryItemUpdateRequest/Response.

Add escalation memory methods used by the backend agentic loop:
- escalation_search() -> POST /api/Agent/memory/{id}/escalation/search
- escalation_ingest() -> POST /api/Agent/memory/{id}/escalation/ingest

Add models: EscalationMemoryIngestRequest, EscalationMemorySearchResponse,
EscalationMemoryMatch, CachedRecall (matching backend C# contracts).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename _ECS_BASE to _MEMORY_SPACES_BASE for clarity
- Add full docstrings (Args/Returns) to all async methods to match
  their sync counterparts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mjnovice and others added 5 commits April 17, 2026 10:10
Cover all 5 public methods: create, list, search,
escalation_search, escalation_ingest. Tests verify correct
URL construction, request body serialization, folder header
propagation, and response deserialization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EpisodicMemoryField was for ECS ingest (removed). EpisodicMemoryStatus
is not referenced by any service method or model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace "index" terminology with "memory space" throughout the
memory module to match the product language used by frontends
and backend (MemorySpaceResponse, MemorySpace, etc.).

Renames:
- EpisodicMemoryIndex → MemorySpace
- EpisodicMemoryListResponse → MemorySpaceListResponse
- EpisodicMemoryCreateRequest → MemorySpaceCreateRequest

All docstrings updated to use "memory space" instead of
"memory index".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mjnovice mjnovice force-pushed the feat/memory-service-scaffold branch from fea6d4e to 6347598 Compare April 17, 2026 17:12
0.1.30 already published to PyPI — bump to next available version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mjnovice added a commit that referenced this pull request Apr 17, 2026
This PR contains no code changes — it exists solely to prove that the
langchain-cross and Test Langchain CI failures are repo-wide, not
caused by the memory-service-scaffold branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mjnovice mjnovice removed the test:uipath-langchain Triggers tests in the uipath-langchain-python repository label Apr 17, 2026
@mjnovice mjnovice merged commit 6d1ca97 into main Apr 17, 2026
82 of 122 checks passed
@mjnovice mjnovice deleted the feat/memory-service-scaffold branch April 17, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants