Skip to content
118 changes: 118 additions & 0 deletions dashscope/agentstudio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# Copyright (c) Alibaba, Inc. and its affiliates.
"""AgentStudio sub-SDK for the dashscope Python client.

The ``agentstudio`` package wraps the AgentStudio managed-agent HTTP
API. All resource classes are accessed through a client instance::

from dashscope.agentstudio import Client
from dashscope.agentstudio.types import (
user_message, user_tool_result,
)

Example
-------
>>> from dashscope.agentstudio import Client
>>> from dashscope.agentstudio.types import user_message
>>> client = Client(api_key="sk-xxx")
>>> agent = client.agents.create(name="demo", model="qwen-plus")
>>> session = client.sessions.create(agent=agent.id)
>>> client.sessions.events.send(session.id, [user_message("Hello!")])
>>> with client.sessions.events.stream(session.id) as stream:
... for event in stream:
... print(event.type, event.to_dict())
... if event.type == "session_status":
... break
"""

# yapf: disable

from .client import Client, AsyncClient
from .transport import APIResponse, RequestOptions
from . import types
from .exceptions import (
AgentStudioError,
APIConnectionError,
APIStatusError,
APITimeoutError,
AuthenticationError,
ConflictError,
InternalServerError,
InvalidRequestError,
NotFoundError,
OverloadedError,
PermissionDeniedError,
RateLimitError,
StreamClosedError,
StreamError,
)
from .pagination import (
AsyncCursorPage,
CursorPage,
)
from .types import (
Message,
ServerEvent,
user_define_outcome,
user_interrupt,
user_message,
user_tool_confirmation,
user_custom_tool_result,
user_tool_result,
)
from .types.params import (
AgentCreateParams,
AgentUpdateParams,
SessionCreateParams,
SessionUpdateParams,
EnvironmentCreateParams,
EnvironmentUpdateParams,
SessionEventSendParams,
)

__all__ = [
# client
"Client",
"AsyncClient",
# base types
"RequestOptions",
"APIResponse",
# exceptions
"AgentStudioError",
"APIConnectionError",
"APIStatusError",
"APITimeoutError",
"AuthenticationError",
"ConflictError",
"InternalServerError",
"InvalidRequestError",
"NotFoundError",
"OverloadedError",
"PermissionDeniedError",
"RateLimitError",
"StreamError",
"StreamClosedError",
# pagination
"CursorPage",
"AsyncCursorPage",
# unified message type
"Message",
"ServerEvent",
# client event helpers (re-exported for convenience)
"user_message",
"user_interrupt",
"user_tool_confirmation",
"user_custom_tool_result",
"user_tool_result",
"user_define_outcome",
# typing module
"types",
# params (commonly used request-body types)
"AgentCreateParams",
"AgentUpdateParams",
"SessionCreateParams",
"SessionUpdateParams",
"EnvironmentCreateParams",
"EnvironmentUpdateParams",
"SessionEventSendParams",
]
208 changes: 208 additions & 0 deletions dashscope/agentstudio/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# -*- coding: utf-8 -*-
# Copyright (c) Alibaba, Inc. and its affiliates.
"""AgentStudio client classes."""

from __future__ import annotations

import os
from typing import Any, Optional, Tuple, Union

import httpx

from dashscope.agentstudio.resources.agents import Agents, AsyncAgents
from dashscope.agentstudio.resources.environments import (
Environments,
AsyncEnvironments,
)
from dashscope.agentstudio.resources.files import Files, AsyncFiles
from dashscope.agentstudio.resources.sessions import Sessions, AsyncSessions
from dashscope.agentstudio.resources.skills import Skills, AsyncSkills
from dashscope.agentstudio.resources.vaults import Vaults, AsyncVaults
from dashscope.agentstudio.constants import (
AGENTSTUDIO_BASE_URL_TEMPLATE,
AGENTSTUDIO_DEFAULT_REGION,
AGENTSTUDIO_DEFAULT_TIMEOUT,
AGENTSTUDIO_MAX_RETRIES,
)
from dashscope.agentstudio.transport import SyncTransport, AsyncTransport
from dashscope.common.api_key import get_default_api_key


