refactor: align package folder names with npm package names
CI / check (pull_request) Failing after 8m30s
CI / check (pull_request) Failing after 8m30s
Rename packages/ subdirectories to match their @united-workforce/* scope: cli-workflow → cli workflow-agent-builtin → agent-builtin workflow-agent-claude-code → agent-claude-code workflow-agent-hermes → agent-hermes workflow-dashboard → dashboard workflow-protocol → protocol workflow-util-agent → util-agent workflow-util → util Updated all tsconfig references, scripts, and active docs. Historical docs (docs/plans/, docs/superpowers/) left as-is. Closes #21
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# @united-workforce/protocol
|
||||
|
||||
Shared TypeScript types and JSON Schema constants for the workflow engine.
|
||||
|
||||
## Overview
|
||||
|
||||
This is the contract layer (Layer 0). It defines `WorkflowPayload`, thread node payloads, moderator context, CLI output shapes, and configuration types used across every other package. It has no runtime logic beyond exporting schema objects from `@ocas/core`.
|
||||
|
||||
**Dependencies:** `@ocas/core`, `@ocas/fs`
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @united-workforce/protocol
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
All exports come from `src/index.ts`.
|
||||
|
||||
### JSON Schema constants
|
||||
|
||||
```typescript
|
||||
START_NODE_SCHEMA: JSONSchema
|
||||
STEP_NODE_SCHEMA: JSONSchema
|
||||
WORKFLOW_SCHEMA: JSONSchema
|
||||
```
|
||||
|
||||
### Core identifiers
|
||||
|
||||
```typescript
|
||||
type CasRef = string // XXH64 hash, 13-char Crockford Base32
|
||||
type ThreadId = string // ULID, 26-char Crockford Base32
|
||||
type WorkflowName = string
|
||||
type RoleName = string
|
||||
```
|
||||
|
||||
### Workflow definition
|
||||
|
||||
```typescript
|
||||
type RoleDefinition = {
|
||||
description: string;
|
||||
goal: string;
|
||||
capabilities: string[];
|
||||
procedure: string;
|
||||
output: string;
|
||||
frontmatter: CasRef;
|
||||
};
|
||||
|
||||
type Target = {
|
||||
role: string;
|
||||
prompt: string;
|
||||
};
|
||||
|
||||
type WorkflowPayload = {
|
||||
name: string;
|
||||
description: string;
|
||||
roles: Record<string, RoleDefinition>;
|
||||
graph: Record<string, Record<string, Target>>;
|
||||
};
|
||||
```
|
||||
|
||||
### Thread nodes
|
||||
|
||||
```typescript
|
||||
type StepRecord = {
|
||||
role: string;
|
||||
output: CasRef;
|
||||
detail: CasRef;
|
||||
agent: string;
|
||||
edgePrompt: string;
|
||||
};
|
||||
|
||||
type StartNodePayload = {
|
||||
workflow: CasRef;
|
||||
prompt: string;
|
||||
};
|
||||
|
||||
type StepNodePayload = StepRecord & {
|
||||
start: CasRef;
|
||||
prev: CasRef | null;
|
||||
};
|
||||
```
|
||||
|
||||
### Moderator context
|
||||
|
||||
```typescript
|
||||
type StepContext = Omit<StepRecord, "output"> & { output: unknown; content: string | null };
|
||||
|
||||
type ModeratorContext = {
|
||||
start: StartNodePayload;
|
||||
steps: StepContext[];
|
||||
};
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
type ProviderAlias = string;
|
||||
type ModelAlias = string;
|
||||
type AgentAlias = string;
|
||||
|
||||
type ProviderConfig = { baseUrl: string; apiKey: string };
|
||||
type ModelConfig = {
|
||||
provider: ProviderAlias;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type AgentConfig = {
|
||||
command: string;
|
||||
args: string[];
|
||||
};
|
||||
|
||||
type WorkflowConfig = {
|
||||
providers: Record<ProviderAlias, ProviderConfig>;
|
||||
models: Record<ModelAlias, ModelConfig>;
|
||||
agents: Record<AgentAlias, AgentConfig>;
|
||||
defaultAgent: AgentAlias;
|
||||
agentOverrides: Record<WorkflowName, Record<RoleName, AgentAlias>> | null;
|
||||
defaultModel: ModelAlias;
|
||||
modelOverrides: Record<Scenario, ModelAlias> | null;
|
||||
};
|
||||
```
|
||||
|
||||
### CLI output types
|
||||
|
||||
```typescript
|
||||
type StartOutput = { workflow: CasRef; thread: ThreadId };
|
||||
|
||||
type StepOutput = {
|
||||
workflow: CasRef;
|
||||
thread: ThreadId;
|
||||
head: CasRef;
|
||||
done: boolean;
|
||||
};
|
||||
|
||||
type StepEntry = {
|
||||
hash: CasRef;
|
||||
role: string;
|
||||
output: unknown;
|
||||
detail: CasRef;
|
||||
agent: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
type StartEntry = {
|
||||
hash: CasRef;
|
||||
workflow: CasRef;
|
||||
prompt: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
type ThreadStepsOutput = {
|
||||
thread: ThreadId;
|
||||
workflow: CasRef;
|
||||
steps: [StartEntry, ...StepEntry[]];
|
||||
};
|
||||
|
||||
type ThreadForkOutput = {
|
||||
thread: ThreadId;
|
||||
forkedFrom: { step: CasRef };
|
||||
};
|
||||
|
||||
type ThreadListItem = {
|
||||
thread: ThreadId;
|
||||
workflow: CasRef;
|
||||
head: CasRef;
|
||||
};
|
||||
|
||||
type ThreadsIndex = Record<ThreadId, CasRef>;
|
||||
|
||||
type Scenario = string;
|
||||
```
|
||||
|
||||
## Internal Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.ts Public re-exports
|
||||
├── types.ts All type definitions
|
||||
└── schemas.ts START_NODE_SCHEMA, STEP_NODE_SCHEMA, WORKFLOW_SCHEMA
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
This package defines `WorkflowConfig` types only. Runtime config loading lives in `@united-workforce/util-agent` (`loadWorkflowConfig`).
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@united-workforce/protocol",
|
||||
"version": "0.5.0",
|
||||
"files": [
|
||||
"src",
|
||||
"dist",
|
||||
"package.json"
|
||||
],
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"bun": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "bun test src/__tests__/",
|
||||
"test:ci": "bun test src/__tests__/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ocas/core": "^0.1.1",
|
||||
"@ocas/fs": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/protocol"
|
||||
},
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import {
|
||||
createThreadIndexEntry,
|
||||
markThreadSuspended,
|
||||
normalizeThreadIndexEntry,
|
||||
parseThreadsIndex,
|
||||
serializeThreadIndexEntry,
|
||||
serializeThreadsIndex,
|
||||
updateThreadHead,
|
||||
} from "../thread-index.js";
|
||||
|
||||
describe("thread-index", () => {
|
||||
test("parse legacy string head hash", () => {
|
||||
const entry = normalizeThreadIndexEntry("0123456789ABC");
|
||||
expect(entry).toEqual({
|
||||
head: "0123456789ABC",
|
||||
suspendedRole: null,
|
||||
suspendMessage: null,
|
||||
});
|
||||
});
|
||||
|
||||
test("parse suspended object entry", () => {
|
||||
const entry = normalizeThreadIndexEntry({
|
||||
head: "0123456789ABC",
|
||||
suspendedRole: "worker",
|
||||
suspendMessage: "Please clarify: Which API?",
|
||||
});
|
||||
expect(entry).toEqual({
|
||||
head: "0123456789ABC",
|
||||
suspendedRole: "worker",
|
||||
suspendMessage: "Please clarify: Which API?",
|
||||
});
|
||||
});
|
||||
|
||||
test("serialize non-suspended entry as compact string", () => {
|
||||
const entry = createThreadIndexEntry("0123456789ABC");
|
||||
expect(serializeThreadIndexEntry(entry)).toBe("0123456789ABC");
|
||||
});
|
||||
|
||||
test("serialize suspended entry as object", () => {
|
||||
const entry = markThreadSuspended(
|
||||
createThreadIndexEntry("0123456789ABC"),
|
||||
"worker",
|
||||
"Please clarify: Which API?",
|
||||
);
|
||||
expect(serializeThreadIndexEntry(entry)).toEqual({
|
||||
head: "0123456789ABC",
|
||||
suspendedRole: "worker",
|
||||
suspendMessage: "Please clarify: Which API?",
|
||||
});
|
||||
});
|
||||
|
||||
test("updateThreadHead clears suspend metadata", () => {
|
||||
const suspended = markThreadSuspended(
|
||||
createThreadIndexEntry("OLDHEAD0123456"),
|
||||
"worker",
|
||||
"Waiting",
|
||||
);
|
||||
const resumed = updateThreadHead(suspended, "NEWHEAD01234567");
|
||||
expect(resumed).toEqual({
|
||||
head: "NEWHEAD01234567",
|
||||
suspendedRole: null,
|
||||
suspendMessage: null,
|
||||
});
|
||||
});
|
||||
|
||||
test("parseThreadsIndex round-trip", () => {
|
||||
const raw = {
|
||||
"01THREAD0000000000000001": "HEAD00000000001",
|
||||
"01THREAD0000000000000002": {
|
||||
head: "HEAD00000000002",
|
||||
suspendedRole: "reviewer",
|
||||
suspendMessage: "Need input",
|
||||
},
|
||||
};
|
||||
const parsed = parseThreadsIndex(raw);
|
||||
expect(serializeThreadsIndex(parsed)).toEqual(raw);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { StartNodePayload, StepRecord, Target } from "../types.js";
|
||||
|
||||
describe("Protocol types for thread/edge location", () => {
|
||||
describe("StartNodePayload", () => {
|
||||
test("has required cwd field", () => {
|
||||
const payload: StartNodePayload = {
|
||||
workflow: "0123456789ABC",
|
||||
prompt: "Test prompt",
|
||||
cwd: "/home/user/project",
|
||||
};
|
||||
|
||||
expect(payload.cwd).toBe("/home/user/project");
|
||||
expect(typeof payload.cwd).toBe("string");
|
||||
});
|
||||
});
|
||||
|
||||
describe("StepRecord", () => {
|
||||
test("has required cwd field", () => {
|
||||
const record: StepRecord = {
|
||||
role: "planner",
|
||||
output: "0123456789ABC",
|
||||
detail: "DEF0123456789",
|
||||
agent: "uwf-hermes",
|
||||
edgePrompt: "Plan the implementation",
|
||||
startedAtMs: Date.now(),
|
||||
completedAtMs: Date.now() + 1000,
|
||||
assembledPrompt: null,
|
||||
cwd: "/home/user/project",
|
||||
};
|
||||
|
||||
expect(record.cwd).toBe("/home/user/project");
|
||||
expect(typeof record.cwd).toBe("string");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Target", () => {
|
||||
test("has location field that accepts string", () => {
|
||||
const target: Target = {
|
||||
role: "coder",
|
||||
prompt: "Implement the code",
|
||||
location: "/custom/path",
|
||||
};
|
||||
|
||||
expect(target.location).toBe("/custom/path");
|
||||
expect(typeof target.location).toBe("string");
|
||||
});
|
||||
|
||||
test("has location field that accepts null", () => {
|
||||
const target: Target = {
|
||||
role: "coder",
|
||||
prompt: "Implement the code",
|
||||
location: null,
|
||||
};
|
||||
|
||||
expect(target.location).toBe(null);
|
||||
});
|
||||
|
||||
test("location supports mustache template syntax", () => {
|
||||
const target: Target = {
|
||||
role: "coder",
|
||||
prompt: "Implement the code",
|
||||
location: "{{{repoPath}}}",
|
||||
};
|
||||
|
||||
expect(target.location).toBe("{{{repoPath}}}");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
export {
|
||||
START_NODE_SCHEMA,
|
||||
STEP_NODE_SCHEMA,
|
||||
WORKFLOW_SCHEMA,
|
||||
} from "./schemas.js";
|
||||
export {
|
||||
createThreadIndexEntry,
|
||||
markThreadSuspended,
|
||||
normalizeThreadIndexEntry,
|
||||
parseThreadsIndex,
|
||||
serializeThreadIndexEntry,
|
||||
serializeThreadsIndex,
|
||||
updateThreadHead,
|
||||
} from "./thread-index.js";
|
||||
export type {
|
||||
AgentAlias,
|
||||
AgentConfig,
|
||||
CasRef,
|
||||
GraphPseudoRole,
|
||||
ModelAlias,
|
||||
ModelConfig,
|
||||
ModeratorContext,
|
||||
ProviderAlias,
|
||||
ProviderConfig,
|
||||
RoleDefinition,
|
||||
RoleName,
|
||||
RunningThreadItem,
|
||||
RunningThreadsOutput,
|
||||
Scenario,
|
||||
StartEntry,
|
||||
StartNodePayload,
|
||||
StartOutput,
|
||||
StepContext,
|
||||
StepEntry,
|
||||
StepNodePayload,
|
||||
StepOutput,
|
||||
StepRecord,
|
||||
Target,
|
||||
ThreadForkOutput,
|
||||
ThreadId,
|
||||
ThreadIndexEntry,
|
||||
ThreadListItem,
|
||||
ThreadStatus,
|
||||
ThreadStepsOutput,
|
||||
ThreadsIndex,
|
||||
WorkflowConfig,
|
||||
WorkflowName,
|
||||
WorkflowPayload,
|
||||
} from "./types.js";
|
||||
@@ -0,0 +1,96 @@
|
||||
import type { JSONSchema } from "@ocas/core";
|
||||
|
||||
const ROLE_DEFINITION: JSONSchema = {
|
||||
type: "object",
|
||||
required: ["description", "goal", "capabilities", "procedure", "output", "frontmatter"],
|
||||
properties: {
|
||||
description: { type: "string" },
|
||||
goal: { type: "string" },
|
||||
capabilities: { type: "array", items: { type: "string" } },
|
||||
procedure: { type: "string" },
|
||||
output: { type: "string" },
|
||||
frontmatter: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
const TARGET: JSONSchema = {
|
||||
type: "object",
|
||||
required: ["role", "prompt"],
|
||||
properties: {
|
||||
role: { type: "string", description: "Role name or pseudo-role ($END, $SUSPEND)" },
|
||||
prompt: { type: "string" },
|
||||
location: {
|
||||
anyOf: [{ type: "string" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const WORKFLOW_SCHEMA: JSONSchema = {
|
||||
title: "Workflow",
|
||||
type: "object",
|
||||
required: ["name", "description", "roles", "graph"],
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
description: { type: "string" },
|
||||
roles: {
|
||||
type: "object",
|
||||
additionalProperties: ROLE_DEFINITION,
|
||||
},
|
||||
graph: {
|
||||
type: "object",
|
||||
additionalProperties: {
|
||||
type: "object",
|
||||
additionalProperties: TARGET,
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const START_NODE_SCHEMA: JSONSchema = {
|
||||
title: "StartNode",
|
||||
type: "object",
|
||||
required: ["workflow", "prompt", "cwd"],
|
||||
properties: {
|
||||
workflow: { type: "string", format: "ocas_ref" },
|
||||
prompt: { type: "string" },
|
||||
cwd: { type: "string" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const STEP_NODE_SCHEMA: JSONSchema = {
|
||||
title: "StepNode",
|
||||
type: "object",
|
||||
required: [
|
||||
"start",
|
||||
"prev",
|
||||
"role",
|
||||
"output",
|
||||
"detail",
|
||||
"agent",
|
||||
"startedAtMs",
|
||||
"completedAtMs",
|
||||
"cwd",
|
||||
],
|
||||
properties: {
|
||||
start: { type: "string", format: "ocas_ref" },
|
||||
prev: {
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
role: { type: "string" },
|
||||
output: { type: "string", format: "ocas_ref" },
|
||||
detail: { type: "string", format: "ocas_ref" },
|
||||
agent: { type: "string" },
|
||||
edgePrompt: { type: "string" },
|
||||
startedAtMs: { type: "integer" },
|
||||
completedAtMs: { type: "integer" },
|
||||
cwd: { type: "string" },
|
||||
assembledPrompt: {
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { CasRef, ThreadId, ThreadIndexEntry, ThreadsIndex } from "./types.js";
|
||||
|
||||
/** Normalize a legacy head hash or entry object into {@link ThreadIndexEntry}. */
|
||||
export function normalizeThreadIndexEntry(raw: unknown): ThreadIndexEntry | null {
|
||||
if (typeof raw === "string") {
|
||||
return createThreadIndexEntry(raw as CasRef);
|
||||
}
|
||||
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
||||
return null;
|
||||
}
|
||||
const rec = raw as Record<string, unknown>;
|
||||
const head = rec.head;
|
||||
if (typeof head !== "string") {
|
||||
return null;
|
||||
}
|
||||
const suspendedRole = rec.suspendedRole;
|
||||
const suspendMessage = rec.suspendMessage;
|
||||
return {
|
||||
head: head as CasRef,
|
||||
suspendedRole: typeof suspendedRole === "string" ? suspendedRole : null,
|
||||
suspendMessage: typeof suspendMessage === "string" ? suspendMessage : null,
|
||||
};
|
||||
}
|
||||
|
||||
export function createThreadIndexEntry(head: CasRef): ThreadIndexEntry {
|
||||
return {
|
||||
head,
|
||||
suspendedRole: null,
|
||||
suspendMessage: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateThreadHead(_entry: ThreadIndexEntry, head: CasRef): ThreadIndexEntry {
|
||||
return {
|
||||
head,
|
||||
suspendedRole: null,
|
||||
suspendMessage: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function markThreadSuspended(
|
||||
entry: ThreadIndexEntry,
|
||||
suspendedRole: string,
|
||||
suspendMessage: string,
|
||||
): ThreadIndexEntry {
|
||||
return {
|
||||
head: entry.head,
|
||||
suspendedRole,
|
||||
suspendMessage,
|
||||
};
|
||||
}
|
||||
|
||||
/** Serialize for threads.yaml — compact string when not suspended. */
|
||||
export function serializeThreadIndexEntry(
|
||||
entry: ThreadIndexEntry,
|
||||
): string | Record<string, string> {
|
||||
if (entry.suspendedRole === null || entry.suspendMessage === null) {
|
||||
return entry.head;
|
||||
}
|
||||
return {
|
||||
head: entry.head,
|
||||
suspendedRole: entry.suspendedRole,
|
||||
suspendMessage: entry.suspendMessage,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseThreadsIndex(raw: unknown): ThreadsIndex {
|
||||
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
||||
return {};
|
||||
}
|
||||
const index: ThreadsIndex = {};
|
||||
for (const [threadId, value] of Object.entries(raw as Record<string, unknown>)) {
|
||||
const entry = normalizeThreadIndexEntry(value);
|
||||
if (entry !== null) {
|
||||
index[threadId as ThreadId] = entry;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
export function serializeThreadsIndex(
|
||||
index: ThreadsIndex,
|
||||
): Record<string, string | Record<string, string>> {
|
||||
const out: Record<string, string | Record<string, string>> = {};
|
||||
for (const [threadId, entry] of Object.entries(index)) {
|
||||
out[threadId] = serializeThreadIndexEntry(entry);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// ── 4.1 公共类型 ────────────────────────────────────────────────────
|
||||
|
||||
/** CAS hash — XXH64, 13-char Crockford Base32 */
|
||||
export type CasRef = string;
|
||||
|
||||
/** Thread ID — ULID, 26-char Crockford Base32 */
|
||||
export type ThreadId = string;
|
||||
|
||||
/** 一个 step 的核心数据,被 StepNode payload 和 JSONata 上下文共享 */
|
||||
export type StepRecord = {
|
||||
role: string;
|
||||
output: CasRef;
|
||||
detail: CasRef;
|
||||
agent: string;
|
||||
/** Moderator edge prompt that led to this step. Missing in legacy nodes → "". */
|
||||
edgePrompt: string;
|
||||
/** Date.now() before agent spawn */
|
||||
startedAtMs: number;
|
||||
/** Date.now() after agent returns */
|
||||
completedAtMs: number;
|
||||
/** Working directory where the agent executed. Missing in legacy nodes → "". */
|
||||
cwd: string;
|
||||
/** CAS ref to the fully assembled prompt sent to the agent. null for legacy steps. */
|
||||
assembledPrompt: CasRef | null;
|
||||
};
|
||||
|
||||
// ── 4.2 Workflow 定义 ───────────────────────────────────────────────
|
||||
|
||||
export type RoleDefinition = {
|
||||
description: string;
|
||||
goal: string;
|
||||
capabilities: string[];
|
||||
procedure: string;
|
||||
output: string;
|
||||
frontmatter: CasRef;
|
||||
};
|
||||
|
||||
/** Pseudo-role targets in workflow graph edges (not real roles). */
|
||||
export type GraphPseudoRole = "$END" | "$SUSPEND";
|
||||
|
||||
export type Target = {
|
||||
/** 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;
|
||||
};
|
||||
|
||||
export type WorkflowPayload = {
|
||||
name: string;
|
||||
description: string;
|
||||
roles: Record<string, RoleDefinition>;
|
||||
graph: Record<string, Record<string, Target>>;
|
||||
};
|
||||
|
||||
// ── 4.3 Thread 节点 ─────────────────────────────────────────────────
|
||||
|
||||
export type StartNodePayload = {
|
||||
workflow: CasRef;
|
||||
prompt: string;
|
||||
/** Working directory where the thread was created. */
|
||||
cwd: string;
|
||||
};
|
||||
|
||||
export type StepNodePayload = StepRecord & {
|
||||
start: CasRef;
|
||||
prev: CasRef | null;
|
||||
};
|
||||
|
||||
// ── 4.4 JSONata 求值上下文 ──────────────────────────────────────────
|
||||
|
||||
/** JSONata 上下文中的 step — output 被展开 */
|
||||
export type StepContext = Omit<StepRecord, "output"> & {
|
||||
output: unknown;
|
||||
content: string | null;
|
||||
};
|
||||
|
||||
export type ModeratorContext = {
|
||||
start: StartNodePayload;
|
||||
steps: StepContext[];
|
||||
};
|
||||
|
||||
// ── 4.5 CLI 输出 ────────────────────────────────────────────────────
|
||||
|
||||
/** Thread status — unified status representation */
|
||||
export type ThreadStatus = "idle" | "running" | "suspended" | "completed" | "cancelled";
|
||||
|
||||
/** uwf thread start */
|
||||
export type StartOutput = {
|
||||
workflow: CasRef;
|
||||
thread: ThreadId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Output from thread show and thread exec commands.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
export type StepOutput = {
|
||||
workflow: CasRef;
|
||||
thread: ThreadId;
|
||||
head: CasRef;
|
||||
status: ThreadStatus;
|
||||
/** The current or next role. Null when completed, cancelled, suspended, or next is $END. */
|
||||
currentRole: string | null;
|
||||
/** Role whose output triggered suspension. Null when thread is not suspended. */
|
||||
suspendedRole: string | null;
|
||||
/** Rendered suspend prompt for the user. Null when thread is not suspended. */
|
||||
suspendMessage: string | null;
|
||||
done: boolean;
|
||||
background: boolean | null;
|
||||
};
|
||||
|
||||
/** Active thread entry in ~/.uwf/threads.yaml */
|
||||
export type ThreadIndexEntry = {
|
||||
head: CasRef;
|
||||
suspendedRole: string | null;
|
||||
suspendMessage: string | null;
|
||||
};
|
||||
|
||||
/** uwf thread steps — single step entry */
|
||||
export type StepEntry = {
|
||||
hash: CasRef;
|
||||
role: string;
|
||||
output: unknown;
|
||||
detail: CasRef;
|
||||
agent: string;
|
||||
timestamp: number;
|
||||
durationMs: number;
|
||||
};
|
||||
|
||||
/** uwf thread steps — start entry */
|
||||
export type StartEntry = {
|
||||
hash: CasRef;
|
||||
workflow: CasRef;
|
||||
prompt: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
/** uwf thread steps output */
|
||||
export type ThreadStepsOutput = {
|
||||
thread: ThreadId;
|
||||
workflow: CasRef;
|
||||
steps: [StartEntry, ...StepEntry[]];
|
||||
};
|
||||
|
||||
/** uwf thread fork output */
|
||||
export type ThreadForkOutput = {
|
||||
thread: ThreadId;
|
||||
forkedFrom: {
|
||||
step: CasRef;
|
||||
};
|
||||
};
|
||||
|
||||
/** uwf thread list */
|
||||
export type ThreadListItem = {
|
||||
thread: ThreadId;
|
||||
workflow: CasRef;
|
||||
head: CasRef;
|
||||
};
|
||||
|
||||
/** uwf thread running — single running thread entry */
|
||||
export type RunningThreadItem = {
|
||||
thread: ThreadId;
|
||||
workflow: CasRef;
|
||||
pid: number;
|
||||
startedAt: number;
|
||||
};
|
||||
|
||||
/** uwf thread running output */
|
||||
export type RunningThreadsOutput = {
|
||||
threads: RunningThreadItem[];
|
||||
};
|
||||
|
||||
// ── 4.6 配置 ────────────────────────────────────────────────────────
|
||||
|
||||
/** Alias types for config references */
|
||||
export type AgentAlias = string;
|
||||
export type ModelAlias = string;
|
||||
export type ProviderAlias = string;
|
||||
export type WorkflowName = string;
|
||||
export type RoleName = string;
|
||||
export type Scenario = string;
|
||||
|
||||
export type ProviderConfig = {
|
||||
baseUrl: string;
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export type ModelConfig = {
|
||||
provider: ProviderAlias;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type AgentConfig = {
|
||||
command: string;
|
||||
args: string[];
|
||||
};
|
||||
|
||||
/** ~/.uwf/config.yaml */
|
||||
export type WorkflowConfig = {
|
||||
providers: Record<ProviderAlias, ProviderConfig>;
|
||||
models: Record<ModelAlias, ModelConfig>;
|
||||
agents: Record<AgentAlias, AgentConfig>;
|
||||
defaultAgent: AgentAlias;
|
||||
agentOverrides: Record<WorkflowName, Record<RoleName, AgentAlias>> | null;
|
||||
defaultModel: ModelAlias;
|
||||
modelOverrides: Record<Scenario, ModelAlias> | null;
|
||||
};
|
||||
|
||||
/** ~/.uwf/threads.yaml */
|
||||
export type ThreadsIndex = Record<ThreadId, ThreadIndexEntry>;
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user