mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 00:03:01 +03:00
test(providers): cover OrcaRouter WebUI integration
This commit is contained in:
@@ -111,6 +111,26 @@ def test_settings_payload_exposes_edenai_provider(
|
|||||||
assert edenai["model_selectable"] is True
|
assert edenai["model_selectable"] is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_settings_payload_exposes_orcarouter_provider(
|
||||||
|
tmp_path,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
config_path = tmp_path / "config.json"
|
||||||
|
config = Config()
|
||||||
|
config.providers.orcarouter.api_key = "sk-orca-test"
|
||||||
|
save_config(config, config_path)
|
||||||
|
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||||
|
|
||||||
|
payload = settings_payload()
|
||||||
|
orcarouter = next(row for row in payload["providers"] if row["name"] == "orcarouter")
|
||||||
|
|
||||||
|
assert orcarouter["label"] == "OrcaRouter"
|
||||||
|
assert orcarouter["configured"] is True
|
||||||
|
assert orcarouter["default_api_base"] == "https://api.orcarouter.ai/v1"
|
||||||
|
assert orcarouter["model_catalog"] == "catalog"
|
||||||
|
assert orcarouter["model_selectable"] is True
|
||||||
|
|
||||||
|
|
||||||
def test_settings_payload_includes_relocated_capabilities(
|
def test_settings_payload_includes_relocated_capabilities(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
@@ -1958,10 +1978,47 @@ def test_provider_models_payload_requires_gateway_key(
|
|||||||
assert payload["models"] == []
|
assert payload["models"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_provider_models_payload_fetches_orcarouter_catalog(
|
||||||
|
tmp_path,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
config_path = tmp_path / "config.json"
|
||||||
|
config = Config()
|
||||||
|
config.providers.orcarouter.api_key = "sk-orca-test"
|
||||||
|
save_config(config, config_path)
|
||||||
|
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||||
|
|
||||||
|
def fake_get(url: str, **kwargs):
|
||||||
|
assert url == "https://api.orcarouter.ai/v1/models"
|
||||||
|
assert kwargs["headers"]["Authorization"] == "Bearer sk-orca-test"
|
||||||
|
return httpx.Response(
|
||||||
|
200,
|
||||||
|
json={
|
||||||
|
"data": [
|
||||||
|
{"id": "orcarouter/auto", "owned_by": "orcarouter"},
|
||||||
|
{"id": "anthropic/claude-sonnet-4.6", "owned_by": "anthropic"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
request=httpx.Request("GET", url),
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr("nanobot.webui.settings_api.httpx.get", fake_get)
|
||||||
|
|
||||||
|
payload = provider_models_payload({"provider": ["orcarouter"]})
|
||||||
|
|
||||||
|
assert payload["status"] == "available"
|
||||||
|
assert payload["catalog_kind"] == "catalog"
|
||||||
|
assert [model["id"] for model in payload["models"]] == [
|
||||||
|
"orcarouter/auto",
|
||||||
|
"anthropic/claude-sonnet-4.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_model_catalog_kind_uses_provider_spec_metadata() -> None:
|
def test_model_catalog_kind_uses_provider_spec_metadata() -> None:
|
||||||
assert _model_catalog_kind(find_by_name("skywork")) == "official"
|
assert _model_catalog_kind(find_by_name("skywork")) == "official"
|
||||||
assert _model_catalog_kind(find_by_name("anthropic")) == "unsupported"
|
assert _model_catalog_kind(find_by_name("anthropic")) == "unsupported"
|
||||||
assert _model_catalog_kind(find_by_name("openrouter")) == "catalog"
|
assert _model_catalog_kind(find_by_name("openrouter")) == "catalog"
|
||||||
|
assert _model_catalog_kind(find_by_name("orcarouter")) == "catalog"
|
||||||
assert _model_catalog_kind(find_by_name("openai_codex")) == "builtin"
|
assert _model_catalog_kind(find_by_name("openai_codex")) == "builtin"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1003,6 +1003,90 @@ describe("Settings models", () => {
|
|||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("defers the OrcaRouter catalog until the user searches", async () => {
|
||||||
|
const base = settingsPayload();
|
||||||
|
const payload: SettingsPayload = {
|
||||||
|
...base,
|
||||||
|
agent: {
|
||||||
|
...base.agent,
|
||||||
|
model: "orcarouter/auto",
|
||||||
|
provider: "orcarouter",
|
||||||
|
resolved_provider: "orcarouter",
|
||||||
|
},
|
||||||
|
model_presets: [
|
||||||
|
{
|
||||||
|
...base.model_presets[0],
|
||||||
|
model: "orcarouter/auto",
|
||||||
|
provider: "orcarouter",
|
||||||
|
resolved_provider: "orcarouter",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
name: "orcarouter",
|
||||||
|
label: "OrcaRouter",
|
||||||
|
configured: true,
|
||||||
|
auth_type: "api_key",
|
||||||
|
api_key_required: true,
|
||||||
|
api_key_hint: "sk-o••••test",
|
||||||
|
api_base: null,
|
||||||
|
default_api_base: "https://api.orcarouter.ai/v1",
|
||||||
|
model_catalog: "catalog",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||||
|
const url = String(input);
|
||||||
|
if (url === "/api/settings") return jsonResponse(payload);
|
||||||
|
if (url === "/api/settings/cli-apps") {
|
||||||
|
return jsonResponse({ apps: [], installed_count: 0 });
|
||||||
|
}
|
||||||
|
if (url === "/api/settings/mcp-presets") {
|
||||||
|
return jsonResponse({ presets: [], installed_count: 0 });
|
||||||
|
}
|
||||||
|
if (url === "/api/settings/provider-models?provider=orcarouter") {
|
||||||
|
return jsonResponse({
|
||||||
|
provider: "orcarouter",
|
||||||
|
label: "OrcaRouter",
|
||||||
|
status: "available",
|
||||||
|
catalog_kind: "catalog",
|
||||||
|
models: [
|
||||||
|
{ id: "orcarouter/auto", owned_by: "orcarouter" },
|
||||||
|
{ id: "anthropic/claude-sonnet-4.6", owned_by: "anthropic" },
|
||||||
|
],
|
||||||
|
model_count: 2,
|
||||||
|
fetched_at: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { ok: false, status: 404, json: async () => ({}) } as Response;
|
||||||
|
});
|
||||||
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
|
|
||||||
|
renderSettingsView({ initialSection: "models" });
|
||||||
|
|
||||||
|
await togglePresetEditor();
|
||||||
|
const modelButtons = await screen.findAllByRole("button", { name: /orcarouter\/auto/i });
|
||||||
|
await openPopover(modelButtons[modelButtons.length - 1]);
|
||||||
|
expect(await screen.findByText("Search provider catalog to choose a model.")).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
fetchMock.mock.calls.some(([input]) =>
|
||||||
|
String(input).startsWith("/api/settings/provider-models"),
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
fireEvent.change(screen.getByPlaceholderText("Search or type model ID"), {
|
||||||
|
target: { value: "cl" },
|
||||||
|
});
|
||||||
|
|
||||||
|
await screen.findByText("anthropic/claude-sonnet-4.6");
|
||||||
|
expect(fetchMock).toHaveBeenCalledWith(
|
||||||
|
"/api/settings/provider-models?provider=orcarouter",
|
||||||
|
expect.objectContaining({
|
||||||
|
headers: { Authorization: "Bearer tok" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("loads curated models for configured OAuth providers", async () => {
|
it("loads curated models for configured OAuth providers", async () => {
|
||||||
const base = settingsPayload();
|
const base = settingsPayload();
|
||||||
const payload: SettingsPayload = {
|
const payload: SettingsPayload = {
|
||||||
|
|||||||
Reference in New Issue
Block a user