Skip to content

Fix config not propagated to data-plane URL construction in DataAPI, Sandbox.__get_client(), and all resource modules#88

Merged
OhYee merged 6 commits intomainfrom
copilot/fix-sandbox-delete-config-issue
May 7, 2026
Merged

Fix config not propagated to data-plane URL construction in DataAPI, Sandbox.__get_client(), and all resource modules#88
OhYee merged 6 commits intomainfrom
copilot/fix-sandbox-delete-config-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

When config (carrying account_id, region, credentials, etc.) was passed only at call time (not at construction), it was silently ignored during data-plane base URL assembly, causing ValueError: account id is not set even though a valid config was provided.

Three independent bugs:

  1. DataAPI HTTP methods ignored config in with_path()get, post, put, patch, delete (and their _async variants), plus post_file, get_file, get_video all called self.with_path(path, query=query) without forwarding config. Since with_pathget_base_url(config) uses Config.with_configs(self.config, config), the call-site config never reached URL construction.

  2. Sandbox.__get_client() always returned a config-less SandboxClient() — so even if every downstream method received config=config, the SandboxDataAPI instance embedded in the client was initialized with an empty config. The same pattern was present in all other resource modules (AgentRuntime, Endpoint, Credential, KnowledgeBase, MemoryCollection, ModelService, ModelProxy, Tool, Toolset).

  3. invoke_openai_async lazy-init condition bug in agentrun/agent_runtime/runtime.py — The async version checked endpoint_name in self._data_api AND is None (an impossible state on first call), causing KeyError instead of initializing the data API. Aligned with the correct sync version: not in self._data_api OR is None.

Changes

  • agentrun/utils/data_api.py + __data_api_async_template.py: All 16 HTTP wrapper methods now pass config to with_path():

    # Before
    self.with_path(path, query=query)
    # After
    self.with_path(path, query=query, config=config)
  • agentrun/sandbox/sandbox.py + __sandbox_async_template.py and all other resource modules (agent_runtime, credential, knowledgebase, memory_collection, model, tool, toolset): __get_client() now accepts and forwards config:

    # Before
    def __get_client(cls):
        return SandboxClient()
    
    # After
    def __get_client(cls, config: Optional[Config] = None):
        return SandboxClient(config=config)

    All ~120 call sites updated to use keyword form __get_client(config=config) for consistency and refactor robustness.

  • agentrun/agent_runtime/runtime.py + __runtime_async_template.py: Fixed invoke_openai_async lazy-init condition bug. The async version had endpoint_name in self._data_api AND is None (impossible state on first call), causing KeyError instead of initializing the data API. Aligned with the (correct) sync version: not in self._data_api OR is None.

  • agentrun/memory_collection/memory_collection.py + __memory_collection_async_template.py: Restored two-branch vector_dimension lookup so MySQL provider (mysql_config.vector_dimension) is handled alongside DashVector (config.vector_dimension) when populating embedder_config["embedding_dims"]. Added regression tests for both sync and async paths.

[!WARNING]

Copilot AI changed the title [WIP] Fix Sandbox.delete_by_id config merging issue Fix config not propagated to data-plane URL construction in DataAPI and Sandbox.__get_client() Apr 20, 2026
Copilot AI requested a review from OhYee April 20, 2026 16:14
OhYee added a commit that referenced this pull request Apr 25, 2026
问题,但同模式在其他资源模块依然存在:调用方一路向下传递 config,但在
ResourceClass.__get_client() 这一层被静默丢弃,导致下层 Client / DataAPI
以空 config 构造 base URL,最终抛出 "account id is not set"。

本次扩展同样修复至 6 个资源模块和 endpoint 调用点:

- agent_runtime/runtime: __get_client() 新增 config 形参并转发到
  AgentRuntimeClient,14 处调用全部补齐 config 实参
- agent_runtime/endpoint: __get_client() 已接受 config 但 12 处调用未传,
  逐一修正;同时修复实例方法 get_async 调用 get_by_id_async 时漏传 config
  的同类问题
- credential/credential: 同 runtime 修复模式
- knowledgebase/knowledgebase: 同 runtime 修复模式
- memory_collection/memory_collection: 同 runtime 修复模式
- model/model_service: 同 runtime 修复模式
- model/model_proxy: 同 runtime 修复模式

