hermes - ✅(Solved) Fix copilot-acp provider crashes with 'types.SimpleNamespace' object is not iterable [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#14437Fetched 2026-04-24 06:17:18
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Author
Timeline (top)
labeled ×4cross-referenced ×2commented ×1

When using the copilot-acp provider, every request fails with:

RuntimeError: 'types.SimpleNamespace' object is not iterable

Error Message

RuntimeError: 'types.SimpleNamespace' object is not iterable

Root Cause

In agent/copilot_acp_client.py line 337:

tool_calls, cleaned_text = _extract_tool_calls_from_text(response_text)

_extract_tool_calls_from_text returns list[SimpleNamespace] for tool_calls. However, downstream code in Hermes expects OpenAI SDK native tool_calls objects and attempts to iterate over them in a way that's incompatible with SimpleNamespace, causing the crash.

This happens on every request regardless of whether tool calls are actually present in the response, because the returned list[SimpleNamespace] is passed into Hermes' standard tool-call handling path which expects the OpenAI SDK's native format.

Fix Action

Fixed

PR fix notes

PR #14438: fix(agent): stream copilot ACP chat completions

Description (problem / solution / changelog)

Issue

Fixes #14437.

Root cause

Copilot ACP uses the chat-completions path, where Hermes requests stream=true. The ACP shim ignored that argument and returned a one-shot SimpleNamespace completion, so the streaming loop tried to iterate a non-iterable object and raised TypeError. Its parsed tool calls also did not quite match OpenAI SDK model behavior for downstream compatibility.

Fix

The ACP shim now returns OpenAI-style iterable stream chunks when stream=true, including text deltas, tool-call deltas with indices, finish_reason, and a final usage chunk. Parsed ACP tool calls are also constructed as OpenAI SDK ChatCompletionMessageToolCall objects while preserving Hermes call_id metadata.

This is a fresh main-based salvage of the same failure class as stale/dirty PRs #12274, #9578, and #13071, with focused current regression coverage.

Tests

  • /Users/stephenyu/Documents/hermes-agent/.venv/bin/python -m pytest tests/agent/test_copilot_acp_client.py -q --tb=short
  • /Users/stephenyu/Documents/hermes-agent/.venv/bin/python -m pytest tests/run_agent/test_run_agent_codex_responses.py::test_copilot_acp_stays_on_chat_completions_for_gpt_5_models tests/run_agent/test_run_agent.py::test_aiagent_uses_copilot_acp_client -q --tb=short
  • /Users/stephenyu/Documents/hermes-agent/.venv/bin/python inline streaming smoke test with patched CopilotACPClient._run_prompt
  • git diff --check

Changed files

  • agent/copilot_acp_client.py (modified, +77/-8)
  • tests/agent/test_copilot_acp_client.py (modified, +105/-0)

PR #14442: fix(copilot-acp): raise NotImplementedError on stream=True to prevent SimpleNamespace iteration crash

Description (problem / solution / changelog)

Problem

Fixes #14437.

When using the copilot-acp provider, any request crashes with:

RuntimeError: 'types.SimpleNamespace' object is not iterable

Root cause: The agent loop calls .chat.completions.create(stream=True) by default (via _interruptible_streaming_api_call). The copilot-acp provider's _create_chat_completion accepted **_ and silently ignored the stream kwarg, returning a SimpleNamespace response object directly. The streaming loop then did:

for chunk in stream:  # stream is a SimpleNamespace, not an iterator

…crashing immediately with the not iterable error before any response was delivered.

Fix

Add stream as an explicit keyword argument in _create_chat_completion and raise NotImplementedError("stream not supported for copilot-acp provider") when True.

The error message matches the pattern the agent loop already checks in _interruptible_streaming_api_call:

_is_stream_unsupported = (
    "stream" in _err_lower
    and "not supported" in _err_lower
)
if _is_stream_unsupported:
    self._disable_streaming = True  # retries without streaming

This means on the first request Hermes auto-detects that copilot-acp doesn't support streaming, disables it for the session, and retries — so the conversation continues uninterrupted with no user intervention needed.

Testing

from agent.copilot_acp_client import CopilotACPClient
import pytest

client = CopilotACPClient(acp_command="echo")

# stream=False (default) — should NOT raise
# (will fail to connect to echo, but won't crash on iteration)

# stream=True — should raise NotImplementedError with correct message
try:
    client.chat.completions.create(
        model="copilot",
        messages=[{"role": "user", "content": "hi"}],
        stream=True,
    )
    assert False, "Should have raised"
except NotImplementedError as e:
    assert "stream not supported" in str(e).lower()

Changed files

  • agent/copilot_acp_client.py (modified, +10/-0)

Code Example

RuntimeError: 'types.SimpleNamespace' object is not iterable

---

tool_calls, cleaned_text = _extract_tool_calls_from_text(response_text)

---

model:
     default: copilot-acp
     provider: copilot-acp
     base_url: acp://copilot
RAW_BUFFERClick to expand / collapse

Environment

  • Hermes version: latest
  • Provider: copilot-acp
  • ACP backend: claude-agent-acp (any ACP-compatible agent)

Description

When using the copilot-acp provider, every request fails with:

RuntimeError: 'types.SimpleNamespace' object is not iterable

Root Cause

In agent/copilot_acp_client.py line 337:

tool_calls, cleaned_text = _extract_tool_calls_from_text(response_text)

_extract_tool_calls_from_text returns list[SimpleNamespace] for tool_calls. However, downstream code in Hermes expects OpenAI SDK native tool_calls objects and attempts to iterate over them in a way that's incompatible with SimpleNamespace, causing the crash.

This happens on every request regardless of whether tool calls are actually present in the response, because the returned list[SimpleNamespace] is passed into Hermes' standard tool-call handling path which expects the OpenAI SDK's native format.

Steps to Reproduce

  1. Configure Hermes to use copilot-acp provider:
    model:
      default: copilot-acp
      provider: copilot-acp
      base_url: acp://copilot
  2. Set HERMES_COPILOT_ACP_COMMAND to any ACP-compatible agent
  3. Start a conversation
  4. Observe the error on the first message

Expected Behavior

Requests complete successfully. Tool calls parsed from ACP responses are correctly handled downstream.

Suggested Fix

Either convert SimpleNamespace objects to the format Hermes' tool-call handling expects, or ensure the downstream code handles SimpleNamespace the same way it handles OpenAI SDK native objects.

extent analysis

TL;DR

The issue can be fixed by converting SimpleNamespace objects to the format Hermes' tool-call handling expects or modifying the downstream code to handle SimpleNamespace objects.

Guidance

  • Identify the specific lines of code in agent/copilot_acp_client.py where the _extract_tool_calls_from_text function is called and the returned list[SimpleNamespace] is passed to the downstream code.
  • Modify the _extract_tool_calls_from_text function to return the tool_calls in the format expected by Hermes' tool-call handling code.
  • Alternatively, update the downstream code to handle SimpleNamespace objects in the same way it handles OpenAI SDK native objects.
  • Verify the fix by running the steps to reproduce and checking that the error no longer occurs.

Example

# Example of converting SimpleNamespace to a dictionary
def convert_simple_namespace(simple_namespace):
    return {attr: getattr(simple_namespace, attr) for attr in dir(simple_namespace) if not attr.startswith('__')}

# Usage
tool_calls = [convert_simple_namespace(call) for call in tool_calls]

Notes

The suggested fix assumes that the SimpleNamespace objects contain the necessary information to be converted to the expected format. If the objects are missing required attributes, additional modifications may be needed.

Recommendation

Apply a workaround by converting SimpleNamespace objects to the expected format, as this approach is more targeted and less likely to introduce new issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING