Skip to content

Commit fac3cda

Browse files
author
BitsAdmin
committed
Merge branch 'volc_sdk_20251204' into 'integration_2025-12-04_1090671646466'
feat: [development task] ark runtime (1900541) See merge request iaasng/volcengine-python-sdk!956
2 parents a1bb41c + cbfceca commit fac3cda

File tree

9 files changed

+117
-18
lines changed

9 files changed

+117
-18
lines changed

volcenginesdkarkruntime/_client.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
_DEFAULT_MANDATORY_REFRESH_TIMEOUT,
3838
_DEFAULT_STS_TIMEOUT,
3939
_DEFAULT_RESOURCE_TYPE,
40+
_PRESETENDPOINT_RESOURCE_TYPE,
4041
DEFAULT_TIMEOUT,
42+
_BOT_RESOURCE_TYPE,
4143
)
4244
from ._streaming import Stream
4345

@@ -137,12 +139,15 @@ def __init__(
137139
self.files = resources.Files(self)
138140
# self.classification = resources.Classification(self)
139141

140-
def _get_endpoint_sts_token(self, endpoint_id: str):
142+
def _get_endpoint_sts_token(self, endpoint_id: str, project_name: str = None):
141143
if self._sts_token_manager is None:
142144
if self.ak is None or self.sk is None:
143145
raise ArkAPIError("must set ak and sk before get endpoint token.")
144146
self._sts_token_manager = StsTokenManager(self.ak, self.sk, self.region)
145-
return self._sts_token_manager.get(endpoint_id)
147+
resource_type: str = self.get_resource_type_by_endpoint_id(endpoint_id)
148+
if resource_type == _PRESETENDPOINT_RESOURCE_TYPE and (project_name is None or project_name.strip() == ""):
149+
raise ArkAPIError("must set project_name when get preset endpoint token.")
150+
return self._sts_token_manager.get(endpoint_id, resource_type=resource_type, project_name=project_name)
146151

147152
def _get_endpoint_certificate(
148153
self, endpoint_id: str
@@ -179,6 +184,16 @@ def get_model_breaker(self, model_name: str) -> ModelBreaker:
179184
with self.model_breaker_lock:
180185
return self.model_breaker_map[model_name]
181186

187+
def get_resource_type_by_endpoint_id(self, endpoint_id: str) -> str:
188+
if endpoint_id.startswith("ep-m-"):
189+
return _PRESETENDPOINT_RESOURCE_TYPE
190+
if endpoint_id.startswith("ep-"):
191+
return _DEFAULT_RESOURCE_TYPE
192+
if endpoint_id.startswith("bot-"):
193+
return _BOT_RESOURCE_TYPE
194+
# for model id, default to preset endpoint
195+
return _PRESETENDPOINT_RESOURCE_TYPE
196+
182197

183198
class AsyncArk(AsyncAPIClient):
184199
beta: beta.AsyncBeta
@@ -350,6 +365,7 @@ def _protected_refresh(
350365
ttl: int = _DEFAULT_STS_TIMEOUT,
351366
is_mandatory: bool = False,
352367
resource_type: str = _DEFAULT_RESOURCE_TYPE,
368+
project_name: str = None,
353369
):
354370
if ttl < self._advisory_refresh_timeout * 2:
355371
raise ArkAPIError(
@@ -360,7 +376,7 @@ def _protected_refresh(
360376

361377
try:
362378
api_key, expired_time = self._load_api_key(
363-
ep, ttl, resource_type=resource_type
379+
ep, ttl, resource_type=resource_type, project_name=project_name
364380
)
365381
self._endpoint_sts_tokens[ep] = (api_key, expired_time)
366382
except ApiException as e:
@@ -369,7 +385,7 @@ def _protected_refresh(
369385
else:
370386
logging.error("load api key cause error: e={}".format(e))
371387

372-
def _refresh(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE):
388+
def _refresh(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE, project_name: str = None):
373389
if not self._need_refresh(ep, self._advisory_refresh_timeout):
374390
return
375391

@@ -383,7 +399,7 @@ def _refresh(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE):
383399
)
384400

385401
self._protected_refresh(
386-
ep, is_mandatory=is_mandatory_refresh, resource_type=resource_type
402+
ep, is_mandatory=is_mandatory_refresh, resource_type=resource_type, project_name=project_name
387403
)
388404
return
389405
finally:
@@ -394,24 +410,27 @@ def _refresh(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE):
394410
return
395411

396412
self._protected_refresh(
397-
ep, is_mandatory=True, resource_type=resource_type
413+
ep, is_mandatory=True, resource_type=resource_type, project_name=project_name
398414
)
399415

400-
def get(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE) -> str:
401-
self._refresh(ep, resource_type=resource_type)
416+
def get(self, ep: str, resource_type: str = _DEFAULT_RESOURCE_TYPE, project_name: str = None) -> str:
417+
self._refresh(ep, resource_type=resource_type, project_name=project_name)
402418
return self._endpoint_sts_tokens[ep][0]
403419

404420
def _load_api_key(
405421
self,
406422
ep: str,
407423
duration_seconds: int,
408424
resource_type: str = _DEFAULT_RESOURCE_TYPE,
425+
project_name: str = None,
409426
) -> Tuple[str, int]:
410427
get_api_key_request = volcenginesdkark.GetApiKeyRequest(
411428
duration_seconds=duration_seconds,
412429
resource_type=resource_type,
413430
resource_ids=[ep],
414431
)
432+
if project_name is not None and project_name.strip() != "":
433+
get_api_key_request.project_name = project_name
415434
resp: volcenginesdkark.GetApiKeyResponse = self.api_instance.get_api_key(
416435
get_api_key_request
417436
)

volcenginesdkarkruntime/_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
CLIENT_REQUEST_HEADER = "X-Client-Request-Id"
1919
SERVER_REQUEST_HEADER = "X-Request-Id"
2020
ARK_E2E_ENCRYPTION_HEADER = "x-is-encrypted"
21+
ARK_APIKEY_PROJECT_NAME = "X-Project-Name"
2122

2223
DEFAULT_TIMEOUT_SECONDS = 600.0
2324
DEFAULT_CONNECT_TIMEOUT_SECONDS = 60.0
@@ -39,3 +40,5 @@
3940
_DEFAULT_STS_TIMEOUT = 7 * 24 * 60 * 60 # 7 days
4041

4142
_DEFAULT_RESOURCE_TYPE = "endpoint"
43+
_PRESETENDPOINT_RESOURCE_TYPE = "presetendpoint"
44+
_BOT_RESOURCE_TYPE = "bot"

volcenginesdkarkruntime/_utils/_utils.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@
3131
from datetime import date, datetime
3232
from typing_extensions import TypeGuard
3333

34-
import sniffio
35-
3634
from .._types import NotGiven, FileTypes, NotGivenOr
35+
from .._constants import ARK_APIKEY_PROJECT_NAME
3736

3837
_T = TypeVar("_T")
3938
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
@@ -382,6 +381,7 @@ def file_from_path(path: str) -> FileTypes:
382381

383382
def get_async_library() -> str:
384383
try:
384+
import sniffio
385385
return sniffio.current_async_library()
386386
except Exception:
387387
return "false"
@@ -445,12 +445,12 @@ def _insert_sts_token(args, kwargs):
445445
if (
446446
ark_client.api_key is None
447447
and model
448-
and model.startswith("ep-")
448+
and model.startswith("bot-")
449449
and ark_client.ak
450450
and ark_client.sk
451451
):
452452
default_auth_header = {
453-
"Authorization": "Bearer " + ark_client._get_endpoint_sts_token(model)
453+
"Authorization": "Bearer " + ark_client._get_bot_sts_token(model)
454454
}
455455
extra_headers = (
456456
kwargs.get("extra_headers") if kwargs.get("extra_headers") else {}
@@ -459,16 +459,18 @@ def _insert_sts_token(args, kwargs):
459459
elif (
460460
ark_client.api_key is None
461461
and model
462-
and model.startswith("bot-")
463462
and ark_client.ak
464463
and ark_client.sk
465464
):
466-
default_auth_header = {
467-
"Authorization": "Bearer " + ark_client._get_bot_sts_token(model)
468-
}
469465
extra_headers = (
470466
kwargs.get("extra_headers") if kwargs.get("extra_headers") else {}
471467
)
468+
project_name: str = None
469+
if extra_headers is not None and extra_headers.get(ARK_APIKEY_PROJECT_NAME, None) is not None:
470+
project_name = extra_headers[ARK_APIKEY_PROJECT_NAME]
471+
default_auth_header = {
472+
"Authorization": "Bearer " + ark_client._get_endpoint_sts_token(model, project_name)
473+
}
472474
kwargs["extra_headers"] = {**default_auth_header, **extra_headers}
473475

474476

volcenginesdkarkruntime/resources/content_generation/tasks.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ def create(
4646
content: Iterable[CreateTaskContentParam],
4747
callback_url: Optional[str] = None,
4848
return_last_frame: Optional[bool] = None,
49+
service_tier: Optional[str] = None,
50+
execution_expires_after: Optional[int] = None,
4951
extra_headers: Headers | None = None,
5052
extra_query: Query | None = None,
5153
extra_body: Body | None = None,
@@ -58,6 +60,8 @@ def create(
5860
"content": content,
5961
"callback_url": callback_url,
6062
"return_last_frame": return_last_frame,
63+
"service_tier": service_tier,
64+
"execution_expires_after": execution_expires_after,
6165
},
6266
options=make_request_options(
6367
extra_headers=extra_headers,
@@ -99,6 +103,7 @@ def list(
99103
status: str | None = None,
100104
task_ids: Union[List[str], str] | None = None,
101105
model: str | None = None,
106+
service_tier: str | None = None,
102107
extra_headers: Headers | None = None,
103108
extra_body: Body | None = None,
104109
extra_query: Query | None = None,
@@ -113,6 +118,8 @@ def list(
113118
query_params.append(("filter.status", status))
114119
if model:
115120
query_params.append(("filter.model", model))
121+
if service_tier:
122+
query_params.append(("filter.service_tier", service_tier))
116123
if task_ids:
117124
if isinstance(task_ids, str):
118125
task_ids = [task_ids]
@@ -167,6 +174,8 @@ async def create(
167174
content: Iterable[CreateTaskContentParam],
168175
callback_url: Optional[str] = None,
169176
return_last_frame: Optional[bool] = None,
177+
service_tier: Optional[str] = None,
178+
execution_expires_after: Optional[int] = None,
170179
extra_headers: Headers | None = None,
171180
extra_query: Query | None = None,
172181
extra_body: Body | None = None,
@@ -179,6 +188,8 @@ async def create(
179188
"content": content,
180189
"callback_url": callback_url,
181190
"return_last_frame": return_last_frame,
191+
"service_tier": service_tier,
192+
"execution_expires_after": execution_expires_after,
182193
},
183194
options=make_request_options(
184195
extra_headers=extra_headers,
@@ -220,6 +231,7 @@ async def list(
220231
status: str | None = None,
221232
task_ids: Union[List[str], str] | None = None,
222233
model: str | None = None,
234+
service_tier: str | None = None,
223235
extra_headers: Headers | None = None,
224236
extra_body: Body | None = None,
225237
extra_query: Query | None = None,
@@ -234,6 +246,8 @@ async def list(
234246
query_params.append(("filter.status", status))
235247
if model:
236248
query_params.append(("filter.model", model))
249+
if service_tier:
250+
query_params.append(("filter.service_tier", service_tier))
237251
if task_ids:
238252
if isinstance(task_ids, str):
239253
task_ids = [task_ids]

volcenginesdkarkruntime/types/content_generation/content_generation_task.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,9 @@ class ContentGenerationTask(BaseModel):
8080

8181
revised_prompt: str
8282
"""The revised prompt the model uses to generate content"""
83+
84+
service_tier: str
85+
"""The service tier used to run the task (optional)."""
86+
87+
execution_expires_after: int
88+
"""The expiration time in seconds after which execution should end (optional)."""

volcenginesdkarkruntime/types/responses/easy_input_message.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ class EasyInputMessage(BaseModel):
3333

3434
type: Optional[Literal["message"]] = None
3535
"""The type of the message input. Always `message`."""
36+
37+
partial: Optional[bool] = None
38+
"""Whether or not to include partial assistant responses."""

volcenginesdkarkruntime/types/responses/easy_input_message_param.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from __future__ import annotations
1313

14-
from typing import Union
14+
from typing import Union, Optional
1515
from typing_extensions import Literal, Required, TypedDict
1616

1717
from .response_input_message_content_list_param import (
@@ -36,3 +36,6 @@ class EasyInputMessageParam(TypedDict, total=False):
3636

3737
type: Literal["message"]
3838
"""The type of the message input. Always `message`."""
39+
40+
partial: Optional[bool] = None
41+
"""Whether or not to include partial assistant responses."""

volcenginesdkarkruntime/types/responses/response_output_message.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#
1010
# This modified file is released under the same license.
1111

12-
from typing import List, Union
12+
from typing import List, Union, Optional
1313
from typing_extensions import Literal, Annotated, TypeAlias
1414

1515
from ..._utils import PropertyInfo
@@ -42,3 +42,6 @@ class ResponseOutputMessage(BaseModel):
4242

4343
type: Literal["message"]
4444
"""The type of the output message. Always `message`."""
45+
46+
partial: Optional[bool]
47+
"""Whether or not to include partial assistant responses."""

volcenginesdkexamples/volcenginesdkarkruntime/content_generation_tasks.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@
2424
# "role": "first_frame"
2525
}
2626
],
27+
service_tier="default",
28+
execution_expires_after=3600,
2729
# callback_url="${YOUR_CALLBACK_URL}"
2830
)
2931
print(create_result)
3032

3133
print("----- get request -----")
3234
get_result = client.content_generation.tasks.get(task_id=create_result.id)
3335
print(get_result)
36+
print("ServiceTier:", getattr(get_result, "service_tier", None))
37+
print("ExecutionExpiresAfter:", getattr(get_result, "execution_expires_after", None))
3438

3539
print("----- list request -----")
3640
list_result = client.content_generation.tasks.list(
@@ -41,10 +45,52 @@
4145
# task_ids=["test-id-1", "test-id-2"] # Filter by task_ids
4246
)
4347
print(list_result)
48+
if list_result.items:
49+
print("List Item ServiceTier:", getattr(list_result.items[0], "service_tier", None))
50+
print("List Item ExecutionExpiresAfter:", getattr(list_result.items[0], "execution_expires_after", None))
4451

4552
print("----- delete request -----")
4653
try:
4754
client.content_generation.tasks.delete(task_id=create_result.id)
4855
print(create_result.id)
4956
except Exception as e:
5057
print(f"failed to delete task: {e}")
58+
59+
# ---- flex tier flow: create + GET + LIST + DELETE ----
60+
print("----- create request (flex) -----")
61+
create_result_flex = client.content_generation.tasks.create(
62+
model="${YOUR_MODEL_EP}",
63+
content=[
64+
{
65+
"type": "text",
66+
"text": "使用 flex 级别进行内容生成测试,验证 service_tier 与 expire 字段"
67+
}
68+
],
69+
service_tier="flex",
70+
execution_expires_after=3600,
71+
)
72+
print(create_result_flex)
73+
74+
print("----- get request (flex) -----")
75+
get_result_flex = client.content_generation.tasks.get(task_id=create_result_flex.id)
76+
print(get_result_flex)
77+
print("Flex ServiceTier:", getattr(get_result_flex, "service_tier", None))
78+
print("Flex ExecutionExpiresAfter:", getattr(get_result_flex, "execution_expires_after", None))
79+
80+
print("----- list request (flex) -----")
81+
list_result_flex = client.content_generation.tasks.list(
82+
page_num=1,
83+
page_size=10,
84+
service_tier="flex",
85+
)
86+
print(list_result_flex)
87+
if list_result_flex.items:
88+
print("Flex List Item ServiceTier:", getattr(list_result_flex.items[0], "service_tier", None))
89+
print("Flex List Item ExecutionExpiresAfter:", getattr(list_result_flex.items[0], "execution_expires_after", None))
90+
91+
print("----- delete request (flex) -----")
92+
try:
93+
client.content_generation.tasks.delete(task_id=create_result_flex.id)
94+
print(create_result_flex.id)
95+
except Exception as e:
96+
print(f"failed to delete flex task: {e}")

0 commit comments

Comments
 (0)