Skip to content

Commit df202b1

Browse files
authored
Merge branch 'main' into dev/sdk-cli-1
2 parents 7f4b318 + c0d7a0b commit df202b1

51 files changed

Lines changed: 8282 additions & 109 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,8 @@ cython_debug/
169169

170170
# PyPI configuration file
171171
.pypirc
172+
173+
# acli
174+
.acli
175+
176+
.idea

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Changelog
2+
3+
## v1.26.2 (2025-01-13)
4+
5+
### Bug Fixes
6+
- SSE idle_timeout uses queue+thread to actually unblock iter_sse()
7+
- Align SDK params with server API and add SSE wall-clock timeout
8+
- Resolve parameter shadowing in base_api.py update/put methods
9+
- Resolve dict access errors and URL path issues in 5 CLI commands due to SDK dataclass return types
10+
- Resolve UTF-8 encoding issues in HTTP request bodies
11+
- Address code review findings in files, transport, and models
12+
- Remove dead code, fix __del__ safety, make agents.update version explicit
13+
- Resolve resource leak and exception handling issues in async iterator
14+
- Restore assistants imports in __init__.py for Python 3.8 compatibility
15+
16+
### Features
17+
- Add AgentStudio sub-SDK for managed agents
18+
- Expand CLI commands and harden compatibility
19+
- Add 12 generation parameters and fix Models.get
20+
21+
### Refactoring
22+
- Remove custom tools, add vaults/credentials, region param, stop_reason/session_status properties
23+
- Remove assistants-related CLI commands
24+
25+
### Chores
26+
- Remove .acli and .idea from repository
27+
- Update .gitignore to exclude .acli and .idea

dashscope/agentstudio/__init__.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) Alibaba, Inc. and its affiliates.
3+
"""AgentStudio sub-SDK for the dashscope Python client.
4+
5+
The ``agentstudio`` package wraps the AgentStudio managed-agent HTTP
6+
API. All resource classes are accessed through a client instance::
7+
8+
from dashscope.agentstudio import Client
9+
from dashscope.agentstudio.types import (
10+
user_message, user_tool_result,
11+
)
12+
13+
Example
14+
-------
15+
>>> from dashscope.agentstudio import Client
16+
>>> from dashscope.agentstudio.types import user_message
17+
>>> client = Client(api_key="sk-xxx")
18+
>>> agent = client.agents.create(name="demo", model="qwen-plus")
19+
>>> session = client.sessions.create(agent=agent.id)
20+
>>> client.sessions.events.send(session.id, [user_message("Hello!")])
21+
>>> with client.sessions.events.stream(session.id) as stream:
22+
... for event in stream:
23+
... print(event.type, event.to_dict())
24+
... if event.type == "session_status":
25+
... break
26+
"""
27+
28+
# yapf: disable
29+
30+
from .client import Client, AsyncClient
31+
from .transport import APIResponse, RequestOptions
32+
from . import types
33+
from .exceptions import (
34+
AgentStudioError,
35+
APIConnectionError,
36+
APIStatusError,
37+
APITimeoutError,
38+
AuthenticationError,
39+
ConflictError,
40+
InternalServerError,
41+
InvalidRequestError,
42+
NotFoundError,
43+
OverloadedError,
44+
PermissionDeniedError,
45+
RateLimitError,
46+
StreamClosedError,
47+
StreamError,
48+
)
49+
from .pagination import (
50+
AsyncCursorPage,
51+
CursorPage,
52+
)
53+
from .types import (
54+
Message,
55+
ServerEvent,
56+
user_define_outcome,
57+
user_interrupt,
58+
user_message,
59+
user_tool_confirmation,
60+
user_custom_tool_result,
61+
user_tool_result,
62+
)
63+
from .types.params import (
64+
AgentCreateParams,
65+
AgentUpdateParams,
66+
SessionCreateParams,
67+
SessionUpdateParams,
68+
EnvironmentCreateParams,
69+
EnvironmentUpdateParams,
70+
SessionEventSendParams,
71+
)
72+
73+
__all__ = [
74+
# client
75+
"Client",
76+
"AsyncClient",
77+
# base types
78+
"RequestOptions",
79+
"APIResponse",
80+
# exceptions
81+
"AgentStudioError",
82+
"APIConnectionError",
83+
"APIStatusError",
84+
"APITimeoutError",
85+
"AuthenticationError",
86+
"ConflictError",
87+
"InternalServerError",
88+
"InvalidRequestError",
89+
"NotFoundError",
90+
"OverloadedError",
91+
"PermissionDeniedError",
92+
"RateLimitError",
93+
"StreamError",
94+
"StreamClosedError",
95+
# pagination
96+
"CursorPage",
97+
"AsyncCursorPage",
98+
# unified message type
99+
"Message",
100+
"ServerEvent",
101+
# client event helpers (re-exported for convenience)
102+
"user_message",
103+
"user_interrupt",
104+
"user_tool_confirmation",
105+
"user_custom_tool_result",
106+
"user_tool_result",
107+
"user_define_outcome",
108+
# typing module
109+
"types",
110+
# params (commonly used request-body types)
111+
"AgentCreateParams",
112+
"AgentUpdateParams",
113+
"SessionCreateParams",
114+
"SessionUpdateParams",
115+
"EnvironmentCreateParams",
116+
"EnvironmentUpdateParams",
117+
"SessionEventSendParams",
118+
]

