refactor: rename workflow-agent-kit → workflow-util-agent, merge workflow-moderator into cli-workflow
CI / check (pull_request) Failing after 32s

- Rename packages/workflow-agent-kit → packages/workflow-util-agent
- Update all imports, tsconfig references, docs
- Delete dead file packages/workflow-util-agent/src/build-agent-prompt.ts
- Merge workflow-moderator (62 LOC) into cli-workflow/src/moderator/
- Move workflow-moderator to legacy-packages/
- Add mustache dependency to cli-workflow
- Update publish-all.mjs

Fixes #512
This commit is contained in:
2026-05-25 10:51:16 +00:00
parent 0779ab85ca
commit ca223a19c6
66 changed files with 267 additions and 147 deletions
+3 -4
View File
@@ -23,10 +23,9 @@ workflow/
packages/ packages/
workflow-protocol/ # @uncaged/workflow-protocol — shared types (WorkflowPayload, StepNodePayload, WorkflowConfig, etc.) workflow-protocol/ # @uncaged/workflow-protocol — shared types (WorkflowPayload, StepNodePayload, WorkflowConfig, etc.)
workflow-util/ # @uncaged/workflow-util — Crockford Base32, ULID, logger, frontmatter parsing/validation workflow-util/ # @uncaged/workflow-util — Crockford Base32, ULID, logger, frontmatter parsing/validation
workflow-moderator/ # @uncaged/workflow-moderator — Status-based graph evaluator workflow-util-agent/ # @uncaged/workflow-util-agent — createAgent factory, context builder, extract pipeline
workflow-agent-kit/ # @uncaged/workflow-agent-kit — createAgent factory, context builder, extract pipeline
workflow-agent-hermes/ # @uncaged/workflow-agent-hermes — uwf-hermes CLI binary (spawns hermes chat) workflow-agent-hermes/ # @uncaged/workflow-agent-hermes — uwf-hermes CLI binary (spawns hermes chat)
cli-workflow/ # @uncaged/cli-workflow — uwf CLI binary cli-workflow/ # @uncaged/cli-workflow — uwf CLI binary (includes status-based moderator in src/moderator/)
legacy-packages/ # Archived packages (preserved for reference, not active) legacy-packages/ # Archived packages (preserved for reference, not active)
examples/ # Workflow YAML examples (solve-issue.yaml) examples/ # Workflow YAML examples (solve-issue.yaml)
docs/ # Architecture docs docs/ # Architecture docs
@@ -34,7 +33,7 @@ workflow/
tsconfig.json # root TypeScript config tsconfig.json # root TypeScript config
``` ```
- Dependency layers: `workflow-protocol`(`workflow-util`, `workflow-moderator`) → `workflow-agent-kit``workflow-agent-hermes` / `cli-workflow` - Dependency layers: `workflow-protocol``workflow-util` `workflow-util-agent``workflow-agent-hermes` / `cli-workflow`
- Packages use `workspace:^` protocol (resolves to `^x.y.z` on publish) - Packages use `workspace:^` protocol (resolves to `^x.y.z` on publish)
- External CAS: `@uncaged/json-cas` (store API, hashing, schema validation) + `@uncaged/json-cas-fs` (filesystem backend) - External CAS: `@uncaged/json-cas` (store API, hashing, schema validation) + `@uncaged/json-cas-fs` (filesystem backend)
+1 -2
View File
@@ -94,8 +94,7 @@ This creates a markdown file in `.changeset/` describing the change. It will be
packages/ packages/
workflow-protocol/ # Shared types and JSON Schema workflow-protocol/ # Shared types and JSON Schema
workflow-util/ # Encoding, IDs, logging, frontmatter workflow-util/ # Encoding, IDs, logging, frontmatter
workflow-moderator/ # Status-based graph evaluator workflow-util-agent/ # createAgent factory, extract pipeline
workflow-agent-kit/ # createAgent factory, extract pipeline
workflow-agent-hermes/ # Hermes ACP agent workflow-agent-hermes/ # Hermes ACP agent
workflow-agent-builtin/ # Built-in LLM agent workflow-agent-builtin/ # Built-in LLM agent
workflow-agent-claude-code/ # Claude Code agent workflow-agent-claude-code/ # Claude Code agent
+4 -6
View File
@@ -3,7 +3,7 @@
[![CI](https://github.com/shazhou-ww/uncaged-workflow/actions/workflows/ci.yml/badge.svg)](https://github.com/shazhou-ww/uncaged-workflow/actions/workflows/ci.yml) [![CI](https://github.com/shazhou-ww/uncaged-workflow/actions/workflows/ci.yml/badge.svg)](https://github.com/shazhou-ww/uncaged-workflow/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/@uncaged/cli-workflow?label=%40uncaged%2Fcli-workflow)](https://www.npmjs.com/package/@uncaged/cli-workflow) [![npm](https://img.shields.io/npm/v/@uncaged/cli-workflow?label=%40uncaged%2Fcli-workflow)](https://www.npmjs.com/package/@uncaged/cli-workflow)
[![npm](https://img.shields.io/npm/v/@uncaged/workflow-protocol?label=%40uncaged%2Fworkflow-protocol)](https://www.npmjs.com/package/@uncaged/workflow-protocol) [![npm](https://img.shields.io/npm/v/@uncaged/workflow-protocol?label=%40uncaged%2Fworkflow-protocol)](https://www.npmjs.com/package/@uncaged/workflow-protocol)
[![npm](https://img.shields.io/npm/v/@uncaged/workflow-agent-kit?label=%40uncaged%2Fworkflow-agent-kit)](https://www.npmjs.com/package/@uncaged/workflow-agent-kit) [![npm](https://img.shields.io/npm/v/@uncaged/workflow-util-agent?label=%40uncaged%2Fworkflow-util-agent)](https://www.npmjs.com/package/@uncaged/workflow-util-agent)
A stateless workflow engine driven by a single-step CLI. Workflows are YAML definitions with roles, status-based routing, and a directed graph. Threads are immutable CAS-linked chains — each `uwf thread step` runs one moderator→agent→extract cycle and exits. A stateless workflow engine driven by a single-step CLI. Workflows are YAML definitions with roles, status-based routing, and a directed graph. Threads are immutable CAS-linked chains — each `uwf thread step` runs one moderator→agent→extract cycle and exits.
@@ -51,10 +51,9 @@ Layer 0 — Contract
Layer 1 — Shared infra Layer 1 — Shared infra
workflow-util Encoding, IDs, logging, frontmatter, paths workflow-util Encoding, IDs, logging, frontmatter, paths
workflow-moderator Status-based graph evaluator
Layer 2 — Agent framework Layer 2 — Agent framework
workflow-agent-kit createAgent factory, context builder, extract pipeline workflow-util-agent createAgent factory, context builder, extract pipeline
Layer 3 — Agent implementations Layer 3 — Agent implementations
workflow-agent-hermes Hermes ACP agent (uwf-hermes) workflow-agent-hermes Hermes ACP agent (uwf-hermes)
@@ -62,7 +61,7 @@ Layer 3 — Agent implementations
workflow-agent-claude-code Claude Code agent (uwf-claude-code) workflow-agent-claude-code Claude Code agent (uwf-claude-code)
Layer 4 — CLI Layer 4 — CLI
cli-workflow uwf binary — thread lifecycle, registry, CAS, setup cli-workflow uwf binary — thread lifecycle, registry, CAS, setup (includes status-based moderator)
App (uses protocol; not in the runtime engine stack) App (uses protocol; not in the runtime engine stack)
workflow-dashboard Web UI for visual workflow editing workflow-dashboard Web UI for visual workflow editing
@@ -78,8 +77,7 @@ See [docs/architecture.md](docs/architecture.md) for the full design — three-p
|---------|-----|-------------|------|--------| |---------|-----|-------------|------|--------|
| `cli-workflow` | `@uncaged/cli-workflow` | `uwf` CLI — thread lifecycle, workflow registry, CAS inspection, setup | cli | [README](packages/cli-workflow/README.md) | | `cli-workflow` | `@uncaged/cli-workflow` | `uwf` CLI — thread lifecycle, workflow registry, CAS inspection, setup | cli | [README](packages/cli-workflow/README.md) |
| `workflow-protocol` | `@uncaged/workflow-protocol` | Shared TypeScript types and JSON Schema constants | lib | [README](packages/workflow-protocol/README.md) | | `workflow-protocol` | `@uncaged/workflow-protocol` | Shared TypeScript types and JSON Schema constants | lib | [README](packages/workflow-protocol/README.md) |
| `workflow-moderator` | `@uncaged/workflow-moderator` | Status-based graph evaluator — next role or `$END` | lib | [README](packages/workflow-moderator/README.md) | | `workflow-util-agent` | `@uncaged/workflow-util-agent` | `createAgent` factory, context builder, extract pipeline | lib | [README](packages/workflow-util-agent/README.md) |
| `workflow-agent-kit` | `@uncaged/workflow-agent-kit` | `createAgent` factory, context builder, extract pipeline | lib | [README](packages/workflow-agent-kit/README.md) |
| `workflow-util` | `@uncaged/workflow-util` | Crockford Base32, ULID, logger, frontmatter parsing, storage paths | lib | [README](packages/workflow-util/README.md) | | `workflow-util` | `@uncaged/workflow-util` | Crockford Base32, ULID, logger, frontmatter parsing, storage paths | lib | [README](packages/workflow-util/README.md) |
| `workflow-agent-hermes` | `@uncaged/workflow-agent-hermes` | `uwf-hermes` — spawns Hermes chat via ACP | agent | [README](packages/workflow-agent-hermes/README.md) | | `workflow-agent-hermes` | `@uncaged/workflow-agent-hermes` | `uwf-hermes` — spawns Hermes chat via ACP | agent | [README](packages/workflow-agent-hermes/README.md) |
| `workflow-agent-builtin` | `@uncaged/workflow-agent-builtin` | `uwf-builtin` — built-in LLM agent with file/shell tools | agent | [README](packages/workflow-agent-builtin/README.md) | | `workflow-agent-builtin` | `@uncaged/workflow-agent-builtin` | `uwf-builtin` — built-in LLM agent with file/shell tools | agent | [README](packages/workflow-agent-builtin/README.md) |
+9 -13
View File
@@ -8,7 +8,7 @@
A stateless workflow engine driven by a single-step CLI. Workflows are YAML definitions stored as CAS nodes; threads are immutable chains of CAS-linked step nodes. No daemon — each `uwf thread step` invocation runs one moderator→agent→extract cycle and exits. A stateless workflow engine driven by a single-step CLI. Workflows are YAML definitions stored as CAS nodes; threads are immutable chains of CAS-linked step nodes. No daemon — each `uwf thread step` invocation runs one moderator→agent→extract cycle and exits.
The implementation lives in **6** active packages under `packages/`, plus two external CAS packages (`@uncaged/json-cas`, `@uncaged/json-cas-fs`). Legacy packages reside in `legacy-packages/` and are not part of the active stack. The implementation lives in **5** active packages under `packages/`, plus two external CAS packages (`@uncaged/json-cas`, `@uncaged/json-cas-fs`). Legacy packages reside in `legacy-packages/` and are not part of the active stack.
## Package map ## Package map
@@ -16,10 +16,9 @@ The implementation lives in **6** active packages under `packages/`, plus two ex
|-------|---------|---------------| |-------|---------|---------------|
| Contract | `@uncaged/workflow-protocol``workflow-protocol` | Shared TypeScript types (`WorkflowPayload`, `StepNodePayload`, `ModeratorContext`, `WorkflowConfig`, etc.). No runtime deps beyond `@uncaged/json-cas-fs`. | | Contract | `@uncaged/workflow-protocol``workflow-protocol` | Shared TypeScript types (`WorkflowPayload`, `StepNodePayload`, `ModeratorContext`, `WorkflowConfig`, etc.). No runtime deps beyond `@uncaged/json-cas-fs`. |
| Shared infra | `@uncaged/workflow-util``workflow-util` | Crockford Base32, ULID generation, `createLogger`, frontmatter parsing/validation. | | Shared infra | `@uncaged/workflow-util``workflow-util` | Crockford Base32, ULID generation, `createLogger`, frontmatter parsing/validation. |
| Moderator | `@uncaged/workflow-moderator``workflow-moderator` | Status-based graph evaluator: given a routing graph, last role, and last output, returns the next role or `$END`. | | Agent framework | `@uncaged/workflow-util-agent``workflow-util-agent` | `createAgent` entrypoint factory, context builder, frontmatter fast-path extractor, LLM extract fallback, output format instruction builder. |
| Agent framework | `@uncaged/workflow-agent-kit``workflow-agent-kit` | `createAgent` entrypoint factory, context builder, frontmatter fast-path extractor, LLM extract fallback, output format instruction builder. |
| Agent: Hermes | `@uncaged/workflow-agent-hermes``workflow-agent-hermes` | `uwf-hermes` CLI binary — spawns `hermes chat`, pipes prompt, captures session detail. | | Agent: Hermes | `@uncaged/workflow-agent-hermes``workflow-agent-hermes` | `uwf-hermes` CLI binary — spawns `hermes chat`, pipes prompt, captures session detail. |
| CLI | `@uncaged/cli-workflow``cli-workflow` | `uwf` binary — thread lifecycle, workflow registry, CAS inspection, setup. | | CLI | `@uncaged/cli-workflow``cli-workflow` | `uwf` binary — thread lifecycle, workflow registry, CAS inspection, setup. Includes status-based graph evaluator in `src/moderator/` (next role or `$END`). |
### External dependencies ### External dependencies
@@ -27,7 +26,7 @@ The implementation lives in **6** active packages under `packages/`, plus two ex
|---------|------| |---------|------|
| `@uncaged/json-cas` | Content-addressed store API, XXH64 hashing, JSON Schema registration and validation. | | `@uncaged/json-cas` | Content-addressed store API, XXH64 hashing, JSON Schema registration and validation. |
| `@uncaged/json-cas-fs` | Filesystem backend for `json-cas`. | | `@uncaged/json-cas-fs` | Filesystem backend for `json-cas`. |
| `mustache` | Template renderer for edge prompts (used by `workflow-moderator`). | | `mustache` | Template renderer for edge prompts (used by `cli-workflow` moderator). |
| `commander` | CLI argument parsing (used by `cli-workflow`). | | `commander` | CLI argument parsing (used by `cli-workflow`). |
| `dotenv` | Loads `.env` files for API keys. | | `dotenv` | Loads `.env` files for API keys. |
| `yaml` | YAML parse/stringify. | | `yaml` | YAML parse/stringify. |
@@ -45,10 +44,9 @@ flowchart BT
end end
subgraph L1["Layer 1 — shared"] subgraph L1["Layer 1 — shared"]
util["@uncaged/workflow-util"] util["@uncaged/workflow-util"]
moderator["@uncaged/workflow-moderator"]
end end
subgraph L2["Layer 2 — agent framework"] subgraph L2["Layer 2 — agent framework"]
kit["@uncaged/workflow-agent-kit"] kit["@uncaged/workflow-util-agent"]
end end
subgraph L3["Layer 3 — agent implementations"] subgraph L3["Layer 3 — agent implementations"]
hermes["@uncaged/workflow-agent-hermes"] hermes["@uncaged/workflow-agent-hermes"]
@@ -58,7 +56,6 @@ flowchart BT
end end
protocol --> jcasfs protocol --> jcasfs
util --> protocol util --> protocol
moderator --> protocol
kit --> protocol kit --> protocol
kit --> util kit --> util
kit --> jcas kit --> jcas
@@ -68,7 +65,6 @@ flowchart BT
cli --> protocol cli --> protocol
cli --> util cli --> util
cli --> kit cli --> kit
cli --> moderator
cli --> jcas cli --> jcas
cli --> jcasfs cli --> jcasfs
``` ```
@@ -222,7 +218,7 @@ Each agent is an external command invoked by `uwf thread step`:
Contract: Contract:
1. `uwf thread step` determines the next role via the moderator 1. `uwf thread step` determines the next role via the moderator
2. Agent CLI is spawned with `(thread-id, role)` as positional args 2. Agent CLI is spawned with `(thread-id, role)` as positional args
3. `workflow-agent-kit` (`createAgent`) handles the boilerplate: 3. `workflow-util-agent` (`createAgent`) handles the boilerplate:
- Parses argv - Parses argv
- Loads `.env` from storage root - Loads `.env` from storage root
- Builds `AgentContext` by walking the CAS chain from `threads.yaml` head - Builds `AgentContext` by walking the CAS chain from `threads.yaml` head
@@ -255,11 +251,11 @@ scope: role
Fixed the login redirect by updating the auth middleware... Fixed the login redirect by updating the auth middleware...
``` ```
The `outputFormatInstruction` (built by `buildOutputFormatInstruction` in `workflow-agent-kit`) is prepended to the role's system prompt, so the deliverable format is the first thing the agent sees. It lists the expected frontmatter fields derived from the role's `meta` JSON Schema. The `outputFormatInstruction` (built by `buildOutputFormatInstruction` in `workflow-util-agent`) is prepended to the role's system prompt, so the deliverable format is the first thing the agent sees. It lists the expected frontmatter fields derived from the role's `meta` JSON Schema.
## Two-layer extract ## Two-layer extract
Structured output extraction uses a two-layer strategy (`workflow-agent-kit`): Structured output extraction uses a two-layer strategy (`workflow-util-agent`):
### Layer 1: frontmatter fast path (`frontmatter.ts`) ### Layer 1: frontmatter fast path (`frontmatter.ts`)
@@ -283,7 +279,7 @@ If the fast path returns `null` (no frontmatter, invalid, or doesn't satisfy sch
## Prompt injection ## Prompt injection
`workflow-agent-kit` prepends two pieces of context to the agent's system prompt: `workflow-util-agent` prepends two pieces of context to the agent's system prompt:
1. **Deliverable format instruction** — generated from the role's `meta` schema, tells the agent exactly what frontmatter fields to produce and the expected format 1. **Deliverable format instruction** — generated from the role's `meta` schema, tells the agent exactly what frontmatter fields to produce and the expected format
2. **Scope constraint** — "Focus exclusively on YOUR role's deliverable. Do not perform actions outside your role's scope." 2. **Scope constraint** — "Focus exclusively on YOUR role's deliverable. Do not perform actions outside your role's scope."
+16 -16
View File
@@ -78,9 +78,9 @@ Agent 解析优先级(`resolveAgentConfig`):
#### 环境变量:Storage Root #### 环境变量:Storage Root
文档中写的 `UWF_STORAGE_ROOT` **在当前代码中不存在**。实际优先级(`workflow-agent-kit` / `cli-workflow` 一致): 文档中写的 `UWF_STORAGE_ROOT` **在当前代码中不存在**。实际优先级(`workflow-util-agent` / `cli-workflow` 一致):
```33:43:packages/workflow-agent-kit/src/storage.ts ```33:43:packages/workflow-util-agent/src/storage.ts
export function resolveStorageRoot(): string { export function resolveStorageRoot(): string {
const internal = process.env.UNCAGED_WORKFLOW_STORAGE_ROOT; const internal = process.env.UNCAGED_WORKFLOW_STORAGE_ROOT;
if (internal !== undefined && internal !== "") { if (internal !== undefined && internal !== "") {
@@ -107,7 +107,7 @@ Agent 子进程通过继承的 `process.env` 与父 CLI 共享同一 storage roo
### Q2: createAgent 工厂 ### Q2: createAgent 工厂
workflow-agent-kit 的 `createAgent` 做了什么?它的完整生命周期是什么? workflow-util-agent 的 `createAgent` 做了什么?它的完整生命周期是什么?
**调研要点:** **调研要点:**
- `AgentOptions` 类型的 `run` 和 `continue` 回调签名 - `AgentOptions` 类型的 `run` 和 `continue` 回调签名
@@ -119,7 +119,7 @@ workflow-agent-kit 的 `createAgent` 做了什么?它的完整生命周期是
#### 类型定义 #### 类型定义
```4:35:packages/workflow-agent-kit/src/types.ts ```4:35:packages/workflow-util-agent/src/types.ts
export type AgentContext = ModeratorContext & { export type AgentContext = ModeratorContext & {
threadId: ThreadId; threadId: ThreadId;
role: string; role: string;
@@ -156,7 +156,7 @@ export type AgentOptions = {
#### 生命周期(按执行顺序) #### 生命周期(按执行顺序)
```101:152:packages/workflow-agent-kit/src/run.ts ```101:152:packages/workflow-util-agent/src/run.ts
export function createAgent(options: AgentOptions): () => Promise<void> { export function createAgent(options: AgentOptions): () => Promise<void> {
return async function main(): Promise<void> { return async function main(): Promise<void> {
const { threadId, role } = parseArgv(process.argv); const { threadId, role } = parseArgv(process.argv);
@@ -197,7 +197,7 @@ export function createAgent(options: AgentOptions): () => Promise<void> {
#### StepNode 写入结构 #### StepNode 写入结构
```44:68:packages/workflow-agent-kit/src/run.ts ```44:68:packages/workflow-util-agent/src/run.ts
async function writeStepNode(options: { async function writeStepNode(options: {
store: AgentStore["store"]; store: AgentStore["store"];
schemas: AgentStore["schemas"]; schemas: AgentStore["schemas"];
@@ -274,7 +274,7 @@ export type StepContext = Omit<StepRecord, "output"> & {
`buildContextWithMeta` 还返回 `meta`: `buildContextWithMeta` 还返回 `meta`:
```148:154:packages/workflow-agent-kit/src/context.ts ```148:154:packages/workflow-util-agent/src/context.ts
export type BuildContextMeta = { export type BuildContextMeta = {
storageRoot: string; storageRoot: string;
store: Store; store: Store;
@@ -337,7 +337,7 @@ async function resolveFrontmatterRef(..., frontmatter: unknown): Promise<CasRef>
#### Frontmatter fast-path(createAgent 实际使用的路径) #### Frontmatter fast-path(createAgent 实际使用的路径)
```148:195:packages/workflow-agent-kit/src/frontmatter.ts ```148:195:packages/workflow-util-agent/src/frontmatter.ts
export async function tryFrontmatterFastPath( export async function tryFrontmatterFastPath(
raw: string, raw: string,
outputSchema: CasRef, outputSchema: CasRef,
@@ -357,7 +357,7 @@ export async function tryFrontmatterFastPath(
#### LLM extract fallback(已实现但未接入 createAgent) #### LLM extract fallback(已实现但未接入 createAgent)
```135:181:packages/workflow-agent-kit/src/extract.ts ```135:181:packages/workflow-util-agent/src/extract.ts
export async function extract( export async function extract(
rawOutput: string, rawOutput: string,
outputSchema: CasRef, outputSchema: CasRef,
@@ -374,7 +374,7 @@ export async function extract(
#### Correction prompt(retry) #### Correction prompt(retry)
```125:128:packages/workflow-agent-kit/src/run.ts ```125:128:packages/workflow-util-agent/src/run.ts
const correctionMessage = const correctionMessage =
"Your previous response did not contain valid YAML frontmatter matching the role schema.\n" + "Your previous response did not contain valid YAML frontmatter matching the role schema.\n" +
"You MUST begin your response with a YAML frontmatter block (--- delimited).\n" + "You MUST begin your response with a YAML frontmatter block (--- delimited).\n" +
@@ -425,7 +425,7 @@ export type WorkflowConfig = {
#### resolveModel #### resolveModel
```32:50:packages/workflow-agent-kit/src/extract.ts ```32:50:packages/workflow-util-agent/src/extract.ts
export function resolveModel(config: WorkflowConfig, alias: ModelAlias): ResolvedLlmProvider { export function resolveModel(config: WorkflowConfig, alias: ModelAlias): ResolvedLlmProvider {
const modelEntry = config.models[alias]; const modelEntry = config.models[alias];
const providerEntry = config.providers[modelEntry.provider]; const providerEntry = config.providers[modelEntry.provider];
@@ -438,7 +438,7 @@ export function resolveModel(config: WorkflowConfig, alias: ModelAlias): Resolve
Extract 专用别名解析: Extract 专用别名解析:
```18:30:packages/workflow-agent-kit/src/extract.ts ```18:30:packages/workflow-util-agent/src/extract.ts
export function resolveExtractModelAlias(config: WorkflowConfig): ModelAlias { export function resolveExtractModelAlias(config: WorkflowConfig): ModelAlias {
return config.modelOverrides?.extract ?? (config.models.extract ? "extract" : config.models.default ? "default" : config.defaultModel); return config.modelOverrides?.extract ?? (config.models.extract ? "extract" : config.models.default ? "default" : config.defaultModel);
} }
@@ -448,7 +448,7 @@ export function resolveExtractModelAlias(config: WorkflowConfig): ModelAlias {
#### chatCompletionText #### chatCompletionText
```87:124:packages/workflow-agent-kit/src/extract.ts ```87:124:packages/workflow-util-agent/src/extract.ts
async function chatCompletionText( async function chatCompletionText(
provider: ResolvedLlmProvider, provider: ResolvedLlmProvider,
messages: Array<{ role: "system" | "user"; content: string }>, messages: Array<{ role: "system" | "user"; content: string }>,
@@ -463,7 +463,7 @@ async function chatCompletionText(
| 多模态 | **无**(仅 text `content`) | | 多模态 | **无**(仅 text `content`) |
| Extract 专用 | `response_format: { type: "json_object" }` | | Extract 专用 | `response_format: { type: "json_object" }` |
builtin agent 的 run loop 需要**新写**带 `tools` 的 completion 客户端(可放在 `workflow-agent-builtin` 或扩展 `workflow-agent-kit` 的 `llm/` 模块),不能复用当前 `chatCompletionText` 而不改。 builtin agent 的 run loop 需要**新写**带 `tools` 的 completion 客户端(可放在 `workflow-agent-builtin` 或扩展 `workflow-util-agent` 的 `llm/` 模块),不能复用当前 `chatCompletionText` 而不改。
--- ---
@@ -609,7 +609,7 @@ flowchart TB
Loop --> Detail Loop --> Detail
end end
subgraph kit ["workflow-agent-kit"] subgraph kit ["workflow-util-agent"]
Ctx["buildContextWithMeta"] Ctx["buildContextWithMeta"]
FM["tryFrontmatterFastPath"] FM["tryFrontmatterFastPath"]
Persist["persistStep"] Persist["persistStep"]
@@ -630,7 +630,7 @@ flowchart TB
Spawn -->|"stdout: step hash"| Step Spawn -->|"stdout: step hash"| Step
``` ```
**新包**:`packages/workflow-agent-builtin`,bin `uwf-builtin`,仅依赖 `workflow-agent-kit`、`workflow-protocol`、`workflow-util`(可选 `@uncaged/json-cas` 写 detail schema)。 **新包**:`packages/workflow-agent-builtin`,bin `uwf-builtin`,仅依赖 `workflow-util-agent`、`workflow-protocol`、`workflow-util`(可选 `@uncaged/json-cas` 写 detail schema)。
**分层**: **分层**:
+2 -3
View File
@@ -341,9 +341,8 @@ OPENROUTER_API_KEY=sk-or-...
``` ```
packages/ packages/
├── cli-workflow/ # @uncaged/cli-workflow — uwf CLI(thread/workflow 命令) ├── cli-workflow/ # @uncaged/cli-workflow — uwf CLI(thread/workflow 命令,含 src/moderator/
├── workflow-moderator/ # @uncaged/workflow-moderator — Status-based moderator 引擎 ├── workflow-util-agent/ # @uncaged/workflow-util-agent — Agent CLI 框架(含 extractor
├── workflow-agent-kit/ # @uncaged/workflow-agent-kit — Agent CLI 框架(含 extractor)
├── workflow-agent-hermes/ # @uncaged/workflow-agent-hermes — uwf-hermes CLI ├── workflow-agent-hermes/ # @uncaged/workflow-agent-hermes — uwf-hermes CLI
├── workflow-agent-cursor/ # @uncaged/workflow-agent-cursor — uwf-cursor CLI ├── workflow-agent-cursor/ # @uncaged/workflow-agent-cursor — uwf-cursor CLI
└── workflow-protocol/ # @uncaged/workflow-protocol — 共享类型定义 └── workflow-protocol/ # @uncaged/workflow-protocol — 共享类型定义
@@ -32,7 +32,7 @@
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/shazhou-ww/uncaged-workflow.git", "url": "https://github.com/shazhou-ww/uncaged-workflow.git",
"directory": "packages/workflow-moderator" "directory": "legacy-packages/workflow-moderator"
}, },
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme", "homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
"bugs": { "bugs": {
+2 -1
View File
@@ -20,7 +20,7 @@ workflow → thread → step → turn
This package has no library `src/index.ts` — it is consumed as a CLI binary only. This package has no library `src/index.ts` — it is consumed as a CLI binary only.
**Dependencies:** `@uncaged/json-cas`, `@uncaged/json-cas-fs`, `@uncaged/workflow-agent-kit`, `@uncaged/workflow-moderator`, `@uncaged/workflow-protocol`, `@uncaged/workflow-util`, `commander`, `dotenv`, `yaml` **Dependencies:** `@uncaged/json-cas`, `@uncaged/json-cas-fs`, `@uncaged/workflow-util-agent`, `@uncaged/workflow-protocol`, `@uncaged/workflow-util`, `commander`, `dotenv`, `mustache`, `yaml`
## Installation ## Installation
@@ -190,6 +190,7 @@ src/
├── store.ts CAS store + registry initialization ├── store.ts CAS store + registry initialization
├── validate.ts Workflow YAML validation ├── validate.ts Workflow YAML validation
├── schemas.ts CLI-local schema registration ├── schemas.ts CLI-local schema registration
├── moderator/ Status-based graph evaluator (next role or $END)
└── commands/ └── commands/
├── thread.ts Thread lifecycle and exec ├── thread.ts Thread lifecycle and exec
├── step.ts Step operations (list/show/read/fork) ├── step.ts Step operations (list/show/read/fork)
+3 -2
View File
@@ -13,12 +13,12 @@
"dependencies": { "dependencies": {
"@uncaged/json-cas": "^0.5.2", "@uncaged/json-cas": "^0.5.2",
"@uncaged/json-cas-fs": "^0.5.2", "@uncaged/json-cas-fs": "^0.5.2",
"@uncaged/workflow-agent-kit": "workspace:^",
"@uncaged/workflow-moderator": "workspace:^",
"@uncaged/workflow-protocol": "workspace:^", "@uncaged/workflow-protocol": "workspace:^",
"@uncaged/workflow-util": "workspace:^", "@uncaged/workflow-util": "workspace:^",
"@uncaged/workflow-util-agent": "workspace:^",
"commander": "^14.0.3", "commander": "^14.0.3",
"dotenv": "^16.6.1", "dotenv": "^16.6.1",
"mustache": "^4.2.0",
"yaml": "^2.8.4" "yaml": "^2.8.4"
}, },
"scripts": { "scripts": {
@@ -29,6 +29,7 @@
"access": "public" "access": "public"
}, },
"devDependencies": { "devDependencies": {
"@types/mustache": "^4.2.6",
"vitest": "^4.1.6" "vitest": "^4.1.6"
}, },
"repository": { "repository": {
@@ -0,0 +1,132 @@
import { describe, expect, test } from "vitest";
import type { Target, WorkflowPayload } from "@uncaged/workflow-protocol";
import { evaluate } from "../moderator/evaluate.js";
const solveIssueGraph: WorkflowPayload["graph"] = {
$START: {
_: { role: "planner", prompt: "Start planning from the issue in the task." },
},
planner: {
_: { role: "developer", prompt: "Implement the plan: {{plan}}" },
},
developer: {
_: { role: "reviewer", prompt: "Review the changes: {{summary}}" },
},
reviewer: {
approved: { role: "$END", prompt: "Done." },
rejected: { role: "developer", prompt: "Fix: {{comments}}" },
},
};
describe("evaluate", () => {
test("$START → first role (unit status _)", () => {
const result = evaluate(solveIssueGraph, "$START", { $status: "_" });
expect(result).toEqual({
ok: true,
value: { role: "planner", prompt: "Start planning from the issue in the task." },
});
});
test("status-based routing (reviewer rejected → developer)", () => {
const result = evaluate(solveIssueGraph, "reviewer", {
$status: "rejected",
comments: "missing tests",
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: "Fix: missing tests" },
});
});
test("status-based routing (reviewer approved → $END)", () => {
const result = evaluate(solveIssueGraph, "reviewer", { $status: "approved" });
expect(result).toEqual({
ok: true,
value: { role: "$END", prompt: "Done." },
});
});
test("missing role in graph → error", () => {
const result = evaluate(solveIssueGraph, "unknown-role", { $status: "_" });
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error.message).toBe('no transitions defined for role "unknown-role"');
}
});
test("missing status in graph → error", () => {
const result = evaluate(solveIssueGraph, "reviewer", { $status: "pending" });
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error.message).toBe('no transition for role "reviewer" with status "pending"');
}
});
test("mustache template rendering with simple fields", () => {
const result = evaluate(solveIssueGraph, "planner", {
$status: "_",
plan: "Add auth middleware",
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: "Implement the plan: Add auth middleware" },
});
});
test("mustache does not HTML-escape prompt content", () => {
const result = evaluate(solveIssueGraph, "reviewer", {
$status: "rejected",
comments: 'use <T> & "Result<T, E>" types',
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: 'Fix: use <T> & "Result<T, E>" types' },
});
});
test("triple mustache also works for unescaped output", () => {
const graph: Record<string, Record<string, Target>> = {
reviewer: {
_: { role: "developer", prompt: "Fix: {{{comments}}}" },
},
};
const result = evaluate(graph, "reviewer", {
$status: "_",
comments: "<script>alert(1)</script>",
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: "Fix: <script>alert(1)</script>" },
});
});
test("missing $status defaults to _ (unit routing)", () => {
const result = evaluate(solveIssueGraph, "planner", {
plan: "Add auth middleware",
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: "Implement the plan: Add auth middleware" },
});
});
test("mustache template with nested object paths", () => {
const graph: Record<string, Record<string, Target>> = {
reviewer: {
_: {
role: "developer",
prompt: "Address: {{review.comments}}",
},
},
};
const result = evaluate(graph, "reviewer", {
$status: "_",
review: { comments: "refactor the handler" },
});
expect(result).toEqual({
ok: true,
value: { role: "developer", prompt: "Address: refactor the handler" },
});
});
});
+2 -2
View File
@@ -2,8 +2,8 @@ import { execFileSync, spawn } from "node:child_process";
import { access, readFile } from "node:fs/promises"; import { access, readFile } from "node:fs/promises";
import { dirname, isAbsolute, resolve as resolvePath } from "node:path"; import { dirname, isAbsolute, resolve as resolvePath } from "node:path";
import { validate } from "@uncaged/json-cas"; import { validate } from "@uncaged/json-cas";
import { getEnvPath, loadWorkflowConfig } from "@uncaged/workflow-agent-kit"; import { getEnvPath, loadWorkflowConfig } from "@uncaged/workflow-util-agent";
import { evaluate } from "@uncaged/workflow-moderator"; import { evaluate } from "../moderator/index.js";
import type { import type {
AgentAlias, AgentAlias,
AgentConfig, AgentConfig,
@@ -0,0 +1,53 @@
import type { Target } from "@uncaged/workflow-protocol";
import mustache from "mustache";
import type { EvaluateResult, Result } from "./types.js";
// Disable HTML escaping — prompts are plain text, not HTML.
mustache.escape = (text: string) => text;
const START_ROLE = "$START";
const UNIT_STATUS = "_";
type LastOutput = Record<string, unknown>;
const STATUS_KEY = "$status";
export function evaluate(
graph: Record<string, Record<string, Target>>,
lastRole: string,
lastOutput: LastOutput,
): Result<EvaluateResult, Error> {
const status =
lastRole === START_ROLE
? UNIT_STATUS
: typeof lastOutput[STATUS_KEY] === "string"
? (lastOutput[STATUS_KEY] as string)
: UNIT_STATUS;
const roleTargets = graph[lastRole];
if (roleTargets === undefined) {
return {
ok: false,
error: new Error(`no transitions defined for role "${lastRole}"`),
};
}
const target = roleTargets[status];
if (target === undefined) {
return {
ok: false,
error: new Error(`no transition for role "${lastRole}" with status "${status}"`),
};
}
try {
const prompt = mustache.render(target.prompt, lastOutput);
return { ok: true, value: { role: target.role, prompt } };
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error(String(error)),
};
}
}
@@ -0,0 +1,2 @@
export { evaluate } from "./evaluate.js";
export type { EvaluateResult } from "./types.js";
@@ -0,0 +1,7 @@
export type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
/** The result of moderator evaluation — which role to go to, and the edge prompt. */
export type EvaluateResult = {
role: string;
prompt: string;
};
+1 -2
View File
@@ -7,7 +7,6 @@
"include": ["src"], "include": ["src"],
"references": [ "references": [
{ "path": "../workflow-protocol" }, { "path": "../workflow-protocol" },
{ "path": "../workflow-moderator" }, { "path": "../workflow-util-agent" }
{ "path": "../workflow-agent-kit" }
] ]
} }
+1 -1
View File
@@ -8,7 +8,7 @@ Layer 3 agent implementation. Runs an OpenAI-compatible chat completion loop wit
Useful when you want a self-contained agent without an external CLI like Hermes or Claude Code. Useful when you want a self-contained agent without an external CLI like Hermes or Claude Code.
**Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-agent-kit`, `@uncaged/workflow-util` **Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-util-agent`, `@uncaged/workflow-util`
## Installation ## Installation
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import type { AgentContext } from "@uncaged/workflow-agent-kit"; import type { AgentContext } from "@uncaged/workflow-util-agent";
import { buildBuiltinMessages } from "../src/prompt.js"; import { buildBuiltinMessages } from "../src/prompt.js";
+1 -1
View File
@@ -23,7 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@uncaged/json-cas": "^0.5.2", "@uncaged/json-cas": "^0.5.2",
"@uncaged/workflow-agent-kit": "workspace:^", "@uncaged/workflow-util-agent": "workspace:^",
"@uncaged/workflow-util": "workspace:^" "@uncaged/workflow-util": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
+1 -1
View File
@@ -6,7 +6,7 @@ import {
loadWorkflowConfig, loadWorkflowConfig,
resolveModel, resolveModel,
resolveStorageRoot, resolveStorageRoot,
} from "@uncaged/workflow-agent-kit"; } from "@uncaged/workflow-util-agent";
import { createLogger, generateUlid } from "@uncaged/workflow-util"; import { createLogger, generateUlid } from "@uncaged/workflow-util";
import { storeBuiltinDetail } from "./detail.js"; import { storeBuiltinDetail } from "./detail.js";
@@ -1,4 +1,4 @@
import type { ResolvedLlmProvider } from "@uncaged/workflow-agent-kit"; import type { ResolvedLlmProvider } from "@uncaged/workflow-util-agent";
import type { import type {
ChatMessage, ChatMessage,
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ResolvedLlmProvider } from "@uncaged/workflow-agent-kit"; import type { ResolvedLlmProvider } from "@uncaged/workflow-util-agent";
import { createLogger } from "@uncaged/workflow-util"; import { createLogger } from "@uncaged/workflow-util";
import { import {
@@ -1,4 +1,4 @@
import { type AgentContext, buildRolePrompt } from "@uncaged/workflow-agent-kit"; import { type AgentContext, buildRolePrompt } from "@uncaged/workflow-util-agent";
import type { ChatMessage } from "./llm/index.js"; import type { ChatMessage } from "./llm/index.js";
@@ -5,5 +5,5 @@
"outDir": "dist" "outDir": "dist"
}, },
"include": ["src"], "include": ["src"],
"references": [{ "path": "../workflow-agent-kit" }, { "path": "../workflow-util" }] "references": [{ "path": "../workflow-util-agent" }, { "path": "../workflow-util" }]
} }
@@ -6,7 +6,7 @@
Layer 3 agent implementation. Spawns the `claude` CLI with a composed system prompt (role definition, task, prior steps, edge prompt). Parses stream or JSON stdout, caches session IDs for multi-turn continuation, and stores raw output plus structured detail in CAS. Layer 3 agent implementation. Spawns the `claude` CLI with a composed system prompt (role definition, task, prior steps, edge prompt). Parses stream or JSON stdout, caches session IDs for multi-turn continuation, and stores raw output plus structured detail in CAS.
**Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-agent-kit` **Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-util-agent`
## Installation ## Installation
@@ -86,6 +86,6 @@ src/
## Configuration ## Configuration
Uses session caching from `@uncaged/workflow-agent-kit` (`getCachedSessionId` / `setCachedSessionId`). No separate config file — relies on the Claude Code CLI's own authentication. Uses session caching from `@uncaged/workflow-util-agent` (`getCachedSessionId` / `setCachedSessionId`). No separate config file — relies on the Claude Code CLI's own authentication.
Maximum turns per invocation: 90 (constant in `claude-code.ts`). Maximum turns per invocation: 90 (constant in `claude-code.ts`).
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import type { AgentContext } from "@uncaged/workflow-agent-kit"; import type { AgentContext } from "@uncaged/workflow-util-agent";
import type { ThreadId } from "@uncaged/workflow-protocol"; import type { ThreadId } from "@uncaged/workflow-protocol";
import { buildClaudeCodePrompt } from "../src/claude-code.js"; import { buildClaudeCodePrompt } from "../src/claude-code.js";
@@ -23,7 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@uncaged/json-cas": "^0.5.2", "@uncaged/json-cas": "^0.5.2",
"@uncaged/workflow-agent-kit": "workspace:^", "@uncaged/workflow-util-agent": "workspace:^",
"@uncaged/workflow-util": "workspace:^" "@uncaged/workflow-util": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
@@ -8,7 +8,7 @@ import {
createAgent, createAgent,
getCachedSessionId, getCachedSessionId,
setCachedSessionId, setCachedSessionId,
} from "@uncaged/workflow-agent-kit"; } from "@uncaged/workflow-util-agent";
import { createLogger } from "@uncaged/workflow-util"; import { createLogger } from "@uncaged/workflow-util";
import { parseClaudeCodeStreamOutput, storeClaudeCodeDetail } from "./session-detail.js"; import { parseClaudeCodeStreamOutput, storeClaudeCodeDetail } from "./session-detail.js";
@@ -2,5 +2,5 @@
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "rootDir": "src", "outDir": "dist" }, "compilerOptions": { "rootDir": "src", "outDir": "dist" },
"include": ["src"], "include": ["src"],
"references": [{ "path": "../workflow-agent-kit" }] "references": [{ "path": "../workflow-util-agent" }]
} }
+1 -1
View File
@@ -6,7 +6,7 @@
Layer 3 agent implementation. Wraps the Hermes CLI using the Agent Client Protocol (ACP). On first visit to a role it sends a composed prompt (role definition, task, history, edge prompt); on continuation it resumes the cached session. Session transcripts and raw output are stored as CAS detail nodes. Layer 3 agent implementation. Wraps the Hermes CLI using the Agent Client Protocol (ACP). On first visit to a role it sends a composed prompt (role definition, task, history, edge prompt); on continuation it resumes the cached session. Session transcripts and raw output are stored as CAS detail nodes.
**Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-agent-kit`, `@uncaged/workflow-protocol`, `@uncaged/workflow-util` **Dependencies:** `@uncaged/json-cas`, `@uncaged/workflow-util-agent`, `@uncaged/workflow-protocol`, `@uncaged/workflow-util`
## Installation ## Installation
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import type { AgentContext } from "@uncaged/workflow-agent-kit"; import type { AgentContext } from "@uncaged/workflow-util-agent";
import type { ThreadId } from "@uncaged/workflow-protocol"; import type { ThreadId } from "@uncaged/workflow-protocol";
import { buildHermesPrompt } from "../src/hermes.js"; import { buildHermesPrompt } from "../src/hermes.js";
+1 -1
View File
@@ -23,7 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@uncaged/json-cas": "^0.5.2", "@uncaged/json-cas": "^0.5.2",
"@uncaged/workflow-agent-kit": "workspace:^", "@uncaged/workflow-util-agent": "workspace:^",
"@uncaged/workflow-protocol": "workspace:^", "@uncaged/workflow-protocol": "workspace:^",
"@uncaged/workflow-util": "workspace:^" "@uncaged/workflow-util": "workspace:^"
}, },
+1 -1
View File
@@ -5,7 +5,7 @@ import {
buildContinuationPrompt, buildContinuationPrompt,
buildRolePrompt, buildRolePrompt,
createAgent, createAgent,
} from "@uncaged/workflow-agent-kit"; } from "@uncaged/workflow-util-agent";
import { createLogger } from "@uncaged/workflow-util"; import { createLogger } from "@uncaged/workflow-util";
import { HermesAcpClient } from "./acp-client.js"; import { HermesAcpClient } from "./acp-client.js";
@@ -3,7 +3,7 @@
import { import {
getCachedSessionId as getCachedSessionIdBase, getCachedSessionId as getCachedSessionIdBase,
setCachedSessionId as setCachedSessionIdBase, setCachedSessionId as setCachedSessionIdBase,
} from "@uncaged/workflow-agent-kit"; } from "@uncaged/workflow-util-agent";
import type { ThreadId } from "@uncaged/workflow-protocol"; import type { ThreadId } from "@uncaged/workflow-protocol";
export async function getCachedSessionId(threadId: ThreadId, role: string): Promise<string | null> { export async function getCachedSessionId(threadId: ThreadId, role: string): Promise<string | null> {
+1 -1
View File
@@ -5,5 +5,5 @@
"outDir": "dist" "outDir": "dist"
}, },
"include": ["src"], "include": ["src"],
"references": [{ "path": "../workflow-agent-kit" }] "references": [{ "path": "../workflow-util-agent" }]
} }
+1 -1
View File
@@ -183,4 +183,4 @@ src/
## Configuration ## Configuration
This package defines `WorkflowConfig` types only. Runtime config loading lives in `@uncaged/workflow-agent-kit` (`loadWorkflowConfig`). This package defines `WorkflowConfig` types only. Runtime config loading lives in `@uncaged/workflow-util-agent` (`loadWorkflowConfig`).
@@ -1,4 +1,4 @@
# @uncaged/workflow-agent-kit # @uncaged/workflow-util-agent
Agent framework — `createAgent` factory, context builder, frontmatter fast-path, and LLM extract pipeline. Agent framework — `createAgent` factory, context builder, frontmatter fast-path, and LLM extract pipeline.
@@ -13,7 +13,7 @@ Also exports prompt builders, config/storage helpers, and session ID caching for
## Installation ## Installation
```bash ```bash
bun add @uncaged/workflow-agent-kit bun add @uncaged/workflow-util-agent
``` ```
## API ## API
@@ -140,8 +140,8 @@ function loadWorkflowConfig(storageRoot: string): Promise<WorkflowConfig>
## Usage ## Usage
```typescript ```typescript
import { createAgent, buildRolePrompt } from "@uncaged/workflow-agent-kit"; import { createAgent, buildRolePrompt } from "@uncaged/workflow-util-agent";
import type { AgentContext, AgentRunResult } from "@uncaged/workflow-agent-kit"; import type { AgentContext, AgentRunResult } from "@uncaged/workflow-util-agent";
async function run(ctx: AgentContext): Promise<AgentRunResult> { async function run(ctx: AgentContext): Promise<AgentRunResult> {
const prompt = buildRolePrompt(ctx.workflow.roles[ctx.role]!); const prompt = buildRolePrompt(ctx.workflow.roles[ctx.role]!);
@@ -1,5 +1,5 @@
{ {
"name": "@uncaged/workflow-agent-kit", "name": "@uncaged/workflow-util-agent",
"version": "0.5.0", "version": "0.5.0",
"files": [ "files": [
"src", "src",
@@ -35,7 +35,7 @@
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/shazhou-ww/uncaged-workflow.git", "url": "https://github.com/shazhou-ww/uncaged-workflow.git",
"directory": "packages/workflow-agent-kit" "directory": "packages/workflow-util-agent"
}, },
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme", "homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
"bugs": { "bugs": {
@@ -1,64 +0,0 @@
import type { AgentContext } from "@uncaged/workflow-runtime";
/** Max characters of step content to include in the prompt. */
const CONTENT_QUOTA = 16_000;
/** Builds the full agent prompt: system instructions plus summarized thread history. */
export async function buildAgentPrompt(ctx: AgentContext): Promise<string> {
const lines: string[] = [];
lines.push(ctx.currentRole.systemPrompt);
lines.push("");
lines.push("## Task");
lines.push(ctx.start.content);
const { steps } = ctx;
if (steps.length === 0) {
return lines.join("\n");
}
if (steps.length === 1) {
const s = steps[0];
lines.push("");
lines.push(`## Step: ${s.role}`);
lines.push("");
lines.push(`Meta: ${JSON.stringify(s.meta)}`);
appendContent(lines, s.content);
} else {
lines.push("");
lines.push("## Previous Steps");
for (let i = 0; i < steps.length - 1; i++) {
const s = steps[i];
lines.push("");
lines.push(`### Step ${i + 1}: ${s.role}`);
lines.push(`Summary: ${JSON.stringify(s.meta)}`);
}
const last = steps[steps.length - 1];
lines.push("");
lines.push(`## Latest Step: ${last.role}`);
lines.push("");
lines.push(`Meta: ${JSON.stringify(last.meta)}`);
appendContent(lines, last.content);
}
lines.push("");
lines.push("## Tools");
lines.push(
`Use \`uncaged-workflow thread ${ctx.threadId}\` to read full details of any previous step.`,
);
return lines.join("\n");
}
function appendContent(lines: string[], content: string | null | undefined): void {
if (content === null || content === undefined || content.trim() === "") {
return;
}
const truncated =
content.length > CONTENT_QUOTA
? `${content.slice(0, CONTENT_QUOTA)}\n... (truncated)`
: content;
lines.push("");
lines.push("<output>");
lines.push(truncated);
lines.push("</output>");
}
+1 -2
View File
@@ -18,8 +18,7 @@ const dryRun = args.includes("--dry-run");
const publishOrder = [ const publishOrder = [
"workflow-protocol", "workflow-protocol",
"workflow-util", "workflow-util",
"workflow-moderator", "workflow-util-agent",
"workflow-agent-kit",
"workflow-agent-hermes", "workflow-agent-hermes",
"workflow-agent-builtin", "workflow-agent-builtin",
"cli-workflow", "cli-workflow",
+1 -2
View File
@@ -20,8 +20,7 @@
"references": [ "references": [
{ "path": "packages/workflow-util" }, { "path": "packages/workflow-util" },
{ "path": "packages/workflow-protocol" }, { "path": "packages/workflow-protocol" },
{ "path": "packages/workflow-moderator" }, { "path": "packages/workflow-util-agent" },
{ "path": "packages/workflow-agent-kit" },
{ "path": "packages/workflow-agent-hermes" }, { "path": "packages/workflow-agent-hermes" },
{ "path": "packages/workflow-agent-builtin" }, { "path": "packages/workflow-agent-builtin" },
{ "path": "packages/cli-workflow" } { "path": "packages/cli-workflow" }