fix(aionrs): default missing model protocol to openai#577
Conversation
tcp404
left a comment
There was a problem hiding this comment.
crates/aionui-ai-agent/src/factory/aionrs.rs:L260: risk: OpenAI-compatible prefix handling looks right, but Anthropic/custom compatibility is incomplete. aionrs v0.1.38 AnthropicTransport still hardcodes format!("{base_url}/v1/messages") and does not use compat.api_path, so a stored base_url ending in /v1 regresses to /v1/v1/messages. Please convert these tests to table-driven cases and add a final URL semantics regression before merging.
Suggested table-driven cases:
Provider Mapping
| platform | model_id | model_protocols | expected provider | expected result |
|---|---|---|---|---|
anthropic |
m |
None |
anthropic |
ok |
bedrock |
m |
None |
bedrock |
ok |
gemini |
m |
None |
openai |
ok |
openai |
m |
None |
openai |
ok |
gemini-vertex-ai |
m |
None |
vertex |
ok |
custom |
gpt-4o |
None |
openai |
ok |
new-api |
m |
None |
openai |
ok |
unknown |
m |
None |
openai |
ok |
new-api |
claude |
{"claude":"anthropic"} |
anthropic |
ok |
new-api |
gpt |
{"gpt":"openai"} |
openai |
ok |
new-api |
gemini |
{"gemini":"gemini"} |
openai |
ok |
custom |
claude |
{"claude":"anthropic"} |
anthropic |
ok |
custom |
gpt |
{"gpt":"openai"} |
openai |
ok |
custom |
unknown-model |
{"claude":"anthropic"} |
openai |
ok |
custom |
m |
{} |
openai |
ok |
custom |
m |
{"m":""} |
openai |
ok |
custom |
m |
{"m":123} |
openai |
ok |
custom |
m |
not json |
- | error |
custom |
m |
{"m":"unsupported"} |
- | error |
openai |
claude |
{"claude":"anthropic"} |
openai |
ok; known platform wins |
anthropic |
gpt |
{"gpt":"openai"} |
anthropic |
ok; known platform wins |
URL / Compat Resolution
| platform | raw_base_url | mapped_provider | is_full_url | expected base_url | expected api_path | expected max_tokens_field |
|---|---|---|---|---|---|---|
custom |
https://api.openai.com |
openai |
false | same | /chat/completions |
max_completion_tokens |
custom |
https://api.openai.com/v1 |
openai |
false | https://api.openai.com/v1 |
/chat/completions |
max_completion_tokens |
custom |
https://api.openai.com/v1/ |
openai |
false | https://api.openai.com/v1 |
/chat/completions |
max_completion_tokens |
custom |
https://api.deepseek.com/v1 |
openai |
false | same | /chat/completions |
none |
custom |
https://open.bigmodel.cn/api/paas/v4 |
openai |
false | same | /chat/completions |
none |
new-api |
https://host/v1 |
openai |
false | same | /chat/completions |
none |
custom |
http://localhost:11434/v1 |
openai |
false | same | /chat/completions |
none |
gemini |
https://generativelanguage.googleapis.com |
openai |
false | https://generativelanguage.googleapis.com/v1beta/openai |
/chat/completions |
none |
anthropic |
https://api.anthropic.com |
anthropic |
false | same | none | none |
anthropic |
https://api.anthropic.com/ |
anthropic |
false | https://api.anthropic.com |
none | none |
custom |
https://proxy.example.com/anthropic |
anthropic |
false | same | /v1/messages if final transport supports it |
none |
custom |
https://proxy.example.com/v1 |
anthropic |
false | https://proxy.example.com or final URL must not duplicate /v1 |
depends on chosen fix | none |
new-api |
https://proxy.example.com/v1 |
anthropic |
false | https://proxy.example.com or final URL must not duplicate /v1 |
depends on chosen fix | none |
custom |
https://proxy.example.com/v1/chat/completions |
openai |
true | same without trailing slash | "" |
none |
custom |
https://proxy.example.com/v1/messages |
anthropic |
true | same without trailing slash | "" |
none |
custom |
`` | openai |
false | none | none | none |
Final URL Semantics
These are the important regressions; testing only resolve_aionrs_url_and_compat() is not enough because Anthropic currently ignores compat.api_path.
| provider | base_url passed to aionrs | compat.api_path | aionrs transport behavior | expected final URL |
|---|---|---|---|---|
openai |
https://api.deepseek.com/v1 |
/chat/completions |
base_url + api_path |
https://api.deepseek.com/v1/chat/completions |
openai |
https://open.bigmodel.cn/api/paas/v4 |
/chat/completions |
base_url + api_path |
https://open.bigmodel.cn/api/paas/v4/chat/completions |
openai |
https://x/v1/chat/completions |
"" |
base_url + "" |
https://x/v1/chat/completions |
anthropic |
https://api.anthropic.com |
none | fixed {base}/v1/messages |
https://api.anthropic.com/v1/messages |
anthropic |
https://proxy.example.com |
maybe none | fixed {base}/v1/messages |
https://proxy.example.com/v1/messages |
anthropic |
https://proxy.example.com/v1 |
currently /v1/messages in this PR |
fixed {base}/v1/messages |
must not be https://proxy.example.com/v1/v1/messages |
anthropic |
https://x/v1/messages |
"" |
current aionrs still fixed-appends | verify/fix full-url mode for Anthropic too |
done |
Summary
This PR updates AionCore's aionrs provider resolution so custom providers use the selected model protocol instead of inferring protocol behavior from platform/
base URL.
Changes
anthropic-> Anthropicbedrock-> Bedrockgemini/openai-> OpenAI-compatiblegemini-vertex-ai-> Vertexprovider.model_protocols[model_id].model_protocolsto OpenAI-compatible.base_urlas a user-provided endpoint prefix:/chat/completions/v1/messages/v1suffixes frombase_url.model_protocolsJSON as a bad request instead of silently falling back.Why
The previous logic mixed protocol selection with platform/base URL assumptions. For custom providers such as DeepSeek, GLM, Poe, MiniMax, or InfiniAI, the
protocol should come from the user's selected model protocol. If no protocol is configured, the system should default to OpenAI-compatible behavior.
Validation
cargo test -p aionui-ai-agent resolve_custom_anthropiccargo test -p aionui-ai-agent resolve_anthropiccargo fmt --all -- --checkjust push6652 tests run: 6652 passed, 18 skipped