Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions agent-adk/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions agent-agno/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 8 additions & 1 deletion agent-agno/tests/test_model_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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"
4 changes: 2 additions & 2 deletions agent-crewai/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions agent-crewai/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions agent-langroid/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions agent-llamaindex/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions agent-strands/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
1 change: 1 addition & 0 deletions agent-strands/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
14 changes: 14 additions & 0 deletions shared/model_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"