Skip to content

Commit ca10a2f

Browse files
mjnoviceclaude
andcommitted
feat: add @resource_override and folder_path support to MemoryService
- Apply @resource_override(resource_type="memorySpace") to create/create_async so folder bindings are automatically resolved from resource overwrites - Add folder_path parameter to all public methods (create, list, search, escalation_search, escalation_ingest and their async variants) - Plumb folder_path through to private spec builders via _resolve_folder This aligns memory spaces with how other resources (assets, ECS indexes) handle resource binding resolution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f82df05 commit ca10a2f

1 file changed

Lines changed: 43 additions & 15 deletions

File tree

packages/uipath-platform/src/uipath/platform/memory/_memory_service.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from uipath.core.tracing import traced
1111

1212
from ..common._base_service import BaseService
13+
from ..common._bindings import resource_override
1314
from ..common._config import UiPathApiConfig
1415
from ..common._execution_context import UiPathExecutionContext
1516
from ..common._folder_context import FolderContext, header_folder
@@ -50,13 +51,15 @@ def __init__(
5051

5152
# ── Memory space operations (ECS) ──────────────────────────────────
5253

54+
@resource_override(resource_type="memorySpace")
5355
@traced(name="memory_create", run_type="uipath")
5456
def create(
5557
self,
5658
name: str,
5759
description: Optional[str] = None,
5860
is_encrypted: Optional[bool] = None,
5961
folder_key: Optional[str] = None,
62+
folder_path: Optional[str] = None,
6063
) -> MemorySpace:
6164
"""Create a new memory space.
6265
@@ -65,11 +68,12 @@ def create(
6568
description: Optional description (max 1024 chars).
6669
is_encrypted: Whether the memory space should be encrypted.
6770
folder_key: The folder key for the operation.
71+
folder_path: The folder path for the operation.
6872
6973
Returns:
7074
MemorySpace: The created memory space.
7175
"""
72-
spec = self._create_spec(name, description, is_encrypted, folder_key)
76+
spec = self._create_spec(name, description, is_encrypted, folder_key, folder_path)
7377
response = self.request(
7478
spec.method,
7579
spec.endpoint,
@@ -78,13 +82,15 @@ def create(
7882
).json()
7983
return MemorySpace.model_validate(response)
8084

85+
@resource_override(resource_type="memorySpace")
8186
@traced(name="memory_create", run_type="uipath")
8287
async def create_async(
8388
self,
8489
name: str,
8590
description: Optional[str] = None,
8691
is_encrypted: Optional[bool] = None,
8792
folder_key: Optional[str] = None,
93+
folder_path: Optional[str] = None,
8894
) -> MemorySpace:
8995
"""Asynchronously create a new memory space.
9096
@@ -93,11 +99,12 @@ async def create_async(
9399
description: Optional description (max 1024 chars).
94100
is_encrypted: Whether the memory space should be encrypted.
95101
folder_key: The folder key for the operation.
102+
folder_path: The folder path for the operation.
96103
97104
Returns:
98105
MemorySpace: The created memory space.
99106
"""
100-
spec = self._create_spec(name, description, is_encrypted, folder_key)
107+
spec = self._create_spec(name, description, is_encrypted, folder_key, folder_path)
101108
response = (
102109
await self.request_async(
103110
spec.method,
@@ -116,6 +123,7 @@ def list(
116123
top: Optional[int] = None,
117124
skip: Optional[int] = None,
118125
folder_key: Optional[str] = None,
126+
folder_path: Optional[str] = None,
119127
) -> MemorySpaceListResponse:
120128
"""List memory spaces with optional OData query parameters.
121129
@@ -125,11 +133,12 @@ def list(
125133
top: Maximum number of results.
126134
skip: Number of results to skip.
127135
folder_key: The folder key for the operation.
136+
folder_path: The folder path for the operation.
128137
129138
Returns:
130139
MemorySpaceListResponse: The list of memory spaces.
131140
"""
132-
spec = self._list_spec(filter, orderby, top, skip, folder_key)
141+
spec = self._list_spec(filter, orderby, top, skip, folder_key, folder_path)
133142
response = self.request(
134143
spec.method,
135144
spec.endpoint,
@@ -146,6 +155,7 @@ async def list_async(
146155
top: Optional[int] = None,
147156
skip: Optional[int] = None,
148157
folder_key: Optional[str] = None,
158+
folder_path: Optional[str] = None,
149159
) -> MemorySpaceListResponse:
150160
"""Asynchronously list memory spaces.
151161
@@ -155,11 +165,12 @@ async def list_async(
155165
top: Maximum number of results.
156166
skip: Number of results to skip.
157167
folder_key: The folder key for the operation.
168+
folder_path: The folder path for the operation.
158169
159170
Returns:
160171
MemorySpaceListResponse: The list of memory spaces.
161172
"""
162-
spec = self._list_spec(filter, orderby, top, skip, folder_key)
173+
spec = self._list_spec(filter, orderby, top, skip, folder_key, folder_path)
163174
response = (
164175
await self.request_async(
165176
spec.method,
@@ -178,6 +189,7 @@ def search(
178189
memory_space_id: str,
179190
request: MemorySearchRequest,
180191
folder_key: Optional[str] = None,
192+
folder_path: Optional[str] = None,
181193
) -> MemorySearchResponse:
182194
"""Search a memory space via LLMOps.
183195
@@ -188,11 +200,12 @@ def search(
188200
memory_space_id: The GUID of the memory space.
189201
request: The search request payload.
190202
folder_key: The folder key for the operation.
203+
folder_path: The folder path for the operation.
191204
192205
Returns:
193206
MemorySearchResponse: Results, metadata, and system prompt injection.
194207
"""
195-
spec = self._search_spec(memory_space_id, folder_key)
208+
spec = self._search_spec(memory_space_id, folder_key, folder_path)
196209
response = self.request(
197210
spec.method,
198211
spec.endpoint,
@@ -207,6 +220,7 @@ async def search_async(
207220
memory_space_id: str,
208221
request: MemorySearchRequest,
209222
folder_key: Optional[str] = None,
223+
folder_path: Optional[str] = None,
210224
) -> MemorySearchResponse:
211225
"""Asynchronously search a memory space via LLMOps.
212226
@@ -217,11 +231,12 @@ async def search_async(
217231
memory_space_id: The GUID of the memory space.
218232
request: The search request payload.
219233
folder_key: The folder key for the operation.
234+
folder_path: The folder path for the operation.
220235
221236
Returns:
222237
MemorySearchResponse: Results, metadata, and system prompt injection.
223238
"""
224-
spec = self._search_spec(memory_space_id, folder_key)
239+
spec = self._search_spec(memory_space_id, folder_key, folder_path)
225240
response = (
226241
await self.request_async(
227242
spec.method,
@@ -240,6 +255,7 @@ def escalation_search(
240255
memory_space_id: str,
241256
request: MemorySearchRequest,
242257
folder_key: Optional[str] = None,
258+
folder_path: Optional[str] = None,
243259
) -> EscalationMemorySearchResponse:
244260
"""Search escalation memory for previously resolved outcomes.
245261
@@ -250,11 +266,12 @@ def escalation_search(
250266
memory_space_id: The GUID of the memory space.
251267
request: The search request payload (same as regular search).
252268
folder_key: The folder key for the operation.
269+
folder_path: The folder path for the operation.
253270
254271
Returns:
255272
EscalationMemorySearchResponse: Matched escalation outcomes.
256273
"""
257-
spec = self._escalation_search_spec(memory_space_id, folder_key)
274+
spec = self._escalation_search_spec(memory_space_id, folder_key, folder_path)
258275
response = self.request(
259276
spec.method,
260277
spec.endpoint,
@@ -269,6 +286,7 @@ async def escalation_search_async(
269286
memory_space_id: str,
270287
request: MemorySearchRequest,
271288
folder_key: Optional[str] = None,
289+
folder_path: Optional[str] = None,
272290
) -> EscalationMemorySearchResponse:
273291
"""Asynchronously search escalation memory for previously resolved outcomes.
274292
@@ -279,11 +297,12 @@ async def escalation_search_async(
279297
memory_space_id: The GUID of the memory space.
280298
request: The search request payload (same as regular search).
281299
folder_key: The folder key for the operation.
300+
folder_path: The folder path for the operation.
282301
283302
Returns:
284303
EscalationMemorySearchResponse: Matched escalation outcomes.
285304
"""
286-
spec = self._escalation_search_spec(memory_space_id, folder_key)
305+
spec = self._escalation_search_spec(memory_space_id, folder_key, folder_path)
287306
response = (
288307
await self.request_async(
289308
spec.method,
@@ -300,6 +319,7 @@ def escalation_ingest(
300319
memory_space_id: str,
301320
request: EscalationMemoryIngestRequest,
302321
folder_key: Optional[str] = None,
322+
folder_path: Optional[str] = None,
303323
) -> None:
304324
"""Ingest a resolved escalation outcome into memory.
305325
@@ -310,8 +330,9 @@ def escalation_ingest(
310330
memory_space_id: The GUID of the memory space.
311331
request: The escalation ingest payload.
312332
folder_key: The folder key for the operation.
333+
folder_path: The folder path for the operation.
313334
"""
314-
spec = self._escalation_ingest_spec(memory_space_id, folder_key)
335+
spec = self._escalation_ingest_spec(memory_space_id, folder_key, folder_path)
315336
self.request(
316337
spec.method,
317338
spec.endpoint,
@@ -325,6 +346,7 @@ async def escalation_ingest_async(
325346
memory_space_id: str,
326347
request: EscalationMemoryIngestRequest,
327348
folder_key: Optional[str] = None,
349+
folder_path: Optional[str] = None,
328350
) -> None:
329351
"""Asynchronously ingest a resolved escalation outcome into memory.
330352
@@ -335,8 +357,9 @@ async def escalation_ingest_async(
335357
memory_space_id: The GUID of the memory space.
336358
request: The escalation ingest payload.
337359
folder_key: The folder key for the operation.
360+
folder_path: The folder path for the operation.
338361
"""
339-
spec = self._escalation_ingest_spec(memory_space_id, folder_key)
362+
spec = self._escalation_ingest_spec(memory_space_id, folder_key, folder_path)
340363
await self.request_async(
341364
spec.method,
342365
spec.endpoint,
@@ -379,8 +402,9 @@ def _create_spec(
379402
description: Optional[str],
380403
is_encrypted: Optional[bool],
381404
folder_key: Optional[str] = None,
405+
folder_path: Optional[str] = None,
382406
) -> RequestSpec:
383-
folder_key = self._resolve_folder(folder_key)
407+
folder_key = self._resolve_folder(folder_key, folder_path)
384408
body = MemorySpaceCreateRequest(
385409
name=name,
386410
description=description,
@@ -400,8 +424,9 @@ def _list_spec(
400424
top: Optional[int],
401425
skip: Optional[int],
402426
folder_key: Optional[str] = None,
427+
folder_path: Optional[str] = None,
403428
) -> RequestSpec:
404-
folder_key = self._resolve_folder(folder_key)
429+
folder_key = self._resolve_folder(folder_key, folder_path)
405430
params: dict[str, Any] = {}
406431
if filter is not None:
407432
params["$filter"] = filter
@@ -424,8 +449,9 @@ def _search_spec(
424449
self,
425450
memory_space_id: str,
426451
folder_key: Optional[str] = None,
452+
folder_path: Optional[str] = None,
427453
) -> RequestSpec:
428-
folder_key = self._resolve_folder(folder_key)
454+
folder_key = self._resolve_folder(folder_key, folder_path)
429455
return RequestSpec(
430456
method="POST",
431457
endpoint=Endpoint(f"{_LLMOPS_AGENT_BASE}/{memory_space_id}/search"),
@@ -436,8 +462,9 @@ def _escalation_search_spec(
436462
self,
437463
memory_space_id: str,
438464
folder_key: Optional[str] = None,
465+
folder_path: Optional[str] = None,
439466
) -> RequestSpec:
440-
folder_key = self._resolve_folder(folder_key)
467+
folder_key = self._resolve_folder(folder_key, folder_path)
441468
return RequestSpec(
442469
method="POST",
443470
endpoint=Endpoint(
@@ -450,8 +477,9 @@ def _escalation_ingest_spec(
450477
self,
451478
memory_space_id: str,
452479
folder_key: Optional[str] = None,
480+
folder_path: Optional[str] = None,
453481
) -> RequestSpec:
454-
folder_key = self._resolve_folder(folder_key)
482+
folder_key = self._resolve_folder(folder_key, folder_path)
455483
return RequestSpec(
456484
method="POST",
457485
endpoint=Endpoint(

0 commit comments

Comments
 (0)