diff --git a/CHANGELOG.md b/CHANGELOG.md index c70ae2f58b..2d375d1be0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -260,6 +260,17 @@ deployment: - LangChain is called **LangChain**, with LangChain's own mark, where it said "LangChain (LangGraph)": in New Bot, a Bot's "Powered by" subtitle and its Runs on row, and OpenBot Desktop's note under a ChatGPT plan. +- A browser action waiting for your approval is named the way its card names it. A Bot's Activity + row read "Approve computer_click" with "write" beside it, and now reads "Click the link “Python” + on en.wikipedia.org". The Needs you card names the link too and lists what the action would send + by label, without the page handles a click carried as raw JSON. An approval in Slack says it the + same way ("Research Bot wants to click the link “Python” on en.wikipedia.org"), and a saved rule + is titled "Click" or "Send email on Gmail" instead of its tool id. The line under it names the + folder and the Bot by name and the kind of action in words ("changes in share for Shop"), where + it read "write on host-grant-15407-… for shopper-bot". +- The CrewAI, Agno, LlamaIndex, ADK, Strands and Langroid Bots now run on Google. Choosing + Google sent litellm the provider name `google`, which it does not know, so every message failed + with "LLM Provider NOT provided"; it now gets `gemini`. `GOOGLE_API_KEY` is still the key. - Settings → Activity and Admin → Audit reach past the newest 50 events. **Show older events** under the last row loads the next page, and the count reads "Newest 50 events", growing as more load, until nothing older is left. They stopped at the newest 50 and counted them as if that were diff --git a/agent-adk/src/main.py b/agent-adk/src/main.py index 32b4c335d7..2e5adc5a38 100644 --- a/agent-adk/src/main.py +++ b/agent-adk/src/main.py @@ -14,7 +14,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id from ag_ui.core import ( AssistantMessage, @@ -339,7 +339,7 @@ def _model_id() -> str: settings = bot_settings("agent-adk") provider = settings.provider model = settings.model - return f"{provider}/{model}" + return litellm_model_id(provider, model) app = FastAPI() diff --git a/agent-agno/src/main.py b/agent-agno/src/main.py index f45885ce79..6849e8b1c9 100644 --- a/agent-agno/src/main.py +++ b/agent-agno/src/main.py @@ -13,7 +13,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id from agno.agent import Agent from agno.models.litellm import LiteLLM @@ -42,7 +42,7 @@ def _model_id() -> str: settings = bot_settings("agent-agno") provider = settings.provider model = settings.model - return f"{provider}/{model}" + return litellm_model_id(provider, model) # Before the app is built: Agno's AG-UI router would otherwise send the model only the newest line. diff --git a/agent-agno/tests/test_model_spec.py b/agent-agno/tests/test_model_spec.py index 1ef9da4d4c..757e321852 100644 --- a/agent-agno/tests/test_model_spec.py +++ b/agent-agno/tests/test_model_spec.py @@ -9,7 +9,7 @@ from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import BotSettings, bot_settings +from model_providers import BotSettings, bot_settings, litellm_model_id BOT_ID = "agent-agno" @@ -30,3 +30,10 @@ def test_blank_environment_falls_through_to_the_file(monkeypatch): monkeypatch.setenv("BOT_PROVIDER", "") monkeypatch.setenv("BOT_MODEL", " ") assert bot_settings(BOT_ID) == BotSettings(provider="openai", model="gpt-5.5") + + +def test_litellm_calls_google_gemini(): + """litellm has no `google` provider; Google AI Studio is `gemini` there.""" + assert litellm_model_id("google", "gemini-2.5-flash") == "gemini/gemini-2.5-flash" + assert litellm_model_id("openai", "qwen/qwen3-8b") == "openai/qwen/qwen3-8b" + assert litellm_model_id("anthropic", "claude-haiku") == "anthropic/claude-haiku" diff --git a/agent-crewai/src/main.py b/agent-crewai/src/main.py index d3f47aab64..fa2b3a79eb 100644 --- a/agent-crewai/src/main.py +++ b/agent-crewai/src/main.py @@ -20,7 +20,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id import ag_ui_crewai.endpoint as crewai_endpoint from ag_ui.core import Message, Tool @@ -57,7 +57,7 @@ def _model() -> str: settings = bot_settings("agent-crewai") provider = settings.provider model = settings.model - return f"{provider}/{model}" + return litellm_model_id(provider, model) _PROVIDER_MESSAGE_FIELDS = { diff --git a/agent-crewai/tests/test_main.py b/agent-crewai/tests/test_main.py index a46d33fac6..34fde5b37e 100644 --- a/agent-crewai/tests/test_main.py +++ b/agent-crewai/tests/test_main.py @@ -60,6 +60,7 @@ def run_input(messages): ("anthropic", "openai/gpt-4o", "anthropic/openai/gpt-4o"), ("openai", "qwen/qwen3-8b", "openai/qwen/qwen3-8b"), ("", "openai/gpt-5.6-terra", "openai/openai/gpt-5.6-terra"), + ("google", "gemini-2.5-flash", "gemini/gemini-2.5-flash"), ], ) def test_model_normalizes_blank_provider_and_model_before_defaults( diff --git a/agent-langroid/src/main.py b/agent-langroid/src/main.py index bc6d1638c0..4fed23f191 100644 --- a/agent-langroid/src/main.py +++ b/agent-langroid/src/main.py @@ -8,7 +8,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id from ag_ui_langroid import create_langroid_app from fastapi import Request @@ -32,7 +32,7 @@ def _model_id() -> str: model = settings.model if "/" in model or provider == "openai": return model - return f"litellm/{provider}/{model}" + return f"litellm/{litellm_model_id(provider, model)}" # An empty `OPENAI_API_KEY` is no key. Compose writes the keys a model choice does not use as empty diff --git a/agent-llamaindex/src/main.py b/agent-llamaindex/src/main.py index 48b81e5189..481f1f2efa 100644 --- a/agent-llamaindex/src/main.py +++ b/agent-llamaindex/src/main.py @@ -12,7 +12,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id import litellm from fastapi import FastAPI, Request @@ -37,7 +37,7 @@ def _model_id() -> str: settings = bot_settings("agent-llamaindex") provider = settings.provider model = settings.model - return f"{provider}/{model}" + return litellm_model_id(provider, model) def _llm() -> LiteLLM: diff --git a/agent-strands/src/main.py b/agent-strands/src/main.py index 038fdb49cf..439b6e7e91 100644 --- a/agent-strands/src/main.py +++ b/agent-strands/src/main.py @@ -8,7 +8,7 @@ # The spec file every language in the box reads: one level above this Bot in the repository, and # one level above /app/src in the image the Dockerfile builds. sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "shared")) -from model_providers import bot_settings +from model_providers import bot_settings, litellm_model_id from ag_ui_strands import StrandsAgent, add_strands_fastapi_endpoint from fastapi import FastAPI, Request @@ -33,7 +33,7 @@ def _model_id() -> str: settings = bot_settings("agent-strands") provider = settings.provider model = settings.model - return f"{provider}/{model}" + return litellm_model_id(provider, model) app = FastAPI() diff --git a/agent-strands/tests/test_main.py b/agent-strands/tests/test_main.py index a6fa792abd..3878502c7e 100644 --- a/agent-strands/tests/test_main.py +++ b/agent-strands/tests/test_main.py @@ -105,6 +105,7 @@ def provider(): ("openai", "openai/gpt-5.6-terra", "openai/openai/gpt-5.6-terra"), ("", "qwen/qwen3-8b", "openai/qwen/qwen3-8b"), ("anthropic", "claude-sonnet-4-5", "anthropic/claude-sonnet-4-5"), + ("google", "gemini-2.5-flash", "gemini/gemini-2.5-flash"), ], ) def test_model_id_keeps_the_chosen_provider_on_a_name_that_contains_a_slash( diff --git a/shared/model_providers.py b/shared/model_providers.py index 7345a0b5fe..33f380fede 100644 --- a/shared/model_providers.py +++ b/shared/model_providers.py @@ -177,3 +177,17 @@ def bot_settings( ) return BotSettings(provider=provider, model=model) + + +# litellm's name for a provider, where it differs from OpenBot's. litellm addresses Google AI Studio +# as `gemini`; `google/...` is not a provider it knows and fails with `LLM Provider NOT provided`. +_LITELLM_PROVIDER = {"google": "gemini"} + + +def litellm_model_id(provider: str, model: str) -> str: + """`provider/model` as litellm addresses it: the chosen provider stays in front of the model. + + OpenBot calls Google AI Studio `google`; litellm calls it `gemini`, so that one name is + translated. Every other provider is passed through as typed. + """ + return f"{_LITELLM_PROVIDER.get(provider, provider)}/{model}"