Merge branch 'main' of github.com:NousResearch/hermes-agent into feat/ink-refactor

This commit is contained in:
Brooklyn Nicholson 2026-04-13 21:46:11 -05:00
commit 6bbac046a7
3 changed files with 97 additions and 2 deletions

View File

@ -106,9 +106,15 @@ DEFAULT_CONTEXT_LENGTHS = {
"claude-sonnet-4.6": 1000000,
# Catch-all for older Claude models (must sort after specific entries)
"claude": 200000,
# OpenAI
# OpenAI — GPT-5 family (most have 400k; specific overrides first)
# Source: https://developers.openai.com/api/docs/models
"gpt-5.4-nano": 400000, # 400k (not 1.05M like full 5.4)
"gpt-5.4-mini": 400000, # 400k (not 1.05M like full 5.4)
"gpt-5.4": 1050000, # GPT-5.4, GPT-5.4 Pro (1.05M context)
"gpt-5.3-codex-spark": 128000, # Spark variant has reduced 128k context
"gpt-5.1-chat": 128000, # Chat variant has 128k context
"gpt-5": 400000, # GPT-5.x base, mini, codex variants (400k)
"gpt-4.1": 1047576,
"gpt-5": 128000,
"gpt-4": 128000,
# Google
"gemini": 1048576,

View File

@ -280,6 +280,14 @@ class GatewayStreamConsumer:
await self._send_or_edit(self._accumulated)
except Exception:
pass
# If we delivered any content before being cancelled, mark the
# final response as sent so the gateway's already_sent check
# doesn't trigger a duplicate message. The 5-second
# stream_task timeout (gateway/run.py) can cancel us while
# waiting on a slow Telegram API call — without this flag the
# gateway falls through to the normal send path.
if self._already_sent:
self._final_response_sent = True
except Exception as e:
logger.error("Stream consumer error: %s", e)

View File

@ -599,3 +599,84 @@ class TestInterimCommentaryMessages:
assert sent_texts == ["Hello ▉", "world"]
assert consumer.already_sent is True
assert consumer.final_response_sent is True
class TestCancelledConsumerSetsFlags:
"""Cancellation must set final_response_sent when already_sent is True.
The 5-second stream_task timeout in gateway/run.py can cancel the
consumer while it's still processing. If final_response_sent stays
False, the gateway falls through to the normal send path and the
user sees a duplicate message.
"""
@pytest.mark.asyncio
async def test_cancelled_with_already_sent_marks_final_response_sent(self):
"""Cancelling after content was sent should set final_response_sent."""
adapter = MagicMock()
adapter.send = AsyncMock(
return_value=SimpleNamespace(success=True, message_id="msg_1")
)
adapter.edit_message = AsyncMock(
return_value=SimpleNamespace(success=True)
)
adapter.MAX_MESSAGE_LENGTH = 4096
consumer = GatewayStreamConsumer(
adapter,
"chat_123",
StreamConsumerConfig(edit_interval=0.01, buffer_threshold=5),
)
# Stream some text — the consumer sends it and sets already_sent
consumer.on_delta("Hello world")
task = asyncio.create_task(consumer.run())
await asyncio.sleep(0.08)
assert consumer.already_sent is True
# Cancel the task (simulates the 5-second timeout in gateway)
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
# The fix: final_response_sent should be True even though _DONE
# was never processed, preventing a duplicate message.
assert consumer.final_response_sent is True
@pytest.mark.asyncio
async def test_cancelled_without_any_sends_does_not_mark_final(self):
"""Cancelling before anything was sent should NOT set final_response_sent."""
adapter = MagicMock()
adapter.send = AsyncMock(
return_value=SimpleNamespace(success=False, message_id=None)
)
adapter.edit_message = AsyncMock(
return_value=SimpleNamespace(success=True)
)
adapter.MAX_MESSAGE_LENGTH = 4096
consumer = GatewayStreamConsumer(
adapter,
"chat_123",
StreamConsumerConfig(edit_interval=0.01, buffer_threshold=5),
)
# Send fails — already_sent stays False
consumer.on_delta("x")
task = asyncio.create_task(consumer.run())
await asyncio.sleep(0.08)
assert consumer.already_sent is False
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
# Without a successful send, final_response_sent should stay False
# so the normal gateway send path can deliver the response.
assert consumer.final_response_sent is False