Skip to content

feat(agent_runtime): align SDK model with agentrun-20250910 & support workspace_name#102

Merged
OhYee merged 4 commits into
mainfrom
feature/agentrun-sdk-model-alignment-2026-05
May 20, 2026
Merged

feat(agent_runtime): align SDK model with agentrun-20250910 & support workspace_name#102
OhYee merged 4 commits into
mainfrom
feature/agentrun-sdk-model-alignment-2026-05

Conversation

@Sodawyx
Copy link
Copy Markdown
Collaborator

@Sodawyx Sodawyx commented May 20, 2026

Summary

  • 对齐官方模型 (agentrun-20250910):补齐 AgentRuntime / Endpoint / List 入参字段差异,下线已被 system_tags 覆盖的 tags 字段;新增 NASConfig / OSSMountConfig / ScalingConfig / RegistryConfig / ProtocolSettings 等辅助模型一比一对齐。
  • 支持 workspace_name:创建 / 查询 Agent Runtime 时可直接传 workspace 名称,SDK 自动调 ListWorkspaces 解析为 workspace_id(带 (ak, region, name) 缓存),无需手查 ID;同时传 workspace_id + workspace_name 时抛 ValueError,找不到抛 ResourceNotExistError,重名抛 ValueError
  • 示例 examples/quickstart_runtime.py 演示通过镜像部署 AgentRuntime 并以 workspace_name 选择工作空间。