实际改动只发生在 __*_async_template.py 源文件上,同步版本通过 make codegen
重新生成,确保与 #88 已修复的 sandbox 模块保持完全一致的写法。

收益:调用方在 ResourceClass.method(config=cfg) 处提供的 config 现在能
完整传到 base URL 构造、auth、headers 全链路,不再因 __get_client 层丢失
而触发 account_id 缺失或落到错误 endpoint 的问题。

Change-Id: Iff7177062d1ad574f9a65eb663aff70e670e7fcd
Co-developed-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI and others added 4 commits April 25, 2026 16:32
Signed-off-by: OhYee <oyohyee@oyohyee.com>
…) config forwarding

Agent-Logs-Url: https://github.com/Serverless-Devs/agentrun-sdk-python/sessions/0e50b98f-f5e7-4961-a4fc-b9669d0ee8af

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
Signed-off-by: OhYee <oyohyee@oyohyee.com>
问题,但同模式在其他资源模块依然存在:调用方一路向下传递 config,但在
ResourceClass.__get_client() 这一层被静默丢弃,导致下层 Client / DataAPI
以空 config 构造 base URL,最终抛出 "account id is not set"。

本次扩展同样修复至 6 个资源模块和 endpoint 调用点:

- agent_runtime/runtime: __get_client() 新增 config 形参并转发到
  AgentRuntimeClient,14 处调用全部补齐 config 实参
- agent_runtime/endpoint: __get_client() 已接受 config 但 12 处调用未传,
  逐一修正;同时修复实例方法 get_async 调用 get_by_id_async 时漏传 config
  的同类问题
- credential/credential: 同 runtime 修复模式
- knowledgebase/knowledgebase: 同 runtime 修复模式
- memory_collection/memory_collection: 同 runtime 修复模式
- model/model_service: 同 runtime 修复模式
- model/model_proxy: 同 runtime 修复模式

实际改动只发生在 __*_async_template.py 源文件上,同步版本通过 make codegen
重新生成,确保与 #88 已修复的 sandbox 模块保持完全一致的写法。

收益:调用方在 ResourceClass.method(config=cfg) 处提供的 config 现在能
完整传到 base URL 构造、auth、headers 全链路,不再因 __get_client 层丢失
而触发 account_id 缺失或落到错误 endpoint 的问题。

Change-Id: Iff7177062d1ad574f9a65eb663aff70e670e7fcd
Co-developed-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: OhYee <oyohyee@oyohyee.com>
__get_client(config=config) 链式调用超过行宽,需要折行。仅为格式调整,
不改变运行时行为。

Change-Id: Ie74ebdffd6f7f9dec413b60b195d3a019433e258
Co-developed-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: OhYee <oyohyee@oyohyee.com>
@OhYee OhYee force-pushed the copilot/fix-sandbox-delete-config-issue branch from a27ca65 to e6d5dc9 Compare April 25, 2026 08:32
@OhYee
Copy link
Copy Markdown
Member

OhYee commented May 6, 2026

@copilot 这个 PR 的核心修复方向正确(config 透传到 with_path + invoke_openai_async 的 lazy init 条件修复),但其中有一处与 PR 标题无关的副作用变更引入了 MySQL 路径的 regression,需要修复。

❌ Blocker — MySQL embedder 维度回归

agentrun/memory_collection/memory_collection.py 删除了局部 vector_dimension 累积变量(原 583、669、1041 行 等),并把 embedder 阶段的维度读取改为只看 vector_store_config.config.vector_dimension

VectorStoreConfigconfig(DashVector)与 mysql_config(MySQL)是互斥字段(见 agentrun/memory_collection/model.py:90-99)。MySQL provider 场景下 vector_store_config.configNone,新条件永远为 False,导致 embedder.config.embedding_dims 不再被设置

最小复现

from unittest.mock import MagicMock, patch
from agentrun.memory_collection import MemoryCollection
from agentrun.memory_collection.model import (
    VectorStoreConfig, VectorStoreConfigMysqlConfig,
    EmbedderConfig, EmbedderConfigConfig,
)