def _resolve_base_url(
explicit_url: Optional[str],
workspace: Optional[str],
region: Optional[str] = None,
) -> str:
"""Resolve the base URL.

Priority:
1. explicit base_url parameter (full URL)
2. DASHSCOPE_AGENTSTUDIO_URL / AGENTSTUDIO_URL env
3. Build from workspace + region template
"""
if explicit_url:
return explicit_url
env_url = os.environ.get("DASHSCOPE_AGENTSTUDIO_URL") or os.environ.get(
"AGENTSTUDIO_URL",
)
if env_url:
return env_url
# Build from workspace + region
ws = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
if not ws:
raise ValueError(
"workspace is required when base_url is not provided "
"(pass workspace='ws_xxx' or set DASHSCOPE_WORKSPACE env var "
"or use base_url=... to override)",
)
rgn = region or AGENTSTUDIO_DEFAULT_REGION
return AGENTSTUDIO_BASE_URL_TEMPLATE.format(
workspace=ws,
region=rgn,
)


def _user_agent(base_url: str) -> str:
try:
from dashscope.version import __version__
except Exception:
__version__ = "0.0.0"
return f"dashscope-agentstudio-python/{__version__} (+{base_url})"


class Client:
"""Synchronous AgentStudio client.

Usage::

from dashscope.agentstudio import Client

client = Client(api_key="sk-xxx", workspace="my-ws")
agent = client.agents.create(name="demo", model="qwen-max")
session = client.sessions.create(agent=agent.id)
with client.sessions.events.stream(session.id) as stream:
for event in stream:
print(event.type)
"""

def __init__(
self,
*,
api_key: Optional[str] = None,
workspace: Optional[str] = None,
region: Optional[str] = None,
base_url: Optional[str] = None,
uid: Optional[str] = None,
timeout: Optional[
Union[float, httpx.Timeout, Tuple[float, float]]
] = None,
max_retries: int = AGENTSTUDIO_MAX_RETRIES,
http_client: Optional[httpx.Client] = None,
) -> None:
resolved_workspace = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
resolved_base = _resolve_base_url(
base_url,
resolved_workspace,
region,
)
self.transport = SyncTransport(
base_url=resolved_base,
api_key=api_key or get_default_api_key(),
workspace=resolved_workspace,
uid=uid or os.environ.get("DASHSCOPE_UID"),
user_agent=_user_agent(resolved_base),
timeout=timeout or AGENTSTUDIO_DEFAULT_TIMEOUT,
max_retries=max_retries,
http_client=http_client,
)
self.agents = Agents(self)
self.sessions = Sessions(self)
self.environments = Environments(self)
self.files = Files(self)
self.skills = Skills(self)
self.vaults = Vaults(self)

def close(self) -> None:
self.transport.close()

def __enter__(self) -> "Client":
return self

def __exit__(self, *exc: Any) -> None:
self.close()

def __del__(self) -> None:
try:
self.close()
except Exception:
pass


class AsyncClient:
"""Asynchronous AgentStudio client.

Usage::

from dashscope.agentstudio import AsyncClient

client = AsyncClient(api_key="sk-xxx", workspace="my-ws")
agent = await client.agents.create(
name="demo", model="qwen-max",
)
session = await client.sessions.create(agent=agent.id)
async with client.sessions.events.stream(session.id) as stream:
async for event in stream:
print(event.type)
"""

def __init__(
self,
*,
api_key: Optional[str] = None,
workspace: Optional[str] = None,
region: Optional[str] = None,
base_url: Optional[str] = None,
uid: Optional[str] = None,
timeout: Optional[
Union[float, httpx.Timeout, Tuple[float, float]]
] = None,
max_retries: int = AGENTSTUDIO_MAX_RETRIES,
http_client: Optional[httpx.AsyncClient] = None,
) -> None:
resolved_workspace = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
resolved_base = _resolve_base_url(
base_url,
resolved_workspace,
region,
)
self.transport = AsyncTransport(
base_url=resolved_base,
api_key=api_key or get_default_api_key(),
workspace=resolved_workspace,
uid=uid or os.environ.get("DASHSCOPE_UID"),
user_agent=_user_agent(resolved_base),
timeout=timeout or AGENTSTUDIO_DEFAULT_TIMEOUT,
max_retries=max_retries,
http_client=http_client,
)
self.agents = AsyncAgents(self)
self.sessions = AsyncSessions(self)
self.environments = AsyncEnvironments(self)
self.files = AsyncFiles(self)
self.skills = AsyncSkills(self)
self.vaults = AsyncVaults(self)

async def aclose(self) -> None:
await self.transport.aclose()

async def __aenter__(self) -> "AsyncClient":
return self

async def __aexit__(self, *exc: Any) -> None:
await self.aclose()

def __del__(self) -> None:
try:
self.transport.close()
except Exception:
pass
Loading
Loading