fix(streaming): don't split tool-call arg deltas into separate calls (kimi-coding) - #12
Closed
Fede654 wants to merge 10 commits into
Closed
fix(streaming): don't split tool-call arg deltas into separate calls (kimi-coding)#12Fede654 wants to merge 10 commits into
Fede654 wants to merge 10 commits into
Conversation
# Conflicts: # gateway/run.py # hermes_cli/kanban.py # model_tools.py
# Conflicts: # agent/conversation_loop.py # cli.py # gateway/run.py # hermes_cli/main.py
Add browser automation via Kimi WebBridge daemon (local HTTP on :10086). Unlike Playwright-based browser tools, this controls the user's REAL browser with their actual login sessions. Tools: - kimi_webbridge_navigate, find_tab, snapshot, click, fill, evaluate - kimi_webbridge_screenshot, save_screenshot, save_pdf - kimi_webbridge_list_tabs, close_tab, close_session Config: providers.kimi_webbridge.base_url (defaults to 127.0.0.1:10086) Off by default (requires separate extension + daemon install). Includes 26 tests with mocked daemon responses.
Extract the true AutoResearch functionality from the archived feat/autoresearch branch without provider/docs churn from Fede's broader fork.
The Kimi Coding Plan picker (hermes_cli/model_setup_flows.py:1800) had a hardcoded model_list that included kimi-k2.6, k2.5, kimi-for-coding, k2-thinking, k2-thinking-turbo, but NOT kimi-k2.7-code (the new coding model Moonshot released 2026-06-12, available on Allegro tier). The general catalog (hermes_cli/models.py:60) had it, but the curated Coding Plan picker filtered it out. Added kimi-k2.7-code as the first option, alongside the same edit in the deprecated copy in hermes_cli/main.py and the kimi-coding curated list in hermes_cli/models.py:282. OAuth detection: resolve_kimi_coding_runtime_credentials() already reads ~/.kimi/credentials/kimi-code.json, the runtime_provider auto-routes to api.kimi.com/coding/v1, and the X-Msh-* headers are applied — k2.7-code just needs to be selectable. Now it is.
The info command showed a hardcoded default of '60', but the actual code default from _get_env_config is 180. This mismatch confused users into thinking the timeout was 60s when it was actually 180s.
Adds the v0.16.0 release entry to the project CHANGELOG with: - TL;DR for team members on older agents (5 bullet upgrade steps) - Detailed changelog of all 4 changes that landed on top of upstream sync - Verification commands (hermes --version, hermes tools, hermes model, OAuth test) - List of what did not make it (video-gen-minimax PR, tui-history-nav fix) - DaemonCraft preservation note - Source-of-truth references (MEMORY.md, branch-stewardship note, HMK ch 61) The release note is also mirrored to: - ~/wiki/projects/hermes-agent/notes/release-v0.16.0-2026-06-14.md (wiki; propagated via compaii-state sync) - HMK chapter 62 (library; queryable by future CompAII instances) Together these give CompAII agents on older hermes-agent forks a self-service upgrade path.
Fede654
force-pushed
the
fix/streaming-toolcall-fragmentation
branch
from
June 15, 2026 18:22
68c5a05 to
c0e1fb4
Compare
…arate calls
The chat_completions streaming accumulator's Ollama new-slot heuristic
fired whenever a delta reused a raw index with a different tool_call id.
kimi-coding sends a *changing* id on every argument-continuation delta, so
each JSON fragment ('{"', 'query', '":', 'oro', ...) was redirected to a
fresh slot and surfaced as its own bogus, unparseable tool call (name '?'),
making every web_search/web_extract/read_file fail.
Gate the new-slot redirect (and the _last_id tracking) on the delta also
carrying a function.name — a genuine new tool call always opens with a
name, continuation deltas never do. Preserves the Ollama same-index/new-id
case; fixes kimi-coding fragmentation.
…ation
kimi-coding (and other chat_completions providers) can return a tool call
whose JSON arguments were cut off mid-generation (e.g. '{"') while
under-reporting finish_reason as 'stop'/'tool_calls' instead of 'length'.
The existing truncated-tool-call retry/boost path only fired on
finish_reason=='length', so these were silently sanitized to '{}' and the
agent looped on an empty tool call (surfacing the misleading 'Response
truncated due to output length limit').
Add _has_truncated_tool_call_args() and upgrade finish_reason to 'length'
when a chat_completions tool call has args that open as a JSON object/array
but fail to parse, routing it into the existing retry/boost recovery.
Refs NousResearch#26425.
Fede654
force-pushed
the
fix/streaming-toolcall-fragmentation
branch
from
June 15, 2026 19:19
c0e1fb4 to
cbffe7a
Compare
nicoechaniz
added a commit
that referenced
this pull request
Jul 7, 2026
Tests the two changes cherry-picked from Fede654 PR #12: - _has_truncated_tool_call_args: 16 cases covering api_mode guard, empty/None/non-string args, valid JSON (object + array), truncated JSON (object + array + garbage), dict-shaped tool_calls, multi-tool-call batches, whitespace handling. - Tool-call delta fragmentation gate: asserts that argument-continuation deltas (no function.name) at a reused index do NOT redirect to a new slot (kimi-coding case), while same-index + new-id + with-name still redirects (Ollama case must keep working). Refs #12 (cherry-picked: 7c50ae9, cbffe7a).
Fede654
added a commit
to Fede654/hermes-agent
that referenced
this pull request
Aug 10, 2026
Merged nicoechaniz/main (d5812ea) into the canonical integration and switched the fork to consume-only. - Operating principles now say "consume from Nico, don't push upstream"; the delta stays clean for cheap merges, not for upstreamability. - "Upstream collaboration" retired: PRs nicoechaniz#11/nicoechaniz#12/nicoechaniz#13 closed 2026-08-10 after ~2 months open while his main moved 8k commits (and nicoechaniz#11's target, the autoresearch core, had been dropped from his fork entirely). - PR-hygiene/CI section replaced with sync-time failure triage: reproduce on pristine nicoechaniz/main and on the previous canonical, disable pytest-randomly before believing a failure, and pip install -e . first so missing acp/multipart deps don't read as mass breakage. - Track the kimi OAuth routing bug doc, which Nico's 68932e3 / 5e3034b now plausibly fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a kimi-coding deployment, every tool-using turn (
web_search,web_extract,read_file, …) failed; the user saw the misleading "Response truncated due to output length limit" (a 48-char error reply). It is not an output-length /max_tokensissue (failing turns were ~4–9 s, tiny output) and not a platform message-length limit (Telegram/WhatsApp both chunk correctly).Root cause
The
chat_completionsstreaming accumulator inagent/chat_completion_helpers.pymerges tool-call argument deltas byindex. Its "Ollama fix" redirects to a fresh slot whenever a delta reuses a rawindexwith a different tool_callid(handles Ollama emitting a back-to-back second tool call at the same index).kimi-coding sends a changing
idon every argument-continuation delta, so each streamed JSON fragment ({",query,":,oro, …) tripped the new-slot heuristic and became its own bogus, unparseable tool call (name?). Downstream sanitization replaced each with{}("Unrepairable tool_call arguments"), so the tool ran with empty args and the agent looped, finally surfacing the truncation error. Overlaps with NousResearch#26425.Fix
A genuine new tool call always opens with a
function.name; argument-continuation deltas carry onlyfunction.arguments. Gate the new-slot redirect (and the_last_id_at_idxtracking) on the delta also carrying a name. Provider-neutral — no hardcoded models; preserves the Ollama same-index/new-id-with-name case, fixes the kimi-coding fragmentation.Second commit (
fix(truncation)): detects a tool call whose JSON args open but don't parse as a genuine length-truncation and routes it into the existing retry/boost path instead of silently sanitizing to{}.Validation
web_search→searxng andweb_extract→firecrawl both work end-to-end, zeroUnrepairable tool_call argumentswarnings (vs. a flood before).tests/gateway/test_stream_consumer*.py— 119 passed, no regression.py_compileclean on all touched files.Refs NousResearch#26425.
🤖 Generated with Claude Code