Files
hermes-agent/agent/auxiliary_wire.py
Teknium 2b2e4d908d fix: Gemini and Copilot keep their reasoning carriers across turns
Gemini text-turn thought signatures (native thoughtSignature on a text or
trailing empty-text part; OpenAI-compat/Vertex message-level
extra_content.google.thought_signature) were discarded at capture, and the
Copilot /chat/completions reasoning_text / reasoning_opaque fields and the
Gemini-3 function.thought_signature were never read. Replaying the Gemini
text-turn signature makes the server rehydrate the turn's thoughts (live:
31 -> 237/250 prompt tokens).

agent/reasoning_carriers.py captures them (stream + non-stream), stores
them top-level on the live dict plus one private
hermes.native_assistant reasoning_details record (persisted in the
existing column, so resume/gateway replay keep them), and lifts each one
onto the wire only for the route that reads it: extra_content on the
same Gemini gate as tool-call extra_content, reasoning_opaque/text and
function.thought_signature only to githubcopilot.com. The private record
is never forwarded (no profile declares that type). Copilot reasoning_text
is shown as the turn's reasoning.
2026-10-10 19:22:07 -07:00

25 lines
1.0 KiB
Python

"""Message hygiene at the resolved auxiliary client boundary."""
from openai import AsyncOpenAI, OpenAI
from agent.transports.chat_completions import ChatCompletionsTransport
def prepare_chat_messages(client, kwargs: dict) -> dict:
"""Sanitize actual Chat Completions SDK requests, not native adapter replay.
Auxiliary and MoA callers can retain a prepared request before the virtual
transport sanitizes its copy. The resolved SDK client identifies the wire;
native Messages/Responses adapters must retain their reasoning sidecars.
"""
if not isinstance(client, (OpenAI, AsyncOpenAI)) or "messages" not in kwargs:
return kwargs
from agent.reasoning_carriers import shape_wire_carriers
base_url = str(getattr(client, "base_url", "") or "")
messages = ChatCompletionsTransport().convert_messages(
shape_wire_carriers(kwargs["messages"], model=kwargs.get("model"), base_url=base_url),
model=kwargs.get("model"), base_url=base_url,
)
return {**kwargs, "messages": messages}