Commit Graph

752 Commits

Author SHA1 Message Date
xingyue 603018caf2 fix(builtin): force-strip tool_calls when noTools is set
copilot-api returns tool_calls even when tools field is omitted from
the request (infers from message history). Now the loop explicitly
nullifies tool_calls when noTools=true.
2026-05-23 22:35:20 +08:00
xiaomo aff0ee6fea Merge pull request 'fix(thread-read): remove ### Output section and deduplicate ### Prompt globally' (#442) from fix/440-thread-read-prompt-dedup into main 2026-05-23 14:15:40 +00:00
xiaomo d37fa1393a Merge pull request 'fix: preserve primary detail hash across frontmatter retries' (#443) from fix/439-detail-merge-and-acp into main 2026-05-23 14:14:53 +00:00
xiaoju 759c784267 fix: preserve primary detail hash across frontmatter retries
When the agent's first run output fails frontmatter extraction, the
retry loop (via options.continue) would replace agentResult entirely,
causing the 1-turn continuation detail to overwrite the original
multi-turn detail containing all tool-call history.

Now we capture primaryDetailHash from the first run and always use it
for the persisted StepNode, regardless of how many retries occur.

Fixes #439
2026-05-23 14:02:51 +00:00
xingyue 52ffc7dcc1 fix(thread-read): remove ### Output section and deduplicate ### Prompt globally 2026-05-23 22:01:24 +08:00
xingyue ac55a3e3d9 fix(builtin): nudge LLM when it stops tools without frontmatter
LLM sometimes emits plain text (e.g. 'Now I'll write the tests...')
without calling tools, which the loop treated as final output. Now
the loop detects this and injects a user message nudging the LLM
to either continue using tools or output frontmatter with ---.
2026-05-23 21:49:07 +08:00
xingyue edb979baa9 fix(builtin): disable tools during continue/retry to force frontmatter output
Agent was using all continue turns to keep calling tools instead of
outputting the required frontmatter. Now continue runs with noTools=true,
forcing LLM to emit text-only response.

Also supports null tools in chatCompletionWithTools to omit tools from
the API request entirely.
2026-05-23 21:40:30 +08:00
xingyue 3d1850ddbe fix(builtin): tell agent not to use uwf CLI to discover its task
Agent was wasting all 30 turns using uwf/tea CLI to explore threads
instead of reading the task from its own user message.
2026-05-23 21:30:59 +08:00
xingyue 3c1f4a6dfa fix(builtin): include cwd in system prompt
Agent was wasting turns exploring the filesystem because it didn't
know its working directory. Now the system prompt includes:
'Your working directory is: /path/to/cwd'
2026-05-23 21:27:24 +08:00
xiaomo f07a6daa30 Merge pull request 'fix(builtin): session lifecycle + frontmatter preamble stripping' (#441) from fix/builtin-session-lifecycle into main 2026-05-23 13:20:04 +00:00
xingyue 0eeb4a8ed8 fix(builtin): strip preamble before frontmatter + stronger prompt
- 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
2026-05-23 20:37:14 +08:00
xingyue a3fac708b6 fix(builtin-agent): don't delete session jsonl until process exits
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.
2026-05-23 20:32:38 +08:00
xiaomo 52879c0028 Merge pull request 'feat(cli-workflow): implement multi-strategy workflow resolution' (#438) from fix/428-multi-strategy-workflow-resolution into main 2026-05-23 11:12:56 +00:00
xiaoju 8720eb19af feat(cli-workflow): implement multi-strategy workflow resolution for issue #428
- Add 4-strategy resolution priority: CAS hash → file path → local discovery → global registry
- Add helper functions: isFilePath, workflowFileExists, findWorkflowInDir, findWorkflowInParents
- Refactor resolveWorkflowCasRef to support direct hash, explicit paths, and parent traversal
- Add comprehensive test suite with 24 tests covering all strategies and edge cases
- Support .workflow/ and .workflows/ directories with .yaml/.yml extensions
- All 60 tests pass across 5 test files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-23 11:11:37 +00:00
xiaomo 9e4527bb89 Merge pull request 'fix(cli): disable YAML anchor/alias in output' (#437) from fix/yaml-no-alias into main 2026-05-23 11:09:11 +00:00
xingyue 5209cfa7ac fix(cli): disable YAML anchor/alias + fix biome errors in setup.ts
- Disable aliasDuplicateObjects in YAML stringify to prevent &a1/*a1
  anchors when multiple steps have identical output
- Fix unused discoverAgents function (prefixed with _) and format issue
  in setup.ts
2026-05-23 19:07:36 +08:00
xiaoju 155b879d29 chore(workflow): developer must rebase main when bounced back
Prevents duplicate lint fixes when main already has the fixes.

小橘 🍊(NEKO Team)
2026-05-23 10:57:44 +00:00
xiaomo c1f04929f4 Merge pull request 'feat(builtin-agent): persist ReAct loop turns as session JSONL' (#434) from feat/turn-jsonl-session into main 2026-05-23 10:48:49 +00:00
xingyue 50cd93aa05 test: skip flaky hermes ACP tests (depend on live LLM)
Skip acp-client 'prompt() collects structured messages' and
resume-e2e 'resume() after close' — both require live LLM calls
and fail intermittently in CI.
2026-05-23 18:47:59 +08:00
xingyue 1abc3b4cf4 chore: fix all biome lint errors across monorepo
- Fix import ordering (organizeImports) across multiple packages
- Replace forEach with for...of loops (noForEach)
- Replace non-null assertions with fallback values (noNonNullAssertion)
- Add biome-ignore comments for justified noExplicitAny usages
- Remove parameter properties, use explicit class properties (noParameterProperties)
- Fix string concatenation to template literals (useTemplate)
- Fix format issues (CSS, TypeScript)
- Add tailwindDirectives CSS parser config in biome.json
- Replace var with const (noVar)

Result: 0 errors, 12 warnings (all cognitive complexity, acceptable)
2026-05-23 18:39:02 +08:00
xingyue 330db43b5f feat(builtin-agent): persist ReAct loop turns as session JSONL
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
2026-05-23 18:27:28 +08:00
xiaoju 211f38bc8d fix(claude-code): include edge prompt in agent prompt as Current Instruction
buildClaudeCodePrompt was dropping ctx.edgePrompt entirely — the graph
transition instruction (e.g. 'Implement the plan') never reached the agent.
Now appended as '## Current Instruction' at the end of the prompt.
2026-05-23 09:46:17 +00:00
xiaomo 613793e128 Merge pull request 'feat: builtin agent session resume via deterministic message reconstruction' (#427) from feat/426-builtin-session-resume into main 2026-05-23 09:39:32 +00:00
xingyue 080792a6c0 feat: builtin agent session resume via deterministic message reconstruction (#426)
- 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
2026-05-23 17:34:49 +08:00
xiaoju 43cbf4127f chore(solve-issue): remove redundant steps from planner frontmatter 2026-05-23 09:23:00 +00:00
xiaomo 9f95956e19 Merge pull request 'fix(builtin): split prompt into system/user messages' (#425) from fix/builtin-agent-system-user-split into main 2026-05-23 09:17:13 +00:00
xiaoju 65e2305761 improve(solve-issue): planner must locate repo and read code before planning
- planner procedure: locate repo (cwd/clone/create), read source files, reference actual code
- planner frontmatter: add repoPath as required field
- developer procedure: cd to repoPath, create branch, commit with issue ref
2026-05-23 09:16:51 +00:00
xingyue 44147da419 fix(builtin): split prompt into system/user messages
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
2026-05-23 17:15:23 +08:00
xiaoju bc64f2613b fix(thread): handle null stderr from execFileSync, increase maxBuffer to 50MB
- err.stderr can be null (not just undefined) when child process fails
- maxBuffer default (1MB) too small for stream-json verbose output
2026-05-23 08:58:05 +00:00
xiaoju 0e5b494e12 chore(debate): remove round limit, let step control drive pacing 2026-05-23 08:31:07 +00:00
xiaomo 747b318cc5 Merge pull request 'feat(claude-code): enrich step details with per-turn breakdown' (#423) from feat/422-claude-code-detail-enrichment into main 2026-05-23 08:19:20 +00:00
xiaoju d16ce44bc3 feat(claude-code): enrich step details with per-turn breakdown
Switch from --output-format json to stream-json --verbose to capture
per-turn data. Detail now includes:
- model name
- usage (input/output/cache tokens)
- stopReason
- turns[] as individual CAS nodes with role, content, tool calls

Also addresses PR #421 review fixes:
- sessionId guard: skip cache write when sessionId is empty/undefined
- silent catch: log resume failures with debug tag 5VKR8N3Q
- atomic write: session cache uses temp+rename for crash safety

Closes #422
2026-05-23 08:16:47 +00:00
xiaomo 45122bc458 Merge pull request 'fix: disable hermes resume, add claude-code resume support, debate workflow' (#421) from test/418-resume-e2e-repro into main 2026-05-23 07:59:53 +00:00
xiaomo 3183b4c879 Merge pull request 'feat: add @uncaged/workflow-agent-builtin package' (#420) from feat/builtin-agent into main 2026-05-23 07:57:44 +00:00
xiaoju 03eacbabb2 feat: add debate workflow for resume integration testing
Two-role debate (against/for) with up to 3 rounds per side.
Each role re-enters with session resume, making this an ideal
integration test for cross-process session continuity.

Supports early termination via concession (conceded=true in frontmatter).

Refs #418
2026-05-23 07:50:38 +00:00
xingyue cef4db9a87 refactor: remove workspace path sandbox and shell gate
- 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.
2026-05-23 15:50:30 +08:00
xiaoju 1afaeacd57 feat: extract session cache to agent-kit, add resume to claude-code agent
Move getCachedSessionId/setCachedSessionId from workflow-agent-hermes
into workflow-agent-kit so all agent adapters can share the same
session cache logic.

Add cross-process session resume to workflow-agent-claude-code:
on re-entry (isFirstVisit=false), look up the cached sessionId and
use 'claude --resume' to continue with full conversation history.

Cache file renamed from hermes-sessions.json to agent-sessions.json
to reflect its shared nature.

Refs #418
2026-05-23 07:44:02 +00:00
xingyue deac2336b6 feat: add @uncaged/workflow-agent-builtin package
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)
2026-05-23 15:29:55 +08:00
xiaoju aad2792754 fix(hermes): disable ACP session/resume by default
Hermes ACP _restore fails for custom providers — resolve_runtime_provider
throws and base_url/api_mode are lost, causing resume to silently create a
new session with no history. Prompt then returns empty text or refusal.

Disable resume by default. Set UWF_HERMES_RESUME=1 to opt back in.

Includes investigation notes in docs/investigations/.

Refs #418
2026-05-23 07:23:14 +00:00
scottwei 10642fdc45 Merge pull request 'test: failing e2e test for session resume bug (#418)' (#419) from test/418-resume-e2e-repro into main
Reviewed-on: uncaged/workflow#419
2026-05-23 06:49:54 +00:00
xiaomo 92020d2d78 Merge pull request 'docs: sync cli-reference with recent CLI additions' (#417) from chore/update-cli-reference into main 2026-05-23 06:48:20 +00:00
xiaomo cd0a79d72b chore: remove accidental pnpm-lock.yaml 2026-05-23 06:47:25 +00:00
xiaoju 3b6aa6525f test: add failing e2e test for session resume bug (#418)
Cross-process resume returns empty text on subsequent prompt.
This test documents the bug — expected to fail until #418 is fixed.
2026-05-23 06:43:47 +00:00
xiaomo 54631c43c7 docs: update cli-reference with log commands, --count flag, edge prompt concept 2026-05-23 06:32:27 +00:00
xiaomo 655b57c4b5 Merge pull request 'feat: add uwf log subcommands (list, show, clean)' (#415) from fix/413-log-subcommands into main 2026-05-23 06:27:15 +00:00
xiaoju 7faa8184ae feat: add uwf log subcommands (list, show, clean)
- uwf log list: list log files with sizes
- uwf log show --thread <id>: filter by thread ID
- uwf log show --process <pid>: filter by process ID
- uwf log clean --before <date>: delete old log files
- Tests: 12 new tests covering all subcommands

Implemented by solve-issue workflow, biome fixes applied manually.

Closes #413
Refs #411, #410
2026-05-23 06:23:56 +00:00
xiaoju 816137315e feat: add uwf log subcommands (list, show, clean)
- cmdLogList: list log files with sizes, sorted by date descending
- cmdLogShow: filter entries by thread, process, and/or date
- cmdLogClean: delete log files older than given date
- 12 tests covering all functions and edge cases

Fixes #413
2026-05-23 06:21:06 +00:00
xiaoju 9a111d16c7 fix: invalid Crockford Base32 char 'L' in log tag PL_AGENT_DONE
Fixes runtime crash on uwf thread step.
2026-05-23 06:13:29 +00:00
xiaoju ea6ceafe51 merge: resolve conflict in process-logger test (use null 3rd arg) 2026-05-23 06:10:53 +00:00
xiaoju d0dc7b5a19 feat: add process-level debug logger (Phase 1)
- New ProcessLogger in workflow-util: process-scoped JSONL logger
- Entry schema: {ts, pid, tag, msg, thread, workflow}
- Storage: ~/.uncaged/workflow/logs/YYYY-MM-DD.jsonl
- Auto logs process init info (argv, node version, context)
- cli-workflow thread commands fully instrumented:
  - thread start/step, moderator evaluate, agent spawn/done
  - thread archived, error paths

Refs #411, #412, #410
2026-05-23 06:10:05 +00:00