mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
Keep reserved workers able to persist during drain, join actual in-process writers before releasing a profile, and reap children created after cancelled process acquisition. Reopening a worker outbox reconciles its pending receipt; managed results retain per-turn usage and bounded live tool details.
This commit contains the physical-worker foundation only. Mutation-task and Bot mailbox lifetime tracking are separate follow-ups. The existing zero-second restart drain default is unchanged.
Validation: scripts/run_tests.sh -j 4 across 10 worker/runtime files: 26 passed, 1 POSIX-only skip on native Windows. Includes a real managed child completing its durable receipt during a configured restart drain. The unchanged upstream one-second retirement test missed its deadline once under parallel load and passed the runner retry; an isolated rerun passed both cases without retries. Logs: split-W-tests.log, split-W-retirement-rerun.log.
Review-source: helix4u, https://github.com/NousResearch/hermes-agent/pull/106742#issuecomment-6024687448
Review-source: greptile-apps, https://github.com/NousResearch/hermes-agent/pull/106742#discussion_r4211047305
Review-source: greptile-apps, https://github.com/NousResearch/hermes-agent/pull/106742#discussion_r4211047387
Review-source: greptile-apps, https://github.com/NousResearch/hermes-agent/pull/106742#discussion_r4213427126
Review-source: dokterdok, https://github.com/NousResearch/hermes-agent/pull/106742#discussion_r4211144039
Source-base: NousResearch/hermes-agent#106742 at 0b815190b2
(cherry picked from commit 6156b21c5e3fa5e9295a13d5e02caa9b959ada82)
31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
"""Viewer payload limits; the full tool input/output stays in canonical history."""
|
|
import json
|
|
|
|
MAX_TOOL_EVENT_CHARS = 64 * 1024
|
|
|
|
|
|
def bounded_args(args):
|
|
encoded = json.dumps(args, ensure_ascii=True, default=str)
|
|
if len(encoded) <= MAX_TOOL_EVENT_CHARS:
|
|
return args
|
|
# Retain ordinary scalar paths/commands for editor locations even when a content field is large.
|
|
result = {}
|
|
remaining = MAX_TOOL_EVENT_CHARS // 2
|
|
for key, value in args.items():
|
|
if remaining <= 0 or len(result) >= 64:
|
|
break
|
|
name = str(key)[:256]
|
|
text = value if isinstance(value, str) else json.dumps(value, ensure_ascii=True, default=str)
|
|
text = text[:min(4096, remaining)]
|
|
result[name] = text
|
|
remaining -= len(json.dumps([name, text], ensure_ascii=True))
|
|
return result
|
|
|
|
|
|
def bounded_result(result, is_error):
|
|
text = result if isinstance(result, str) else json.dumps(result, ensure_ascii=True, default=str)
|
|
if len(text) <= MAX_TOOL_EVENT_CHARS:
|
|
return text
|
|
# ACP reads errors from the result as well as the event flag; keep valid JSON after truncation.
|
|
return json.dumps({'error' if is_error else 'output': text[:MAX_TOOL_EVENT_CHARS // 2], 'truncated': True})
|