Commit Graph

319 Commits

Author SHA1 Message Date
xiaoju 1e9900bed3 feat(#194): Phase 2 — Engine layer Merkle call stack wiring
- Protocol: AgentFnResult = string | { output, childThread }, RoleOutput.childThread,
  ThreadContext.bundleHash for parent state lookup
- Runtime: create-workflow normalizes AgentFnResult, propagates childThread in RoleOutput
- Engine: ExecuteThreadOptions.parentStateHash, appendStateForStep writes childThread,
  putStartNode uses parentStateHash
- workflowAsAgent: reads parent head state from threads.json, passes parentStateHash
  to child, returns { output, childThread: rootHash }
- Integration test: 4 cases verifying bidirectional Merkle links (306 lines)

Phase 2 of #194 (Merkle Call Stack). Closes #196.

小橘 <xiaoju@shazhou.work>
2026-05-12 02:10:06 +00:00
xiaomo aebff8b906 Merge pull request 'refactor: replace Moderator function with ModeratorTable in WorkflowDefinition' (#201) from refactor/200-moderator-table into main 2026-05-12 02:06:03 +00:00
xingyue db45089922 refactor: replace Moderator function with ModeratorTable in WorkflowDefinition (#200)
- WorkflowDefinition.moderator → WorkflowDefinition.table (ModeratorTable)
- Moderator type + tableToModerator no longer exported from protocol/runtime
- tableToModerator internalized in workflow-execute engine layer
- WorkflowDescriptor gains graph: WorkflowGraph (auto-extracted from table)
- buildDescriptor extracts serializable graph edges from ModeratorTable
- validateWorkflowDescriptor validates graph structure
- All templates (develop, solve-issue) export table directly
- CLI init scaffold updated to use ModeratorTable
- 99 tests pass, 0 failures
2026-05-12 10:01:30 +08:00
xiaomo 9c1b018ffa Merge pull request 'feat(#194): Phase 1 — Merkle Call Stack protocol + CAS layer' (#199) from feat/194-merkle-call-stack-phase1 into main 2026-05-12 01:50:05 +00:00
xiaoju a98431a12a feat(#194): Phase 1 — parentState / childThread in CAS nodes
- Protocol: StartNodePayload.parentState, StateNodePayload.childThread
- CAS: putStartNode refs include parentState, collectRefs includes childThread
- Parsing: legacy nodes without new fields default to null
- Engine + fork: all callers pass parentState: null / childThread: null
- Tests: 8 new cases for refs, parsing, collect-refs (+208 lines)

Phase 1 of #194 (Merkle Call Stack). Closes #195.

小橘 <xiaoju@shazhou.work>
2026-05-12 01:42:10 +00:00
xingyue 0fe17b0fb2 docs: workflow graph visualization design plan (#198) 2026-05-12 09:38:58 +08:00
xiaoju e37dbc3f35 wip: Phase 1 protocol + CAS types for Merkle call stack
小橘 <xiaoju@shazhou.work>
2026-05-12 01:35:45 +00:00
xiaoju 82d9abf260 rfc: Merkle Call Stack — cross-thread DAG linking
Design doc for parent-child workflow Merkle linking:
- StartNodePayload.parentState: child → parent head state at spawn time
- StateNodePayload.childThread: parent → child final state hash
- Both also in refs[] for GC reachability
- 4-phase implementation plan

小橘 <xiaoju@shazhou.work>
2026-05-12 01:29:38 +00:00
xiaoju 50aec2d0cf fix: use unique log tags per call site in extract-workspace
W8KN3QYT — extraction failed
H4PM7RXV — non-absolute path
V3KM8QWP — success

小橘 <xiaoju@shazhou.work>
2026-05-12 00:58:37 +00:00
xiaomo e979a55f8a Merge pull request 'feat: cursor agent auto-extracts workspace from context' (#193) from feat/cursor-agent-workspace-extract into main 2026-05-12 00:57:33 +00:00
xiaoju 30f1582046 fix: address review feedback on cursor agent PR
1. Replace manual OpenAI response parsing with createThreadReactor —
   workspace extraction now uses the same ReAct loop as extract/summarizer,
   with a zod schema and structured tool call
2. Remove non-null assertion on llmProvider, replaced with explicit guard
3. Add structured logging (LogFn) to extraction — failures, non-absolute
   paths, and successful extractions all logged with tag V3KM8QWP
4. export const run = wf is correct: createWorkflow returns WorkflowFn
   directly, old bundle-entry had stale .run access + unused 3rd arg

小橘 <xiaoju@shazhou.work>
2026-05-11 14:05:01 +00:00
xiaoju cf0540d7fa fix: stabilize kill-thread test by polling instead of fixed delay
Replace 50ms setTimeout with waitUntilPredicate polling for first role
completion before issuing kill. Same pattern used by pause/resume test.

小橘 <xiaoju@shazhou.work>
2026-05-11 13:56:14 +00:00
xiaoju c05fac746c feat: cursor agent auto-extracts workspace from context via LLM
- workflow-agent-cursor: workspace config now optional (string | null)
- When null, uses LLM call to extract workspace path from AgentContext
  (previous steps' meta, start prompt) before spawning cursor-agent CLI
- Requires llmProvider when workspace is null
- develop bundle-entry: switched from hermes to cursor agent for all roles
- solve-issue bundle-entry: created, developer role uses workflowAsAgent('develop'),
  preparer/submitter remain hermes

小橘 <xiaoju@shazhou.work>
2026-05-11 13:51:41 +00:00
xiaoju 34efd25e91 chore: split release into publish.sh + deploy.sh
- publish.sh: version bump → workspace:* swap → npm publish → restore → commit
- deploy.sh: build + deploy dashboard/gateway to Cloudflare (supports single target)

小橘 <xiaoju@shazhou.work>
2026-05-11 12:22:06 +00:00
xiaoju cc0bc6c8aa chore: add release.sh script
Automates: version bump → workspace:* replace → npm publish (topo order)
→ restore workspace:* → dashboard build+deploy → git commit+push.

Env: GITEA_TOKEN, CLOUDFLARE_API_TOKEN (from cfg).

小橘 <xiaoju@shazhou.work>
2026-05-11 12:21:07 +00:00
xiaoju 626cb5d98e Merge pull request 'fix: sort thread list newest-first and differentiate status colors' (#192) from fix/191-dashboard-thread-sort into main 2026-05-11 12:16:19 +00:00
xiaoju f87cb38a67 fix: review — stable sort fallback, cleaner status colors
- Sort: threads without startedAt pushed to bottom (not random)
- Colors: completed=success(green), running/active=accent(blue), failed=error(red)
- Remove opacity hack, simplify ternary

小橘 <xiaoju@shazhou.work>
2026-05-11 12:14:51 +00:00
xiaoju 0970139418 fix: sort thread list newest-first and differentiate status colors
- Sort threads by startedAt descending (newest first)
- completed: green (dimmed) — distinct from running (green, full opacity)
- active: accent color (blue) — was same muted gray as completed
- failed: red — unchanged
- running: green — unchanged

Fixes #191
2026-05-11 12:09:48 +00:00
xiaoju 376dd87b6b chore: bump to v0.3.1, fix workspace:* in published packages
v0.3.0 was published with workspace:* deps (npm doesn't resolve them).
Re-published as v0.3.1 with concrete version refs.
Local monorepo deps restored to workspace:*.

小橘 <xiaoju@shazhou.work>
2026-05-11 11:00:49 +00:00
xiaoju 4d8469a649 chore: bump all packages to v0.3.0
Published to Gitea npm registry (git.shazhou.work).

小橘 <xiaoju@shazhou.work>
2026-05-11 10:52:35 +00:00
xiaoju a929fa4ccb Merge pull request 'feat: generate LLM summary in __end__ node via ReAct loop' (#190) from feat/187-end-node-llm-summary into main 2026-05-11 10:31:24 +00:00
xiaoju ff3e19fd22 docs: add comments explaining summarizer constants
小橘 <xiaoju@shazhou.work>
2026-05-11 10:28:54 +00:00
xiaoju b509d1715e refactor: extract shared CAS reactor pattern into cas-reactor.ts
Deduplicate CAS_GET_TOOL_DEFINITION, isRecord, toolHandler, and
structuredToolFromSchema between summarizer.ts and extract-fn.ts.

Both now use createCasReactor(provider, cas, opts) and only provide
their own systemPrompt.

小橘 <xiaoju@shazhou.work>
2026-05-11 10:25:31 +00:00
xiaoju b93f6e736f feat: generate LLM summary in __end__ node via ReAct loop
Instead of hardcoding 'completed: moderator returned END', the engine now
calls a summarizer (ReAct loop with cas_get tool) to produce a meaningful
summary of the workflow outcome before writing the __end__ node.

- New summarizer.ts following supervisor.ts pattern
- Uses extract scene LLM provider (falls back to raw completion.summary on failure)
- Tracks step contentHashes for summarizer context
- Schema: z.object({ summary: z.string() })

Refs #187, #188

小橘 <xiaoju@shazhou.work>
2026-05-11 10:11:31 +00:00
xiaoju ec13c19505 Merge pull request 'refactor: replace maxRounds with supervisor check interval' (#186) from refactor/185-remove-max-rounds into main 2026-05-11 09:01:24 +00:00
xiaoju 203b86e827 refactor: remove dead hasRoundsRemaining condition, use FALLBACK
The condition always returned true, making the subsequent FALLBACK → END
unreachable. Simplified to FALLBACK → coder directly.

Refs #185
2026-05-11 08:59:14 +00:00
xiaoju 90de1c7025 test: fix develop moderator tests for supervisor-controlled termination
hasRoundsRemaining is now always true — supervisor controls when to
stop, not a round counter. Tests updated to expect coder retry
instead of END on exhaustion.

Refs #185
2026-05-11 08:55:49 +00:00
xiaoju 2b587612d5 refactor: replace maxRounds with supervisor check interval
Removes maxRounds as a hard stop limit from the entire stack. The supervisor
(already configured via workflow.yaml supervisorInterval) is now the sole
termination authority.

Changes across 27 files in 11 packages:
- workflow-protocol: StartStep.meta is now empty, StartNodePayload drops maxRounds
- workflow-cas: isStartPayload no longer checks maxRounds
- workflow-execute: engine, worker, fork-thread all stripped of maxRounds plumbing
- cli-workflow: --max-rounds flag removed from CLI and HTTP API
- workflow-runtime: build-context and create-workflow no longer reference maxRounds
- workflow-dashboard: UI no longer sends maxRounds
- workflow-template-develop/solve-issue: moderator no longer checks rounds remaining
- All tests updated

Fixes #185
2026-05-11 08:51:35 +00:00
xingyue 2342a6e3bd fix: login.tsx use new gateway endpoint path 2026-05-11 16:46:38 +08:00
xingyue 0021596ff0 Merge pull request 'refactor: simplify ExtractFn to (schema, contentHash)' (#184) from refactor/180-simplify-extract-fn into main 2026-05-11 08:03:48 +00:00
xiaomo 56ec8cd401 Merge pull request 'refactor: reorganize gateway routes under /api/ prefix' (#183) from feat/177-gateway-route-reorg into main 2026-05-11 08:01:02 +00:00
xiaoju fe87efd79d fix: cursor agent workspace from config instead of type assertion
Address review feedback: remove unsafe `as unknown as` cast on
currentRole. CursorAgentConfig now takes workspace directly instead
of using ExtractFn to infer it from thread context.

Refs #180
2026-05-11 08:00:51 +00:00
xingyue b783027406 fix: remove stray lockfiles + refactor gateway auth with Hono group
- Remove root and workflow-gateway pnpm-lock.yaml (workspace mode)
- Replace startsWith auth skip with Hono route group
- Gateway management routes use GATEWAY_SECRET (per-route)
- /api/gateway/endpoints + /api/agents/* use dashboard auth
- No more global /api/* middleware with path-based exceptions
2026-05-11 15:59:42 +08:00
xiaoju 904ee1eb83 refactor: workflow-as-agent outputs readable summary instead of raw hash
Extract can now work with the readable content directly, without
needing a special extractPrompt for DAG traversal.

Closes #182
2026-05-11 07:55:49 +00:00
xiaoju 1742ced6df refactor: simplify ExtractFn to (schema, contentHash)
- Remove extractPrompt from RoleDefinition
- Remove ExtractContext type
- ExtractFn now takes (schema, contentHash) instead of (schema, prompt, ExtractContext)
- createExtract reads CAS content by hash, keeps ReAct loop with cas_get
- Coder schema uses .describe() for phase hash hint
- All role definitions, CLI templates, and skill output updated

Refs #180, closes #174, closes #181
2026-05-11 07:54:09 +00:00
xingyue 93145cf08c refactor: reorganize gateway routes under /api/ prefix (closes #178, closes #179)
- Gateway management: /api/gateway/register, /api/gateway/endpoints
- Agent proxy: /api/agents/:agent/*
- /healthz stays at root (CF/k8s convention)
- Skip dashboard auth for gateway register routes
- Update CLI serve tunnel registration paths
- Update dashboard API client paths

Ref: #177
2026-05-11 15:48:13 +08:00
xiaoju da6bcb10d6 feat(workflow): add declarative ModeratorTable type and migrate templates
Migrate workflow-template-develop and workflow-template-solve-issue
moderators to use the declarative ModeratorTable/tableToModerator
pattern. Update workflow-runtime re-exports and workflow-execute
engine to use renamed types.

Fixes #172
2026-05-11 06:25:39 +00:00
xiaoju 6fc97fc8c8 feat(workflow-protocol): add declarative moderator table types and tableToModerator
Add ModeratorCondition, FALLBACK, ModeratorTransition, ModeratorTable types
and tableToModerator converter function. Export from workflow-protocol and
re-export from workflow-runtime for backward compat.

Refs #172
2026-05-11 06:22:24 +00:00
xiaoju 93d9821f64 docs: update CLI skill with serve command, thread status, defaults, env vars
小橘 <xiaoju@shazhou.work>
2026-05-10 01:57:42 +00:00
xiaoju 29367cbe31 chore: remove stray bundle artifacts from repo
小橘 <xiaoju@shazhou.work>
2026-05-10 01:44:40 +00:00
xiaoju ec397aecd3 chore: remove stray bundle artifacts from repo
小橘 <xiaoju@shazhou.work>
2026-05-10 01:42:18 +00:00
xiaoju 2e9d939f8e fix: thread detail API returns correct status instead of source
小橘 <xiaoju@shazhou.work>
2026-05-10 01:39:09 +00:00
xiaoju 064a24f093 fix: no-ctl threads should be failed, not active
小橘 <xiaoju@shazhou.work>
2026-05-10 01:36:14 +00:00
xiaoju fede623a82 dashboard: remove 'All agents' dropdown option, auto-select first agent
小橘 <xiaoju@shazhou.work>
2026-05-09 13:26:11 +00:00
xiaoju 2a52b930b9 chore: raise default maxRounds from 5 to 10 (CLI, matches API default)
小橘 <xiaoju@shazhou.work>
2026-05-09 13:17:57 +00:00
xiaoju bf2f790e6e fix: detect crashed threads even when .running marker is already gone
Check worker PID liveness as final fallback — if worker is dead
and thread has no __end__ node, it crashed.

小橘 <xiaoju@shazhou.work>
2026-05-09 12:52:39 +00:00
xiaoju 08a79b77db fix: SSE sends 'done' event for non-running threads, frontend stops reconnecting
- routes-live: emit 'done' event before closing SSE for non-running threads
- use-sse: handle 'done' event — set completed, disconnect, stop reconnect
- Prevents 'Live' badge flash on failed/completed threads

小橘 <xiaoju@shazhou.work>
2026-05-09 12:49:20 +00:00
xiaoju 22a6200b69 fix: close SSE stream for non-running threads, fix Live badge
- routes-live: check .running marker before keeping SSE open;
  if thread is not running, emit existing records and close
- thread-detail: only show Live badge when connected AND not completed

小橘 <xiaoju@shazhou.work>
2026-05-09 12:45:58 +00:00
xiaoju 7e7f6aa6d6 fix: detect crashed threads by checking worker PID liveness
When .running marker exists but no __end__ in CAS chain,
check if the worker process is actually alive. Dead PID
means the worker crashed without cleanup → status 'failed'.

Fixes #170

小橘 <xiaoju@shazhou.work>
2026-05-09 12:38:18 +00:00
xiaoju d6fe3f844c fix: detect crashed threads as failed instead of stuck running
- resolveThreadListStatus() checks CAS chain for __end__ node
- Stale .running markers no longer cause false 'running' status
- Distinguish 'failed' (returnCode != 0) from 'completed'
- Worker signal handlers (SIGINT/SIGTERM) clean up .running files
- listRunningThreads filters out terminated threads with stale markers

Fixes #170

小橘 <xiaoju@shazhou.work>
2026-05-09 12:28:33 +00:00