dashscope/agentstudio/client.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) Alibaba, Inc. and its affiliates.
3+
"""AgentStudio client classes."""
4+
5+
from __future__ import annotations
6+
7+
import os
8+
from typing import Any, Optional, Tuple, Union
9+
10+
import httpx
11+
12+
from dashscope.agentstudio.resources.agents import Agents, AsyncAgents
13+
from dashscope.agentstudio.resources.environments import (
14+
Environments,
15+
AsyncEnvironments,
16+
)
17+
from dashscope.agentstudio.resources.files import Files, AsyncFiles
18+
from dashscope.agentstudio.resources.sessions import Sessions, AsyncSessions
19+
from dashscope.agentstudio.resources.skills import Skills, AsyncSkills
20+
from dashscope.agentstudio.resources.vaults import Vaults, AsyncVaults
21+
from dashscope.agentstudio.constants import (
22+
AGENTSTUDIO_BASE_URL_TEMPLATE,
23+
AGENTSTUDIO_DEFAULT_REGION,
24+
AGENTSTUDIO_DEFAULT_TIMEOUT,
25+
AGENTSTUDIO_MAX_RETRIES,
26+
)
27+
from dashscope.agentstudio.transport import SyncTransport, AsyncTransport
28+
from dashscope.common.api_key import get_default_api_key
29+
30+
31+
def _resolve_base_url(
32+
explicit_url: Optional[str],
33+
workspace: Optional[str],
34+
region: Optional[str] = None,
35+
) -> str:
36+
"""Resolve the base URL.
37+
38+
Priority:
39+
1. explicit base_url parameter (full URL)
40+
2. DASHSCOPE_AGENTSTUDIO_URL / AGENTSTUDIO_URL env
41+
3. Build from workspace + region template
42+
"""
43+
if explicit_url:
44+
return explicit_url
45+
env_url = os.environ.get("DASHSCOPE_AGENTSTUDIO_URL") or os.environ.get(
46+
"AGENTSTUDIO_URL",
47+
)
48+
if env_url:
49+
return env_url
50+
# Build from workspace + region
51+
ws = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
52+
if not ws:
53+
raise ValueError(
54+
"workspace is required when base_url is not provided "
55+
"(pass workspace='ws_xxx' or set DASHSCOPE_WORKSPACE env var "
56+
"or use base_url=... to override)",
57+
)
58+
rgn = region or AGENTSTUDIO_DEFAULT_REGION
59+
return AGENTSTUDIO_BASE_URL_TEMPLATE.format(
60+
workspace=ws,
61+
region=rgn,
62+
)
63+
64+
65+
def _user_agent(base_url: str) -> str:
66+
try:
67+
from dashscope.version import __version__
68+
except Exception:
69+
__version__ = "0.0.0"
70+
return f"dashscope-agentstudio-python/{__version__} (+{base_url})"
71+
72+
73+
class Client:
74+
"""Synchronous AgentStudio client.
75+
76+
Usage::
77+
78+
from dashscope.agentstudio import Client
79+
80+
client = Client(api_key="sk-xxx", workspace="my-ws")
81+
agent = client.agents.create(name="demo", model="qwen-max")
82+
session = client.sessions.create(agent=agent.id)
83+
with client.sessions.events.stream(session.id) as stream:
84+
for event in stream:
85+
print(event.type)
86+
"""
87+
88+
def __init__(
89+
self,
90+
*,
91+
api_key: Optional[str] = None,
92+
workspace: Optional[str] = None,
93+
region: Optional[str] = None,
94+
base_url: Optional[str] = None,
95+
uid: Optional[str] = None,
96+
timeout: Optional[
97+
Union[float, httpx.Timeout, Tuple[float, float]]
98+
] = None,
99+
max_retries: int = AGENTSTUDIO_MAX_RETRIES,
100+
http_client: Optional[httpx.Client] = None,
101+
) -> None:
102+
resolved_workspace = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
103+
resolved_base = _resolve_base_url(
104+
base_url,
105+
resolved_workspace,
106+
region,
107+
)
108+
self.transport = SyncTransport(
109+
base_url=resolved_base,
110+
api_key=api_key or get_default_api_key(),
111+
workspace=resolved_workspace,
112+
uid=uid or os.environ.get("DASHSCOPE_UID"),
113+
user_agent=_user_agent(resolved_base),
114+
timeout=timeout or AGENTSTUDIO_DEFAULT_TIMEOUT,
115+
max_retries=max_retries,
116+
http_client=http_client,
117+
)
118+
self.agents = Agents(self)
119+
self.sessions = Sessions(self)
120+
self.environments = Environments(self)
121+
self.files = Files(self)
122+
self.skills = Skills(self)
123+
self.vaults = Vaults(self)
124+
125+
def close(self) -> None:
126+
self.transport.close()
127+
128+
def __enter__(self) -> "Client":
129+
return self
130+
131+
def __exit__(self, *exc: Any) -> None:
132+
self.close()
133+
134+
def __del__(self) -> None:
135+
try:
136+
self.close()
137+
except Exception:
138+
pass
139+
140+
141+
class AsyncClient:
142+
"""Asynchronous AgentStudio client.
143+
144+
Usage::
145+
146+
from dashscope.agentstudio import AsyncClient
147+
148+
client = AsyncClient(api_key="sk-xxx", workspace="my-ws")
149+
agent = await client.agents.create(
150+
name="demo", model="qwen-max",
151+
)
152+
session = await client.sessions.create(agent=agent.id)
153+
async with client.sessions.events.stream(session.id) as stream:
154+
async for event in stream:
155+
print(event.type)
156+
"""
157+
158+
def __init__(
159+
self,
160+
*,
161+
api_key: Optional[str] = None,
162+
workspace: Optional[str] = None,
163+
region: Optional[str] = None,
164+
base_url: Optional[str] = None,
165+
uid: Optional[str] = None,
166+
timeout: Optional[
167+
Union[float, httpx.Timeout, Tuple[float, float]]
168+
] = None,
169+
max_retries: int = AGENTSTUDIO_MAX_RETRIES,
170+
http_client: Optional[httpx.AsyncClient] = None,
171+
) -> None:
172+
resolved_workspace = workspace or os.environ.get("DASHSCOPE_WORKSPACE")
173+
resolved_base = _resolve_base_url(
174+
base_url,
175+
resolved_workspace,
176+
region,
177+
)
178+
self.transport = AsyncTransport(
179+
base_url=resolved_base,
180+
api_key=api_key or get_default_api_key(),
181+
workspace=resolved_workspace,
182+
uid=uid or os.environ.get("DASHSCOPE_UID"),
183+
user_agent=_user_agent(resolved_base),
184+
timeout=timeout or AGENTSTUDIO_DEFAULT_TIMEOUT,
185+
max_retries=max_retries,
186+
http_client=http_client,
187+
)
188+
self.agents = AsyncAgents(self)
189+
self.sessions = AsyncSessions(self)
190+
self.environments = AsyncEnvironments(self)
191+
self.files = AsyncFiles(self)
192+
self.skills = AsyncSkills(self)
193+
self.vaults = AsyncVaults(self)
194+
195+
async def aclose(self) -> None:
196+
await self.transport.aclose()
197+
198+
async def __aenter__(self) -> "AsyncClient":
199+
return self
200+
201+
async def __aexit__(self, *exc: Any) -> None:
202+
await self.aclose()
203+
204+
def __del__(self) -> None:
205+
try:
206+
self.transport.close()
207+
except Exception:
208+
pass

0 commit comments

Comments
 (0)