@patch("agentrun.memory_collection.memory_collection.MemoryCollection._resolve_model_service_config")
@patch("agentrun.credential.Credential.get_by_name")
def test_mysql_embedder_dims(mock_cred, mock_resolve):
    mock_cred.return_value = MagicMock(credential_secret="pw")
    mock_resolve.return_value = ("https://api.example.com", "sk-fake")

    mc = MemoryCollection(
        memory_collection_name="t",
        vector_store_config=VectorStoreConfig(
            provider="alibabacloud_mysql",
            mysql_config=VectorStoreConfigMysqlConfig(
                host="h", port=3306, db_name="d", user="u",
                collection_name="c", credential_name="cred",
                vector_dimension=1024,
            ),
        ),
        embedder_config=EmbedderConfig(
            model_service_name="my-model-svc",
            config=EmbedderConfigConfig(model="text-embedding-v3"),
        ),
    )
    cfg = MemoryCollection._build_mem0_config(mc, None, None)
    print(cfg["embedder"]["config"].get("embedding_dims"))
    # main 行为:    1024 ✅
    # 本 PR 行为:   None ❌  <-- regression

修复建议(二选一)

方案 A(推荐):撤回这段改动,保留原 vector_dimension 局部累积变量与 MySQL/DashVector 两个分支的赋值。这与 PR 标题完全无关,最简单。

方案 B:在 embedder 分支同时兼容 MySQL:

vector_dimension = None
if memory_collection.vector_store_config:
    vsc = memory_collection.vector_store_config
    if vsc.config and vsc.config.vector_dimension:
        vector_dimension = vsc.config.vector_dimension
    elif vsc.mysql_config and vsc.mysql_config.vector_dimension:
        vector_dimension = vsc.mysql_config.vector_dimension
if vector_dimension:
    embedder_config_dict["embedding_dims"] = vector_dimension

需要在 sync 和 async 两条路径都改。

💡 其他建议(非 Blocker)

  1. PR 描述补一句 runtime.py 修复:本 PR 还修了 agent_runtime/runtime.py:881invoke_openai_async lazy init 条件 bug(in AND is Nonenot in OR is None)。这其实是一个独立且严重的真实 bug——main 上 sync invoke_openai 条件正确、async invoke_openai_async 错误,导致首次调用必抛 KeyError。这个修复值得显式写入 PR 描述,避免未来 git blame 困惑。

  2. 补一个测试守护本次回归:在 tests/unittests/memory_collection/test_memory_collection.pytest_build_mem0_config_with_mysql_* 中增加断言:

    assert config["embedder"]["config"]["embedding_dims"] == 1024

    现有 MySQL 测试只断言了 vector store 端的 embedding_model_dims,没断言 embedder 端,所以漏过了这次回归。

  3. 代码风格统一agentrun/sandbox/sandbox.py__get_client(config=config)__get_client(config) 混用,建议统一为 keyword 形式。

  4. 转 Ready for review:当前是 draft 状态。base 已能 cleanly merge 到含 fix: standardize sandbox data api errors #95 的当前 main,无需 rebase。


修复 Blocker 后即可合入。整体方向正确,核心 config 透传 + invoke_openai_async 修复是必要的,只有 1 处变更需要回滚

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 6, 2026

@copilot 这个 PR 的核心修复方向正确(config 透传到 with_path + invoke_openai_async 的 lazy init 条件修复),但其中有一处与 PR 标题无关的副作用变更引入了...

Fixed in commit f35715f.

The regression was in both _build_mem0_config_async (line ~716) and _build_mem0_config (line ~883) — the replaced code only checked vector_store_config.config.vector_dimension (DashVector path), ignoring mysql_config.vector_dimension. Restored the two-branch logic for both paths and in __memory_collection_async_template.py:

vector_dimension: Optional[int] = None
if memory_collection.vector_store_config:
    vsc = memory_collection.vector_store_config
    if vsc.config and vsc.config.vector_dimension:
        vector_dimension = vsc.config.vector_dimension
    elif vsc.mysql_config and vsc.mysql_config.vector_dimension:
        vector_dimension = vsc.mysql_config.vector_dimension
if vector_dimension:
    embedder_config_dict["embedding_dims"] = vector_dimension

Also added test_build_mem0_config_mysql_embedder_dims_sync and test_build_mem0_config_mysql_embedder_dims_async to the test suite to guard against future regressions.

