Repository navigation
feat(mod): report unanswered worker turns and name the conversation on state reports - #67
Merged
Merged
Conversation
A lich subagent worker whose final turn ended blank or refused posted
nothing, so its caller waited on an errand that would never be answered.
The mod now posts {session_id, unanswered: blank|refusal} to /mod/answer
when the turn's own main-loop Stop lists no background task. An aborted
turn still posts nothing.
unanswered: error stays unsent: an API error fires StopFailure instead of
Stop, and in Claude Code 2.1.296 neither StopFailure's input nor
turn.complete's carries background_tasks, so the mod cannot tell the
failed turn left nothing running.
turn.complete is now matched once per reason, so every turn drops the
Stop it read. mod-answer.jsonl is read at lich's unreleased 040195f5.
An agent CLI run as a tool inside a lich session (claude -p, cursor-agent -p) inherits LICH_* and its hooks reported as the host card: a nested cursor-agent -p SessionEnd closed the host's relay errands. lich now drops a state report whose provider_session_id is not the bound one. Every /hook report now carries provider_session_id when the harness hands one over: report-state.sh and report-tool.sh read .conversationId // .session_id off stdin (sed fallback without jq), opencode the event's sessionID, omp ctx.sessionManager.getSessionId(), and mod-compacting $.session.id(). report-state.sh reads stdin for every state now, bounded at one second so a pipe nobody writes to cannot hold the turn. session-state.jsonl is read at lich's unreleased faa40def.
report-session-start.sh, report-state.sh and report-tool.sh each parsed .conversationId // .session_id with the same sed fallback. They now source hooks/conversation-id.sh and call conversation_id on the payload. A script shipped without the helper still reports, without the conversation.
A file-shipped install without the helper ran on silently. Each script now writes one line naming the missing file and what is lost, then reports as before: state and tool without provider_session_id, session-start not at all.
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.
Implements the plugin side of two lich contracts merged on lich main: lichdotdev/lich#705 (unanswered turns, 19e808e4) and lichdotdev/lich#709 (
provider_session_id, ce8c36a6). Fixtures are vendored byte-identical from those merge commits; both are in no lich release yet, sorefresh-fixtures.shpins them by commit until one ships. No version bump.Unanswered turns (
hooks/worker-answer.js)turn.completereasonrefusal, and withbackground_tasksempty, posts{session_id, unanswered: "blank" | "refusal"}to/mod/answer, so the caller stops waiting.errorstays pending:StopFailurecarries nobackground_tasks(measured on Claude Code 2.1.296), so the mod cannot tell nothing is left running, and it does not guess.provider_session_idon every state and tool reportbusy/done/tool report names the conversation it comes from, so lich can drop reports from an agent CLI the session runs as a tool (claude -p,cursor-agent -p), which inherits the session'sLICH_*variables.report-state.shnow reads stdin for every state, bounded to one second so an unwritten pipe cannot hold the turn.Shared
hooks/conversation-id.shprovider_session_id; session-start is not reported) and writes one line to stderr naming the file and what is lost. A test covers it.Checks
node --test tests/*.test.mjs: 393 passclaude plugin test .: 32 passclaude plugin validate: passesrefresh-fixtures.shleavestests/fixturesunchanged