Two bugs fixed:
1. request_permission messages (JSON-RPC requests with both id+method) were
silently swallowed by the response handler, causing hermes to hang waiting
for permission approval. Now properly distinguish responses (id only) from
server requests (id+method).
2. uwf-hermes process never exited after completing because the hermes ACP
subprocess was still alive. Now explicitly close the ACP client after
agent completion so the subprocess terminates.
小橘 <xiaoju@shazhou.work>
The official TS SDK's ndJsonStream hangs indefinitely on prompt()
for sessions with 20+ messages (solve-issue planner). Root cause
appears to be a stream backpressure issue in the SDK's ReadableStream
adapter.
Switch back to readline-based line parsing which reliably receives
all JSON-RPC responses. Also handle session/request_permission
inline (auto-approve, yolo mode equivalent).
Ref #398
UwfAcpClient now tracks all session/update events:
- agent_message_chunk → assistant message content
- agent_thought_chunk → assistant reasoning
- tool_call → pending tool invocation (name + rawInput)
- tool_call_update (completed/failed) → assistant tool_call + tool result
Messages are accumulated across prompts (same session) and stored
via storeHermesSessionDetail, restoring the full structured detail
(turns with tool calls, reasoning) that was lost in the initial ACP
migration.
Ref #398
The client is now created once in createHermesAgent() and shared by
runHermes and continueHermes closures. This preserves conversation
context during frontmatter retry loops — continue() sends a follow-up
prompt on the same ACP session instead of starting a new one.
Client is cleaned up via process.on('exit').
Ref #398
Replace 250-line custom ACP client with official TypeScript SDK.
Uses ClientSideConnection + ndJsonStream for stdio transport.
Same public API (connect/prompt/close), 115 lines, zero custom protocol code.
Ref #398
Remove spawnHermes, spawnHermesChat, spawnHermesResume, parseSessionId,
and buildResultFromSession. runHermes and continueHermes now use
HermesAcpClient for structured JSON-RPC communication.
Session ID comes directly from ACP protocol, eliminating #380 race
condition. Agent output collected via streaming chunks instead of
session file loading.
Phase 2 of RFC #398Fixes#380
Implements JSON-RPC client that communicates with `hermes acp` via
stdin/stdout. Replaces fragile stdout/stderr parsing with structured
protocol: initialize → session/new → session/prompt → collect chunks.
Session ID comes directly from protocol response, eliminating the
race condition in #380.
Phase 1 of RFC #398
buildOutputFormatInstruction now includes explicit language telling agents to
output ONLY schema-defined fields and to focus on their role's deliverable.
Fixes#394
Claude Code CLI adapter for the workflow engine, mirroring
workflow-agent-hermes architecture. Spawns `claude -p` with
`--output-format json` for structured output parsing.
Refs #391
Send a test completion request after configuration to verify the model
is reachable. If validation fails, warn the user and suggest trying a
different model or checking their settings.
Fixes#335
Replace hardcoded 5-field example with schema-driven generation.
Now shows actual enum values, types, and required markers for
each role's frontmatter schema.
Fixes#389
小橘 <xiaoju@shazhou.work>
Replace hardcoded 5-field candidate with schema-driven extraction.
Now reads outputSchema properties and picks matching fields from
parsed frontmatter, supporting role-specific fields like plan,
approved, success.
Falls back to standard 5 fields when schema has no properties.
Fixes#388
小橘 <xiaoju@shazhou.work>
Agent CLI outputs plain CAS hash (not JSON), engine parses plain hash.
StepOutput no longer carries sessionId — session info is already in CAS detail.
Keeps the valuable parts of #385: sessionId in AgentRunResult (process-internal),
continue support, and frontmatter retry loop.
Breaking changes:
- AgentRunResult now requires sessionId field
- AgentOptions now requires continue function
- Agent CLI outputs JSON {stepHash, sessionId} instead of plain CAS hash
- Engine parses JSON output (with legacy CAS hash fallback)
New features:
- Frontmatter validation retry: if agent output lacks valid frontmatter,
engine calls agent.continue() up to 2 times with correction message
- Session tracking: sessionId flows from agent → engine → StepOutput
- Hermes agent: session parse failure is now a hard error (no raw text fallback)
- Hermes agent: supports --resume for continue sessions
Closes#384
Agent output must contain valid YAML frontmatter matching the role schema.
If frontmatter parsing fails, the step fails immediately with a clear error
instead of falling back to an LLM extraction that can fabricate values.
The extract module remains as a public API export but is no longer used
in the agent run loop.
Breaking change: agents that relied on LLM extraction to produce valid
output will now fail. They must output proper frontmatter.
Add --count/-c flag to 'uwf thread step' for running N steps in one
invocation, stopping early if $END is reached.
- cmdThreadStep now loops up to count times, delegates to cmdThreadStepOnce
- CLI parses -c/--count, defaults to 1 (backward compatible single output)
- Validation rejects 0, negative, and non-integer counts
- 7 new tests covering CLI parsing and count validation
Fixes#373
Co-authored-by: uwf-hermes (solve-issue workflow)
Fallback transitions (last entry in graph node) omit the condition
field in YAML, resulting in undefined instead of null. The validator
and materializer now handle this:
- validate.ts: accept undefined as valid condition value
- workflow.ts: normalizeGraph() coerces undefined → null before CAS put
This was broken by the graph fallback pattern introduced in #370.
Register custom $first(role) and $last(role) functions in the JSONata
evaluator. These search the steps array and return the matching role's
frontmatter (output) directly, replacing verbose steps[-1].output.x
expressions with semantic $last('role').field syntax.
- workflow-moderator: register functions via expr.registerFunction()
- Updated all condition expressions in .workflows/ and examples/
- Added tests for $last, $first, and unmatched role (undefined)
Fixes#376
- Last transition in each graph node is now the fallback (no condition)
- Remove redundant positive conditions (ready, devDone, approved, passed, pushSuccess)
- notApproved → rejected (positive naming)