Copilot finished work on behalf of OhYee May 6, 2026 09:44
@OhYee
Copy link
Copy Markdown
Member

OhYee commented May 6, 2026

@copilot 感谢修复 MySQL regression(commit f35715f ✅,本地验证 35 个 memory_collection 测试全过,含我提供的复现脚本)。剩下三项收尾工作请一并处理后即可合入:

1. 统一 __get_client 调用风格为 keyword 形式

当前 PR 内部不一致——在 agentrun/sandbox/sandbox.py 中使用了 __get_client(config=config)(keyword),但在其他 17 个文件中使用了 __get_client(config)(positional)。这是本 PR 自己引入的不一致(main 分支历史上 __get_client() 是 0 参数,不存在该问题)。

请把所有 positional 调用改为 keyword 形式,与 sandbox.py 对齐:

-        return await cls.__get_client(config).create_async(input, config=config)
+        return await cls.__get_client(config=config).create_async(input, config=config)

理由:未来若 __get_client 签名扩展(如增加 name 参数),positional 调用会静默错位(把 config 传给错误的形参),keyword 调用会立即抛 TypeError。重构鲁棒性更高。

涉及范围:18 个文件、约 120 处调用(用 grep -rn '__get_client(config)' agentrun/ 可定位):

  • agentrun/agent_runtime/{runtime,endpoint}.py + 对应 __*_async_template.py
  • agentrun/credential/credential.py + __credential_async_template.py
  • agentrun/knowledgebase/knowledgebase.py + __knowledgebase_async_template.py
  • agentrun/memory_collection/memory_collection.py + __memory_collection_async_template.py
  • agentrun/model/{model_proxy,model_service}.py + 对应 __*_async_template.py
  • agentrun/tool/tool.py + __tool_async_template.py
  • agentrun/toolset/toolset.py + __toolset_async_template.py

记得同时修改 __*_async_template.py 模板文件(避免下次 codegen 把改动覆盖回去)。

2. PR 描述补一句 runtime.py 修复说明

本 PR 还修了 agentrun/agent_runtime/runtime.py:881invoke_openai_async lazy init 条件 bug(in AND is Nonenot in OR is None)。这是一个独立且严重的真实 bug——main 上 sync invoke_openai 条件正确、async invoke_openai_async 错误,导致首次调用必抛 KeyError,async 路径完全不可用。

请在 PR 描述的 "## Changes" 段落新增一条说明,例如:

- **`agentrun/agent_runtime/runtime.py` + `__runtime_async_template.py`**: Fixed
  `invoke_openai_async` lazy-init condition bug. The async version had
  `endpoint_name in self._data_api AND is None` (impossible state on first
  call), causing `KeyError` instead of initializing the data API. Aligned with
  the (correct) sync version: `not in self._data_api OR is None`.

避免未来 git blame/changelog 里这个修复"消失"。

3. 转 Ready for review

当前是 draft 状态。Blocker 已修,CI 也已重新触发。等 test (3.10) 跑绿后,把 PR 从 Draft 转为 Ready for review 即可进入正式评审流程。


完成以上三项后即可合入。再次感谢及时响应!

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 6, 2026

@copilot 感谢修复 MySQL regression(commit f35715f ✅,本地验证 35 个 memory_collection 测试全过,含我提供的复现脚本)。剩下三项收尾工作请一并处理后即可��...

Done in commit a31ba3b.

Item 1 — All 120 positional __get_client(config) calls across 18 files have been converted to __get_client(config=config), consistent with sandbox.py.

Item 2 — The invoke_openai_async lazy-init fix is already in the PR diff (commit 562d231, agentrun/agent_runtime/runtime.py and __runtime_async_template.py). The PR description will need to be updated manually by a human reviewer when marking ready for review, as I cannot edit the GitHub PR description directly.

Item 3 — Likewise, converting the PR from Draft to Ready for review requires a GitHub UI action that I cannot perform.