主要字段变更

  • AgentRuntimeMutableProps: + disk_size / enable_session_isolation / nas_config / oss_mount_config; − tags
  • AgentRuntimeListInput: + status / workspace_ids / workspace_name / workspace_names; − tags
  • AgentRuntimeEndpointMutableProps: + disable_public_network_access / scaling_config; − tags
  • AgentRuntimeEndpointUpdateInput: + delete_scaling_config
  • AgentRuntimeContainer: + acr_instance_id / image_registry_type / port / registry_config
  • AgentRuntimeProtocolConfig: + protocol_settings
  • AgentRuntimeEndpointRoutingWeight.weight: intfloat
  • AgentRuntimeImmutableProps: + workspace_name(流入 CreateInput

Test plan

  • 全量 3469 单测通过
  • agentrun.agent_runtime 总覆盖率 99%,_workspace.py 95%,model.py 100% 行/分支覆盖
  • mypy --config-file mypy.ini agentrun/agent_runtime/ 无 issue
  • 新增 25 用例覆盖 workspace 解析(精确匹配 / 缓存 / 空名 / 找不到 / 重名 / Tea 异常透传 / sync+async 互斥校验)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the agentrun.agent_runtime SDK to align with the official agentrun-20250910 model/schema while adding a convenience feature that lets callers specify workspace_name (resolved internally to workspace_id) when creating and listing Agent Runtimes.

Changes:

  • Added workspace name → ID resolution helper (_workspace.py) with in-memory caching and integrated it into AgentRuntimeClient create/list flows.
  • Aligned Agent Runtime models/inputs with agentrun-20250910 (new config sub-models, new fields, tags removal in favor of system_tags, routing weight type change).
  • Updated unit tests to cover new models and workspace resolution behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
agentrun/agent_runtime/_workspace.py New resolver module to map workspace_name/workspace_names to IDs with caching and Tea-exception mapping.
agentrun/agent_runtime/client.py Integrates workspace resolution and adds mutual-exclusion validation for workspace fields in create/list.
agentrun/agent_runtime/model.py Adds/updates models and fields to match agentrun-20250910 (registry/protocol/NAS/OSS/scaling, tags→system_tags, weight float, workspace_name field).
agentrun/agent_runtime/runtime.py Updates high-level AgentRuntime.list_all* filter parameters to match new model fields (system_tags, status, workspace filters).
agentrun/agent_runtime/__client_async_template.py Updates codegen template to include workspace resolution logic for async client methods.
agentrun/agent_runtime/__runtime_async_template.py Updates codegen template for list_all_async signature/args to match new filters.
tests/unittests/agent_runtime/test_workspace.py New unit tests covering resolver behavior plus client create/list integration paths.
tests/unittests/agent_runtime/test_model.py Adds coverage for new/updated models and serialization aliases.
tests/unittests/agent_runtime/test_runtime.py Updates list_all filter test to use system_tags and new filters.
Comments suppressed due to low confidence (4)

agentrun/agent_runtime/client.py:163

  • Same issue as async create: workspace_name resolution ignores self.config when config arg is None (can resolve with wrong credentials/region), and the truthy check skips empty-string validation/clearing. Merge configs before resolving and treat empty strings as invalid (or normalize/strip then validate).
        if input.workspace_id and input.workspace_name:
            raise ValueError(
                "workspace_id and workspace_name are mutually exclusive; please"
                " only set one of them."
            )
        if input.workspace_name:
            input.workspace_id = resolve_workspace_id_by_name(
                input.workspace_name, config
            )
            input.workspace_name = None

agentrun/agent_runtime/client.py:405

  • list_async workspace_name(s) resolution ignores self.config when config arg is None, which can resolve workspace IDs using the wrong account/region compared to the subsequent API call (which uses the client’s configured control_api). Also, if input.workspace_name: / if input.workspace_names: skips empty-string validation/normalization. Merge configs before resolving and validate non-empty strings.
            if input.workspace_id and input.workspace_name:
                raise ValueError(
                    "workspace_id and workspace_name are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_ids and input.workspace_names:
                raise ValueError(
                    "workspace_ids and workspace_names are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_name:
                input.workspace_id = await resolve_workspace_id_by_name_async(
                    input.workspace_name, config
                )
                input.workspace_name = None
            if input.workspace_names:
                input.workspace_ids = (
                    await resolve_workspace_ids_by_names_async(
                        input.workspace_names, config
                    )
                )
                input.workspace_names = None

agentrun/agent_runtime/client.py:463

  • Same issue as list_async: workspace_name(s) resolution should use the effective config (merge self.config with the override config) so lookup runs under the same credentials/region as the API call, and it should not silently accept empty strings due to truthy checks.
            if input.workspace_id and input.workspace_name:
                raise ValueError(
                    "workspace_id and workspace_name are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_ids and input.workspace_names:
                raise ValueError(
                    "workspace_ids and workspace_names are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_name:
                input.workspace_id = resolve_workspace_id_by_name(
                    input.workspace_name, config
                )
                input.workspace_name = None
            if input.workspace_names:
                input.workspace_ids = resolve_workspace_ids_by_names(
                    input.workspace_names, config
                )
                input.workspace_names = None

agentrun/agent_runtime/__client_async_template.py:256

  • Template: list_async workspace_name(s) resolution ignores self.config when config is None, and truthy checks skip empty-string validation. Merge configs before resolving and validate/normalize non-empty workspace_name(s) so the resolver runs under the same account/region as the API call.
        try:
            if input is None:
                input = AgentRuntimeListInput()

            if input.workspace_id and input.workspace_name:
                raise ValueError(
                    "workspace_id and workspace_name are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_ids and input.workspace_names:
                raise ValueError(
                    "workspace_ids and workspace_names are mutually exclusive;"
                    " please only set one of them."
                )
            if input.workspace_name:
                input.workspace_id = await resolve_workspace_id_by_name_async(
                    input.workspace_name, config
                )
                input.workspace_name = None
            if input.workspace_names:
                input.workspace_ids = (
                    await resolve_workspace_ids_by_names_async(
                        input.workspace_names, config
                    )
                )
                input.workspace_names = None


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread agentrun/agent_runtime/client.py Outdated
Comment on lines +101 to +103
if input.workspace_name:
input.workspace_id = await resolve_workspace_id_by_name_async(
input.workspace_name, config
Comment on lines +91 to +93
if input.workspace_name:
input.workspace_id = await resolve_workspace_id_by_name_async(
input.workspace_name, config
Sodawyx added 2 commits May 20, 2026 13:46
补齐 AgentRuntime / Endpoint / List 入参与官方 SDK 的字段差异,并把
``tags`` 字段下线(已被原生 ``system_tags`` 覆盖,与 super_agent 模块统一)。

字段变更:
- AgentRuntimeMutableProps: + disk_size, enable_session_isolation,
  nas_config, oss_mount_config; - tags
- AgentRuntimeListInput: + status, workspace_ids; - tags
- AgentRuntimeEndpointMutableProps: + disable_public_network_access,
  scaling_config; - tags
- AgentRuntimeEndpointUpdateInput: + delete_scaling_config
- AgentRuntimeContainer: + acr_instance_id, image_registry_type, port,
  registry_config
- AgentRuntimeProtocolConfig: + protocol_settings
- AgentRuntimeEndpointRoutingWeight.weight: int -> float

新增辅助模型(一比一对齐官方):
- NASConfig / NASMountConfig
- OSSMountConfig / OSSMountPoint
- ScalingConfig / ScheduledPolicy
- RegistryConfig / RegistryAuthConfig / RegistryCertConfig /
  RegistryNetworkConfig
- ProtocolSettings

list_all / list_all_async 形参同步更新:删 tags,加 system_tags / status /
workspace_id / workspace_ids;runtime.py 通过 make codegen 重新生成。

测试:agent_runtime model.py 100% 行/分支覆盖;3444 全量单测通过;
mypy --config-file mypy.ini agentrun/agent_runtime/ 无 issue。

Signed-off-by: Sodawyx <sodawyx@126.com>
…lve to workspace_id)

让用户在创建 / 查询 Agent Runtime 时可以直接填 workspace 名称,
SDK 自动调用官方 ListWorkspaces 解析为 workspace_id 再下发,
无需用户手动查 ID。

模型变更(agentrun/agent_runtime/model.py):
- AgentRuntimeImmutableProps: 新增 workspace_name(流入 CreateInput)
- AgentRuntimeListInput: 新增 workspace_name / workspace_names

新增 agentrun/agent_runtime/_workspace.py:
- resolve_workspace_id_by_name(_async) 精确名字匹配 + (ak, region, name) 缓存
- resolve_workspace_ids_by_names(_async) 批量名字 -> 逗号分隔 ID
- 找不到抛 ResourceNotExistError,重名抛 ValueError,
  Tea ClientException/ServerException 转 SDK 内置 ClientError/ServerError

client / runtime(async 模板 + codegen 同步生成):
- AgentRuntimeClient.create / list:调底层 API 前自动解析 workspace_name(s)
- 同时传 workspace_id+workspace_name(或复数版本)抛 ValueError
- AgentRuntime.list_all:透传 workspace_name / workspace_names

示例:examples/quickstart_runtime.py
- 演示通过镜像部署 AgentRuntime,并使用 workspace_name 选择工作空间

测试(tests/unittests/agent_runtime/test_workspace.py,新增 25 用例):
- 精确匹配 / 缓存 / 空名 / 找不到 / 重名 / Tea 异常透传
- client.create 与 client.list 在 sync + async 路径下的解析与互斥校验

校验:
- 全量 3469 单测通过
- agentrun.agent_runtime 总覆盖率 99%,_workspace.py 95%
- mypy --config-file mypy.ini agentrun/agent_runtime/ 无 issue

Signed-off-by: Sodawyx <sodawyx@126.com>
@Sodawyx Sodawyx force-pushed the feature/agentrun-sdk-model-alignment-2026-05 branch from 9170897 to 6cc91e1 Compare May 20, 2026 05:47
PR #102 Copilot review surfaced two issues in the new workspace_name
resolution path:

1. workspace_name resolution only used the method-level `config`, ignoring
   `self.config`. When a caller built `AgentRuntimeClient(config=...)` and
   then called `create(input)` without a method-level config, the resolver
   fell back to env credentials/region while the subsequent OpenAPI call
   used `self.config` — possibly resolving a workspace under the wrong
   account/region. Now passes `Config.with_configs(self.config, config)`
   to the resolver, matching the merge done in `ControlAPI._get_client`.

2. `if input.workspace_name:` silently skipped resolution for empty
   strings instead of surfacing the resolver's existing
   `ValueError("workspace_name must be non-empty")`. Switched the
   singular checks to `is not None` so empty strings now raise.

Applied to create / create_async / list / list_async in client.py and
mirrored into the codegen template. Plural `workspace_names` keeps the
truthy check since empty-string plural is a benign "no filter".

Added 8 unit tests covering effective-config propagation (client.config
used when method config=None; method config overrides client.config) and
empty-string ValueError across all four entry points. agent_runtime
suite 262 passed / 2 skipped; `_workspace.py` 95.24% line/branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Sodawyx <sodawyx@126.com>
Copy link
Copy Markdown
Member

@OhYee OhYee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: PR #102 — SDK Model Alignment & workspace_name Support

整体质量不错,模型对齐清晰,测试覆盖充分(99%),CI 全绿。以下几点建议:

1. 🔴 Workspace 分页硬编码 page_size=50

_workspace.pyListWorkspacesRequest(name=name, page_size="50") — 如果用户有超过 50 个 workspace,resolver 可能找不到目标 workspace(API 返回的是 name 模糊匹配还是精确匹配?如果是模糊匹配,50 条可能不够)。建议至少做翻页兜底,或明确文档说明限制。

2. 🟡 resolve_workspace_id_by_name 不继承 client 的 config

Copilot 已经指出了这个问题。client.py:103__client_async_template.py:93 中 workspace 解析只用了方法级 config,没有合并 self.config。如果调用者不传 config 但 client 构造时传了,resolver 会用默认凭证,可能解析到错误的 workspace。

3. 🟡 create() 中 mutate 了 input 对象

input.workspace_name = None  # client.py

调用者传入的 input 对象被修改了,这可能出乎意料。建议做浅拷贝或只在内部变量上操作。

4. 🟡 Module-level cache 无 TTL / 大小限制

_RESOLVE_CACHE 是全局 dict,无过期无上限。长期运行的服务中如果 workspace 被重命名或删除,缓存会返回过时的 ID。建议考虑使用 functools.lru_cache 或加 TTL。

5. ℹ️ tagssystem_tags 是 breaking change

PR description 已说明,确认这是有意为之。建议在 changelog 中明确标注 BREAKING,方便用户升级。

6. ℹ️ resolve_workspace_ids_by_names_async 串行解析

多个 workspace name 用 for 循环逐个 await,可以用 asyncio.gather 并行。非阻塞建议。

总体:模型对齐部分扎实,workspace_name 是好的 DX 改进。建议至少处理 #1 (分页) 和 #3 (input mutation),其余可 follow-up。

Address two issues raised in PR #102 review by Ohyee:

1. Workspace lookup was hardcoded to a single page (page_size=50). If
   the upstream `name=` filter is server-side prefix/fuzzy match, a busy
   account can easily exceed 50 same-prefix workspaces and the resolver
   would silently miss the target. `_lookup_sync` / `_lookup_async` now
   paginate, accumulating candidates across pages and short-circuiting
   when a page returns fewer than `_PAGE_SIZE` rows; a `_MAX_PAGES=20`
   safety cap (1000 candidates) prevents runaway loops on misbehaving
   upstreams.

2. The workspace_name resolution path mutated the caller's input object
   (`input.workspace_id = ...; input.workspace_name = None`), which is
   surprising for a side-effect-free convenience field. Replaced with
   `input = input.model_copy(update={...})` so the caller's instance is
   untouched. Applied to create / create_async / list / list_async in
   client.py and mirrored into the codegen template.

Tests:
- 4 new pagination cases (multi-page accumulation, short-page early
  stop, MAX_PAGES cap, async multi-page).
- 4 existing mutation assertions flipped to "caller's input stays
  unchanged; OpenAPI request carries the resolved id".

agent_runtime suite 266 passed / 2 skipped; `_workspace.py` 95.62%
line/branch. Full repo 3481 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Sodawyx <sodawyx@126.com>
@OhYee OhYee merged commit 4790a57 into main May 20, 2026
3 checks passed
@OhYee OhYee deleted the feature/agentrun-sdk-model-alignment-2026-05 branch May 20, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants