diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index a3904630fa96..4792ba917905 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -3658,6 +3658,11 @@ async def _fetch_channel_context( if limit <= 0: return "" + # Not all channel-like objects expose ``history``. Forum parents, + # voice channels, and custom proxies in tests can lack it. + if not hasattr(channel, "history"): + return "" + # Determine which bot messages to include in context allow_bots_raw = os.getenv("DISCORD_ALLOW_BOTS", "none").lower().strip() include_other_bots = allow_bots_raw != "none" diff --git a/tests/gateway/test_discord_free_response.py b/tests/gateway/test_discord_free_response.py index c69af3e7781c..237474949cfa 100644 --- a/tests/gateway/test_discord_free_response.py +++ b/tests/gateway/test_discord_free_response.py @@ -801,6 +801,22 @@ def history(self, *, limit, before, after=None, oldest_first=None): assert recorded_after["value"] is None +@pytest.mark.asyncio +async def test_fetch_channel_context_returns_empty_when_channel_lacks_history(adapter, monkeypatch): + """Channel-like objects without ``.history`` should not break backfill.""" + monkeypatch.setenv("DISCORD_ALLOW_BOTS", "all") + adapter.config.extra["history_backfill_limit"] = 10 + + channel = SimpleNamespace(id=123, name="general") + + result = await adapter._fetch_channel_context( + channel, + before=SimpleNamespace(id=42), + ) + + assert result == "" + + @pytest.mark.asyncio async def test_discord_shared_channel_backfill_prepends_context(adapter, monkeypatch): monkeypatch.setenv("DISCORD_REQUIRE_MENTION", "true") diff --git a/tests/run_agent/test_provider_parity.py b/tests/run_agent/test_provider_parity.py index d3a5a1b37fa1..1178a6714d1f 100644 --- a/tests/run_agent/test_provider_parity.py +++ b/tests/run_agent/test_provider_parity.py @@ -252,8 +252,12 @@ def test_original_messages_not_mutated(self, monkeypatch): assert messages[0]["role"] == "system" def test_developer_role_via_nous_portal(self, monkeypatch): - agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1") - agent.model = "gpt-5" + agent = _make_agent( + monkeypatch, + "nous", + base_url="https://inference-api.nousresearch.com/v1", + model="gpt-5", + ) messages = [ {"role": "system", "content": "You are helpful."}, {"role": "user", "content": "hi"}, @@ -344,14 +348,24 @@ def test_includes_tools(self, monkeypatch): class TestBuildApiKwargsNousPortal: def test_includes_nous_product_tags(self, monkeypatch): from agent.portal_tags import nous_portal_tags - agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1") + agent = _make_agent( + monkeypatch, + "nous", + base_url="https://inference-api.nousresearch.com/v1", + model="gpt-5", + ) messages = [{"role": "user", "content": "hi"}] kwargs = agent._build_api_kwargs(messages) extra = kwargs.get("extra_body", {}) assert extra.get("tags") == nous_portal_tags() def test_uses_chat_completions_format(self, monkeypatch): - agent = _make_agent(monkeypatch, "nous", base_url="https://inference-api.nousresearch.com/v1") + agent = _make_agent( + monkeypatch, + "nous", + base_url="https://inference-api.nousresearch.com/v1", + model="gpt-5", + ) messages = [{"role": "user", "content": "hi"}] kwargs = agent._build_api_kwargs(messages) assert "messages" in kwargs