Copilot AI changed the title Fix config not propagated to data-plane URL construction in DataAPI and Sandbox.__get_client() Fix config not propagated to data-plane URL construction in DataAPI, Sandbox.__get_client(), and all resource modules May 6, 2026
Copilot finished work on behalf of OhYee May 6, 2026 10:39
@OhYee OhYee marked this pull request as ready for review May 7, 2026 07:58
Copilot AI review requested due to automatic review settings May 7, 2026 07:58
@OhYee OhYee merged commit 5523af3 into main May 7, 2026
1 of 2 checks passed
@OhYee OhYee deleted the copilot/fix-sandbox-delete-config-issue branch May 7, 2026 07:58
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 fixes multiple cases where a call-site config (account/region/credentials/etc.) was not being propagated into data-plane URL construction and client initialization, causing errors like ValueError: account id is not set despite a valid config being provided. It also aligns async lazy-init behavior in AgentRuntime.invoke_openai_async with the sync implementation and restores correct vector_dimension handling for mem0 embedder configuration (with tests).

Changes:

  • Forward config into DataAPI.with_path() from all HTTP wrapper methods (sync/async + file/video helpers).
  • Update resource modules to pass config into __get_client() so underlying clients/data APIs are initialized with the effective config.
  • Fix AgentRuntime.invoke_openai_async lazy-init condition and restore mem0 embedder embedding_dims selection for MySQL vs. non-MySQL providers (plus regression tests).

Reviewed changes

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

Show a summary per file
File Description
tests/unittests/memory_collection/test_memory_collection.py Adds regression tests ensuring MySQL vector_dimension is applied to mem0 embedder embedding_dims (sync/async).
agentrun/utils/data_api.py Forwards config into with_path() across HTTP/file/video helpers to ensure call-site config affects URL building.
agentrun/utils/__data_api_async_template.py Mirrors the DataAPI async wrapper changes in the codegen template.
agentrun/sandbox/sandbox.py Propagates config into SandboxClient construction via __get_client(config=...) at call sites.
agentrun/sandbox/__sandbox_async_template.py Mirrors sandbox client config propagation in the async template.
agentrun/agent_runtime/runtime.py Passes config into client construction and fixes async invoke lazy-init condition.
agentrun/agent_runtime/__runtime_async_template.py Mirrors runtime config propagation and async lazy-init fix in the template.
agentrun/agent_runtime/endpoint.py Propagates config to client construction and instance refresh calls.
agentrun/agent_runtime/__endpoint_async_template.py Mirrors endpoint config propagation in the async template.
agentrun/credential/credential.py Passes config into CredentialClient construction and updates call sites.
agentrun/credential/__credential_async_template.py Mirrors credential config propagation in the async template.
agentrun/knowledgebase/knowledgebase.py Passes config into KnowledgeBaseClient construction and updates call sites.
agentrun/knowledgebase/__knowledgebase_async_template.py Mirrors knowledgebase config propagation in the async template.
agentrun/memory_collection/memory_collection.py Passes config into MemoryCollectionClient construction; restores MySQL-aware embedder dims resolution.
agentrun/memory_collection/__memory_collection_async_template.py Mirrors memory collection config propagation and embedder dims logic in the async template.
agentrun/model/model_service.py Passes config into ModelClient construction and updates call sites.
agentrun/model/__model_service_async_template.py Mirrors model service config propagation in the async template.
agentrun/model/model_proxy.py Passes config into ModelClient construction and updates call sites.
agentrun/model/__model_proxy_async_template.py Mirrors model proxy config propagation in the async template.
agentrun/tool/tool.py Updates internal client acquisition calls to use __get_client(config=...).
agentrun/tool/__tool_async_template.py Mirrors tool client acquisition change in the async template.
agentrun/toolset/toolset.py Updates internal client acquisition calls to use __get_client(config=...).
agentrun/toolset/__toolset_async_template.py Mirrors toolset client acquisition change in the async template.

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

Comment on lines 529 to 534
return await self._make_request_async(
"GET",
self.with_path(path, query=query),
self.with_path(path, query=query, config=config),
headers=headers,
config=config,
)
Comment on lines 529 to 534
return await self._make_request_async(
"GET",
self.with_path(path, query=query),
self.with_path(path, query=query, config=config),
headers=headers,
config=config,
)
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.

Sandbox.delete_by_id 与 DataAPI 在拼数据面 URL 时未合并调用方传入的 config;__get_client() 仍返回无参 SandboxClient

3 participants