- Add stripPreamble() to handle LLM output with text before ---
- Strengthen system prompt: CRITICAL instruction for --- at position 0
- Fixes frontmatter parsing failures on first output turn
Previously runBuiltinWithMessages deleted the session jsonl after each
run/continue call. This meant the createAgent retry mechanism (which
calls continue on frontmatter validation failure) would lose all
previous turn data — each continue started with an empty jsonl.
Now the session jsonl accumulates across run + continue calls, so the
final storeBuiltinDetail captures all turns. The jsonl file is left
behind for debugging; it's small and can be cleaned up on next startup.
Also add a workflow hint to the system prompt reminding the LLM to use
tools before outputting frontmatter, preventing premature text-only
responses on the first turn.
Each turn (assistant response / tool result) is appended to a JSONL file
at ~/.uncaged/workflow/sessions/<sessionId>.jsonl during the loop.
On completion, the JSONL is read back, each turn is stored as a CAS node,
and the detail payload references them as a flat turns[] array in
chronological order. The session file is then deleted.
Benefits:
- Real-time observability: tail -f the JSONL to watch loop progress
- Crash recovery: partial JSONL survives process death
- Zero write contention: one file per session
- Detail stays a flat array for easy consumption by CLI/dashboard
Changes:
- New session.ts: initSessionDir, appendSessionTurn, readSessionTurns, removeSession
- loop.ts: append JSONL each turn instead of accumulating in-memory
- detail.ts: reads session JSONL → persists turns to CAS → stores detail
- agent.ts: passes storageRoot/sessionId to loop, cleans up session on completion
- types.ts: remove index from TurnPayload (order is implicit in JSONL/array)
- schemas.ts: sync with type changes
Ref: #433
- StepRecord adds edgePrompt field (backward compat: defaults to "")
- StepNode CAS schema includes edgePrompt
- writeStepNode persists ctx.edgePrompt
- buildHistory exposes edgePrompt in StepContext
- buildBuiltinMessages reconstructs multi-turn moderator↔agent conversation:
system = role prompt + output format (stable prefix)
per prior visit: user (edgePrompt + inter-step summary) + assistant (output)
current: user (edgePrompt + recent summary)
- Zero extra persistence — pure function of CAS chain
- Stable prefix for LLM prompt cache hits
- 10 builtin tests pass, all other package tests pass
System message = agent identity (role prompt + output format instruction)
User message = moderator speech (task + edge prompt + history)
This reflects the workflow's core model: moderator speaks to agent
via the graph's edge prompt. Previously all content was in a single
system message with no user message, causing Claude API 400 errors.
- buildBuiltinPrompt now returns { system, user } instead of string
- agent.ts sends system + user as separate messages
- Tests updated accordingly
- Replace resolvePathInWorkspace with simple resolvePath (no boundary check)
- Remove UWF_BUILTIN_ALLOW_SHELL env gate from run_command
- Update tests accordingly
Per review: sandbox was false security with shell=true, and path
restrictions are unnecessary for a trusted agent environment.
Built-in role agent that uses workflow config models directly,
with its own tool-calling run loop. No external agent dependency.
- OpenAI-compatible chat completion client with tool_calls support
- P0 toolkit: read_file, write_file, run_command
- Integrates via createAgent factory from workflow-agent-kit
- CAS detail recording for each turn
- Path sandboxing and shell opt-in (UWF_BUILTIN_ALLOW_SHELL)