Skip to content

feat(cli): add result metadata fd transport - #19

Merged
cermm merged 1 commit into
mainfrom
issue-358-result-meta-fd-attrib-63fd98ddb2
Aug 16, 2026
Merged

feat(cli): add result metadata fd transport#19
cermm merged 1 commit into
mainfrom
issue-358-result-meta-fd-attrib-63fd98ddb2

Conversation

@cermm

@cermm cermm commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Summary

Supersedes #18 with contributor attribution repaired while preserving the exact reviewed tree.

Implements the NousResearch#358/NousResearch#401 producer-bound --result-meta-fd transport on current cermm/hermes-agent main.

  • Adds closed-world hermes-agent-result-meta-v1 frame generation.
  • Preserves legacy process exit behavior when the flag is absent.
  • With a valid result-metadata FD, a zero process exit means the frame was published; semantic failure/interruption remains in the frame.
  • Publishes bounded interrupted and unknown_failure frames for quiet KeyboardInterrupt / unexpected exceptions without raw exception/path/secret leakage.
  • Rejects duplicate --result-meta-fd options before descriptor claim/startup and keeps the standalone parser aligned.

Exact gate evidence

Base/fork main before candidate: e0c3e1b098e719d2f7327b202755ace76414212f.
Previous reviewed commit/tree: 18b50851f037c4686bd6be77aff092098973c899 / bb1e4c3ada50641c5ecbf0a7260018f4bb76db5f.
This commit/tree: 63fd98ddb2317702026019934a3b9eb64591ef76 / bb1e4c3ada50641c5ecbf0a7260018f4bb76db5f.
Tree equality: exact; only author/committer attribution changed to the repository-accepted 53539590+cermm@users.noreply.github.com identity after CI rejected hermes-agent@local on #18.
Reviewed Kanban gates: t_f74bbba6 repair handoff, t_2a4921d3 independent GPT-5.6 PASS (PASS_REVIEW_RESULT_META_FD_DUPLICATE_REPAIR).

Local verification rerun from /home/michal/worktrees/nousresearch-hermes-agent/issue358-result-meta-current-main-20260816 before the tree-identical attribution repair:

  • scripts/run_tests.sh tests/hermes_cli/test_result_metadata.py tests/hermes_cli/test_result_metadata_cli.py -q → 44 passed, 0 failed.
  • 12-file affected CLI suite (test_result_metadata*, parser/flags/startup/safe-mode/relaunch/coalesce/container/yolo/subparser) → 209 passed, 0 failed.
  • /home/michal/.hermes/hermes-agent/venv/bin/python -m ruff check cli.py hermes_cli/_parser.py hermes_cli/main.py hermes_cli/result_metadata.py tests/hermes_cli/test_result_metadata.py tests/hermes_cli/test_result_metadata_cli.py → All checks passed.
  • python -m compileall -q on six Python scope files → exit 0.
  • python -m hermes_cli.main chat --help exposes --result-meta-fd.
  • git diff --check → exit 0.

Boundaries

This is repository code/docs/tests only. It does not mutate live Hermes profiles, SOUL files, auth stores, runtime config, canary state, rollout state, or wc-infrastructure issue closure.

Refs cermm/wc-infrastructure#358
Refs cermm/wc-infrastructure#401

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63fd98ddb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +119 to +124
for descriptor_root in ("/proc/self/fd", "/dev/fd"):
try:
descriptor_target = os.readlink(f"{descriptor_root}/{fd}")
break
except OSError:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept anonymous pipes on non-Linux POSIX

On macOS and BSD, /dev/fd/<n> entries are generally descriptor nodes rather than symlinks whose targets begin with pipe:, while /proc/self/fd is unavailable by default. Consequently, a valid anonymous-pipe writer reaches descriptor_target is None and is rejected, making the option unusable on platforms covered by the documented “POSIX systems” support claim. Use a platform-appropriate descriptor identity check or narrow the supported-platform contract.

Useful? React with 👍 / 👎.

Comment thread cli.py
Comment on lines +12594 to +12595
if getattr(self, "result_meta_fd", None) is not None:
self._publish_result_metadata(result)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish a failure frame when nonquiet chat setup fails

For the default nonquiet hermes chat -q path, publication occurs only after all preceding chat/display work succeeds. If any of that work raises—for example thread startup, stream flushing, or another pre-publication UI operation—the existing chat() catch at lines 12818–12820 swallows the exception and returns None; the outer command then exits successfully while the ownership guard merely closes the pipe, so the caller receives EOF with no frame despite a zero process status. Publish an unknown_failure frame from that exception path or otherwise ensure every successful process exit after claiming the descriptor has written a frame.

Useful? React with 👍 / 👎.

Comment on lines +195 to +200
for key in ("completed", "failed", "partial", "interrupted"):
defaultable = key != "completed"
value = result.get(key, False)
if (key not in result and not defaultable) or type(value) is not bool:
valid = False
value = False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve Codex app-server interruption status

When a Codex app-server turn is interrupted, agent/codex_runtime.py returns completed=False and partial=True but does not include an interrupted key. Defaulting the missing field to False here causes build_result_metadata() to classify that turn as max_turns_or_incomplete, so automation cannot distinguish a user cancellation from exhaustion. Normalize this runtime's result shape or infer its interruption signal before projecting the public metadata.

Useful? React with 👍 / 👎.

@cermm
cermm merged commit 4a440e0 into main Aug 16, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant