Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dashscope/agentstudio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
CursorPage,
)
from .types import (
Memory,
MemoryStore,
MemoryVersion,
Message,
PermissionPolicy,
SecurityAlert,
Expand Down Expand Up @@ -117,6 +120,9 @@
"CursorPage",
"AsyncCursorPage",
# unified message type
"Memory",
"MemoryStore",
"MemoryVersion",
"Message",
"PermissionPolicy",
"SecurityAlert",
Expand Down
6 changes: 6 additions & 0 deletions dashscope/agentstudio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
AsyncEnvironments,
)
from dashscope.agentstudio.resources.files import Files, AsyncFiles
from dashscope.agentstudio.resources.memory_stores import (
MemoryStores,
AsyncMemoryStores,
)
from dashscope.agentstudio.resources.security import Security, AsyncSecurity
from dashscope.agentstudio.resources.sessions import Sessions, AsyncSessions
from dashscope.agentstudio.resources.skills import Skills, AsyncSkills
Expand Down Expand Up @@ -144,6 +148,7 @@ def __init__(
self.files = Files(self)
self.skills = Skills(self)
self.vaults = Vaults(self)
self.memory_stores = MemoryStores(self)
self.webhook_endpoints = WebhookEndpoints(self)
self.security = Security(self)

Expand Down Expand Up @@ -218,6 +223,7 @@ def __init__(
self.files = AsyncFiles(self)
self.skills = AsyncSkills(self)
self.vaults = AsyncVaults(self)
self.memory_stores = AsyncMemoryStores(self)
self.webhook_endpoints = AsyncWebhookEndpoints(self)
self.security = AsyncSecurity(self)

Expand Down
43 changes: 40 additions & 3 deletions dashscope/agentstudio/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@


class CursorPage(Generic[T]):
"""Synchronous page over an opaque ``page`` cursor."""
"""Synchronous page over an opaque ``page`` cursor.

``extra`` preserves any additional top-level fields the list
envelope carried beyond ``data`` / ``next_page`` (forward
compatibility when the server adds fields); ``extra`` is per page
and does not participate in auto-pagination.
"""

def __init__(
self,
Expand All @@ -34,11 +40,13 @@ def __init__(
next_page: Optional[str],
request_id: Optional[str],
fetch_next: Optional[Callable[[str], "CursorPage[T]"]] = None,
extra: Optional[Dict[str, Any]] = None,
) -> None:
self.data = data
self.next_page = next_page
self.request_id = request_id
self._fetch_next = fetch_next
self.extra: Dict[str, Any] = dict(extra or {})

def has_next(self) -> bool:
return bool(self.next_page) and self._fetch_next is not None
Expand Down Expand Up @@ -66,9 +74,20 @@ def __len__(self) -> int:
"""
return len(self.data)

@property
def prefixes(self) -> List[str]:
"""Directory prefixes of a tree-style listing (memory only)."""

raw = self.extra.get("prefixes") or []
return list(raw) if isinstance(raw, (list, tuple)) else []


class AsyncCursorPage(Generic[T]):
"""Asynchronous page over an opaque ``page`` cursor."""
"""Asynchronous page over an opaque ``page`` cursor.

See :class:`CursorPage` for the ``extra`` forward-compatibility
bag.
"""

def __init__(
self,
Expand All @@ -77,11 +96,13 @@ def __init__(
next_page: Optional[str],
request_id: Optional[str],
fetch_next: Optional[Callable[[str], "AsyncCursorPage[T]"]] = None,
extra: Optional[Dict[str, Any]] = None,
) -> None:
self.data = data
self.next_page = next_page
self.request_id = request_id
self._fetch_next = fetch_next
self.extra: Dict[str, Any] = dict(extra or {})

def has_next(self) -> bool:
return bool(self.next_page) and self._fetch_next is not None
Expand Down Expand Up @@ -115,6 +136,13 @@ def __len__(self) -> int:
"""
return len(self.data)

@property
def prefixes(self) -> List[str]:
"""Directory prefixes of a tree-style listing (memory only)."""

raw = self.extra.get("prefixes") or []
return list(raw) if isinstance(raw, (list, tuple)) else []


def build_page(
*,
Expand All @@ -124,16 +152,25 @@ def build_page(
request_id: Optional[str] = None,
page_cls: type = CursorPage,
) -> Any:
"""Hydrate a page object from a normalized payload."""
"""Hydrate a page object from a normalized payload.

Envelope fields beyond ``data`` / ``next_page`` are preserved on
the page's ``extra`` forward-compatibility bag (mirrors
``BaseModel.extra``).
"""

items_raw = payload.get("data") or []
items: List[T] = [
item_factory(it) for it in items_raw if isinstance(it, dict)
]
next_page = payload.get("next_page")
extra = {
k: v for k, v in payload.items() if k not in ("data", "next_page")
}
return page_cls(
data=items,
next_page=next_page,
request_id=request_id,
fetch_next=fetch_next,
extra=extra,
)
14 changes: 14 additions & 0 deletions dashscope/agentstudio/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
AsyncEnvironments,
)
from dashscope.agentstudio.resources.files import Files, AsyncFiles
from dashscope.agentstudio.resources.memory_stores import (
AsyncMemories,
AsyncMemoryStores,
AsyncMemoryVersions,
Memories,
MemoryStores,
MemoryVersions,
)
from dashscope.agentstudio.resources.session_events import (
AsyncSessionEvents,
SessionEvents,
Expand Down Expand Up @@ -74,6 +82,12 @@
"AsyncSessionEvents",
"Vaults",
"AsyncVaults",
"MemoryStores",
"AsyncMemoryStores",
"Memories",
"AsyncMemories",
"MemoryVersions",
"AsyncMemoryVersions",
"WebhookEndpoints",
"AsyncWebhookEndpoints",
"_TypedEventStream",
Expand Down
47 changes: 47 additions & 0 deletions dashscope/agentstudio/resources/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
DeploymentRun,
Environment,
File,
Memory,
MemoryStore,
MemoryVersion,
ServerEvent,
Session,
SessionResource,
Expand Down Expand Up @@ -103,6 +106,18 @@ def _coerce_deployment_run(payload: Mapping[str, Any]) -> DeploymentRun:
return DeploymentRun(**dict(payload))


def _coerce_memory_store(payload: Mapping[str, Any]) -> MemoryStore:
return MemoryStore(**dict(payload))


def _coerce_memory(payload: Mapping[str, Any]) -> Memory:
return Memory(**dict(payload))


def _coerce_memory_version(payload: Mapping[str, Any]) -> MemoryVersion:
return MemoryVersion(**dict(payload))


# ---------------------------------------------------------------------------
# Path helpers
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -138,3 +153,35 @@ def _session_thread_events_path(session_id: str, thread_id: str) -> str:

def _session_thread_archive_path(session_id: str, thread_id: str) -> str:
return f"/sessions/{session_id}/threads/{thread_id}/archive"


def _memory_stores_path() -> str:
return "/memory_stores"


def _memory_store_item_path(store_id: str) -> str:
return f"/memory_stores/{store_id}"


def _memory_store_archive_path(store_id: str) -> str:
return f"/memory_stores/{store_id}/archive"


def _memories_path(store_id: str) -> str:
return f"/memory_stores/{store_id}/memories"


def _memory_item_path(store_id: str, memory_id: str) -> str:
return f"/memory_stores/{store_id}/memories/{memory_id}"


def _memory_versions_path(store_id: str) -> str:
return f"/memory_stores/{store_id}/memory_versions"


def _memory_version_item_path(store_id: str, version_id: str) -> str:
return f"/memory_stores/{store_id}/memory_versions/{version_id}"


def _memory_version_redact_path(store_id: str, version_id: str) -> str:
return f"/memory_stores/{store_id}/memory_versions/{version_id}/redact"
Loading
Loading