fix(model): resolve proxy credentials and fallback detection - #132
fix(model): resolve proxy credentials and fallback detection#132hanxie-crypto wants to merge 1 commit into
Conversation
Change-Id: Ic762f1ec003cee398a27c30ce06a37e933e483e6 Tests: 77 model unit tests passed.\nType check: uv run mypy --config-file mypy.ini . was blocked by numpy stubs using Python 3.12 type syntax while mypy targets Python 3.10 (1 error).
There was a problem hiding this comment.
🟡 Changes recommended
The updated auto-detection logic now broadly swallows exceptions for ModelService lookups (and drops prior HTTPError -> ResourceError mapping for explicit SERVICE requests), which can mask real failures and change public error behavior.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes Model auto-detection and ModelProxy credential handling so that incomplete ModelService responses fall back to ModelProxy, and ModelProxy.model_info() can resolve a credential bound to the proxy and build an authenticated public data-plane endpoint. It also updates the generated async templates to keep sync/async behavior aligned.
Changes:
- Tighten auto-detection behavior: treat service-shaped but unusable
ModelServiceresponses (missingproviderSettings) as a fallback signal toModelProxy. - Enhance
ModelProxy.model_info()to resolve a boundCredential(via request-scopedConfig) and constructbase_url+ auth headers for the proxy endpoint. - Add/adjust unit tests to cover fallback behavior and bound-credential resolution.
File summaries
| File | Description |
|---|---|
agentrun/model/client.py |
Adjusts sync/async get*() auto-detection logic to reject incomplete service responses and fall back to proxy. |
agentrun/model/__client_async_template.py |
Mirrors the updated auto-detection logic in the generated async client template. |
agentrun/model/model_proxy.py |
Adds bound-credential resolution and public endpoint auth header construction in model_info(). |
agentrun/model/__model_proxy_async_template.py |
Mirrors the updated model_info() behavior in the generated async template. |
tests/unittests/model/test_client.py |
Adds coverage ensuring incomplete ModelService responses fall back to proxy (sync + async). |
tests/unittests/model/test_model_proxy.py |
Adds coverage for ModelProxy.model_info() resolving a bound credential and producing authenticated base URL + headers. |
Review details
Suppressed comments (1)
agentrun/model/client.py:578
- Same as the async path: the new
except Exceptionfallback inget()can hide realModelServiceerrors during auto-detection and it removes the previousHTTPError -> ResourceErrorconversion for explicitbackend_type==SERVICEcalls. Restrict fallback to the intended cases (HTTPError + the specific "no provider settings" validation) and keepto_resource_errorfor SERVICE-only lookups.
model_service = ModelService.from_inner_object(result)
if (
backend_type is None
and model_service.provider_settings is None
):
raise ValueError(
f"ModelService '{name}' returned no provider settings"
)
return model_service
except Exception:
if backend_type == BackendType.SERVICE:
raise
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| model_service = ModelService.from_inner_object(result) | ||
| if ( | ||
| backend_type is None | ||
| and model_service.provider_settings is None | ||
| ): | ||
| raise ValueError( | ||
| f"ModelService '{name}' returned no provider settings" | ||
| ) | ||
| return model_service | ||
| except Exception: | ||
| if backend_type == BackendType.SERVICE: | ||
| raise |
| model_service = ModelService.from_inner_object(result) | ||
| if ( | ||
| backend_type is None | ||
| and model_service.provider_settings is None | ||
| ): | ||
| raise ValueError( | ||
| f"ModelService '{name}' returned no provider settings" | ||
| ) | ||
| return model_service | ||
| except Exception: | ||
| if backend_type == BackendType.SERVICE: | ||
| raise |
| ) | ||
| return model_service | ||
| except Exception: | ||
| if backend_type == BackendType.SERVICE: |
There was a problem hiding this comment.
[P2] 保留异常契约,避免将网络失败当作类型探测失败
这里改成 except Exception 后,有两种已对照 base 复现的行为变化:
- 显式
backend_type=BackendType.SERVICE,接口返回404 + model not found:原来经to_resource_error()抛ResourceNotExistError,现在直接抛HTTPError,已有的except ResourceNotExistError无法捕获。ModelService.get_by_name()和异步路径同样受影响。 - 自动探测时,Service 查询因网络超时抛底层
UnretryableException,随后 Proxy 查询返回 404:原来保留网络异常且不查 Proxy,现在吞掉网络异常,最终变成ResourceNotExistError,将查询失败误报为资源不存在。此场景通过 mock 底层 SDK、保留真实 ModelControlAPI 转换逻辑复现。
建议只在成功解析但缺少 provider_settings 时直接进入 Proxy 查询,保留原有的 HTTPError 捕获及 SERVICE 分支的 to_resource_error() 转换,不扩大到捕获所有异常。请同步修改 get_async() 和 __client_async_template.py,并增加断言具体异常类型的回归测试;现有 pytest.raises(Exception) 覆盖不了第一种变化。
Fix bugs
Bug detail
Pull request tasks
Validation
uv run pytest tests/unittests/model/test_client.py tests/unittests/model/test_model_proxy.py: 77 passed, 1 deprecation warning.uv run mypy --config-file mypy.ini .: attempted, but blocked by.venv/lib/python3.12/site-packages/numpy/__init__.pyiusing Python 3.12typesyntax while this repository's mypy configuration targets Python 3.10 (1 dependency-stub syntax error).Change-Id: Ic762f1ec003cee398a27c30ce06a37e933e483e6