feat: moderator recognizes $SUSPEND as pseudo-role target

- Add GraphPseudoRole type ($END | $SUSPEND) to workflow-protocol
- Add 'suspended' to ThreadStatus
- evaluate() returns EvaluateSuspendResult for $SUSPEND targets
- Thread show/list derive suspended status from moderator evaluation
- validate-semantic treats $SUSPEND like $END (valid target, no outgoing edges)
- Tests: routing to $SUSPEND, mustache rendering, thread status display

Closes #588
This commit is contained in:
2026-06-02 04:39:29 +00:00
parent a335471cc7
commit b0ef9c55a9
12 changed files with 316 additions and 32 deletions
+1
View File
@@ -7,6 +7,7 @@ export type {
AgentAlias,
AgentConfig,
CasRef,
GraphPseudoRole,
ModelAlias,
ModelConfig,
ModeratorContext,
+1 -1
View File
@@ -18,7 +18,7 @@ const TARGET: JSONSchema = {
type: "object",
required: ["role", "prompt"],
properties: {
role: { type: "string" },
role: { type: "string", description: "Role name or pseudo-role ($END, $SUSPEND)" },
prompt: { type: "string" },
location: {
anyOf: [{ type: "string" }, { type: "null" }],
+8 -4
View File
@@ -35,8 +35,12 @@ export type RoleDefinition = {
frontmatter: CasRef;
};
/** Pseudo-role targets in workflow graph edges (not real roles). */
export type GraphPseudoRole = "$END" | "$SUSPEND";
export type Target = {
role: string;
/** Next role name, or a graph pseudo-role such as `$END` or `$SUSPEND`. */
role: string | GraphPseudoRole;
prompt: string;
/** Optional working directory override via mustache template. */
location: string | null;
@@ -79,7 +83,7 @@ export type ModeratorContext = {
// ── 4.5 CLI 输出 ────────────────────────────────────────────────────
/** Thread status — unified status representation */
export type ThreadStatus = "idle" | "running" | "completed" | "cancelled";
export type ThreadStatus = "idle" | "running" | "suspended" | "completed" | "cancelled";
/** uwf thread start */
export type StartOutput = {
@@ -90,7 +94,7 @@ export type StartOutput = {
/**
* Output from thread show and thread exec commands.
*
* @property status - Current thread status (idle/running/completed/cancelled)
* @property status - Current thread status (idle/running/suspended/completed/cancelled)
* @property done - @deprecated Use status field instead. True if thread is completed or cancelled.
* @property background - @deprecated Use status field instead. Always null in current implementation.
*/
@@ -99,7 +103,7 @@ export type StepOutput = {
thread: ThreadId;
head: CasRef;
status: ThreadStatus;
/** The current or next role. Null when completed, cancelled, or next is $END. */
/** The current or next role. Null when completed, cancelled, suspended, or next is $END. */
currentRole: string | null;
done: boolean;
background: boolean | null;