feat: add generic hook emission for external integration#56
Open
comicchang wants to merge 5 commits into
Open
Conversation
comicchang
force-pushed
the
main
branch
5 times, most recently
from
July 2, 2026 02:05
e5fde08 to
1f23c2c
Compare
…eps fix - Add omp-compat.ts: agent config dir and CLI derived from process name - resolveAgentConfigDir() uses argv[0] to pick ~/.omp/agent or ~/.pi/agent - resolveDefaultCli() derives CLI binary from the same process name - buildSessionArgs() maps CLI args: pi --session vs omp --session-dir + --auto-approve - PI_CODING_AGENT_DIR / PI_SUBAGENT_CLI env var overrides - Add generic hook emission for external integration (hook.ts) - Mark peerDependencies as optional for standalone installs - 11 new omp tests + hook tests, 134 existing tests pass
comicchang
force-pushed
the
main
branch
5 times, most recently
from
July 2, 2026 03:29
2d5ac9c to
9a7ea15
Compare
- omp-compat.ts: resolveAgentConfigDir, resolveDefaultCli, buildSessionArgs - omp uses --session <file> (same as pi) + --auto-approve -p (non-interactive auto-exit) - Agent discovery from ~/.omp/agent/agents/, CLI derived from config dir name - No wrapper script, no sentinel files, no mtime-based session lookup - 10 new tests + 134 existing tests pass
…e JSONL location Root cause: omp generates its own session filename, so --session <deterministic-path> doesn't match the actual file. Parent reading the deterministic path gets no assistant output → 'Sub-agent exited without output'. Changes: - buildSessionArgs: omp uses --session-dir <dir> + --auto-approve (no -p/--mode) - watchSubagent: prioritize running.sessionDir scan over actualSessionFile sidecar - subagent-done: autoExit=true writes sidecar before shutdown; autoExit=false normal turn does NOT write done sidecar (only error sidecar for failures) - interpretExitSidecar: omit actualSessionFile key when absent (fixes deepEqual tests) - Add cli identifier to Pi/omp RunningSubagent - Improve fallback error messages with session file path diagnostics - Add omp JSONL fixture test and actualSessionFile presence/absence tests - Include test-omp-compat.ts in default npm test
When the last assistant message contains only thinking + toolCall (e.g. subagent_done) with no text block, findLastAssistantMessage now falls back to extracting text from the matching toolResult entry. This handles the common case where an auto-exit agent calls subagent_done without producing a text summary first — previously the parent would report 'No assistant text found in session'.
SubagentParams/AgentDefaults 新增 pane 布尔字段,launchSubagent 实现 pane:false 后台 omp launch/watch(复用命令组装、独立轮询 .exit sidecar + child exit fallback),handleSubagentInterrupt 对后台返回 unsupported。新增 11 个 pane 相关测试,更新 README 文档。
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.
Add Generic Hook Emission for External Integration
Summary
This PR adds a generic hook system to pi-interactive-subagents that emits subagent lifecycle events to external tools. The primary use case is integrating with tmux-agent-sidebar to display subagent status in the tmux sidebar.
Motivation
pi-interactive-subagents has its own TUI widget for displaying subagent status, but users who use tmux-agent-sidebar cannot see subagent status in their tmux sidebar. This PR adds a generic, decoupled hook mechanism that allows any external tool to receive subagent lifecycle events.
Design Principles
Generic and decoupled: The hook system doesn't know about tmux-agent-sidebar or any specific consumer. It's a generic telemetry sink.
Best-effort, fail-open: Hook failures never affect subagent lifecycle. Spawn errors, timeouts, and non-zero exits are silently ignored.
Robust protocol: JSON payload on stdin (not argv) for robustness. No shell quoting issues, no argv length limits.
Fan-out support: Multiple hook commands can be configured for different consumers (sidebar, logging, metrics, etc.).
Versioned payloads: Schema versioning prevents future refactors from breaking consumers.
Ordering protection: Sequence numbers and status throttling prevent out-of-order events.
Changes
New Files
pi-extension/subagents/hook.ts: Hook emission module with:loadHooksConfig(): Load config from config.jsonfireHook(): Emit events to configured commandsemitSubagentStart/Status/Stop(): Lifecycle helpersModified Files
pi-extension/subagents/index.ts: Integrated hook emissions at:config.json.example: Added hooks configuration exampleREADME.md: Added comprehensive hooks documentationHook Protocol
Invocation
Example
tmux-agent-sidebar hook pi subagent-start # stdin: {"version":1,"source":"pi-interactive-subagents","event":"subagent-start","id":"abc","name":"Scout",...}Events
subagent-startstartingsubagent-statusstarting,active,waiting,stalled,runningsubagent-stopdone,failed,cancelledPayload Schema
Configuration
{ "hooks": { "enabled": true, "status_throttle_ms": 5000, "timeout_ms": 1000, "commands": [ { "command": "tmux-agent-sidebar", "args": ["hook", "pi"], "events": ["subagent-start", "subagent-status", "subagent-stop"] } ] } }Multiple Commands (Fan-out)
{ "hooks": { "commands": [ { "command": "tmux-agent-sidebar", "args": ["hook", "pi"] }, { "command": "/usr/local/bin/audit-log", "args": [], "events": ["subagent-start", "subagent-stop"] } ] } }tmux-agent-sidebar Integration
To display pi subagent status in tmux-agent-sidebar, a
piadapter needs to be added to tmux-agent-sidebar that parses these events:subagent-start→AgentEvent::SubagentStartsubagent-status→ NewAgentEvent::SubagentStatuseventsubagent-stop→AgentEvent::SubagentStopThe adapter would parse the JSON payload from stdin and map it to the internal event representation.
Testing
Breaking Changes
None. This is a purely additive feature.
Checklist