Files
united-workforce/packages/workflow-template-solve-issue/src/roles.ts
T
xiaoju c7b0beb6be refactor: unify RoleDefinition + WorkflowDefinition with description & schema
- Add RoleDefinition<Meta> = { description, run, schema } to core types
- WorkflowDefinition now carries description and RoleDefinition per role
- Add buildDescriptor() in core to derive WorkflowDescriptor from WorkflowDefinition
- Remove buildDescriptorFromRoles / RoleDescriptorInput from workflow-util-role
- Update solve-issue template, examples, and all tests

小橘 <xiaoju@shazhou.work>
2026-05-06 11:19:49 +00:00

176 lines
4.6 KiB
TypeScript

import type { AgentFn, RoleDefinition } from "@uncaged/workflow";
import { createRole } from "@uncaged/workflow-agent-llm";
import {
type CommitterMeta,
committerMetaSchema,
createCommitterRole,
} from "@uncaged/workflow-role-committer";
import {
createReviewerRole,
type ReviewerMeta,
reviewerMetaSchema,
} from "@uncaged/workflow-role-reviewer";
import type { LlmProvider } from "@uncaged/workflow-util-role";
import * as z from "zod/v4";
const DRY_RUN_PROVIDER: LlmProvider = {
baseUrl: "http://127.0.0.1:9",
apiKey: "",
model: "template-dry-run",
};
const PLANNER_SYSTEM = `You are a **planner** for a software task. Analyze the issue, list relevant files, and produce a clear step-by-step approach.
Focus on: root cause, edge cases, and how the implementation will be verified. Output enough detail for a coding agent to implement without guessing.`;
const CODER_SYSTEM = `You are a **coder**. The previous step produced a plan: read the thread and implement that plan in the repository.
Make focused changes, follow project conventions, and explain what you changed.`;
export const SOLVE_ISSUE_WORKFLOW_DESCRIPTION =
"Plan, implement, review, and commit changes to resolve an issue end-to-end (planner → coder → reviewer → committer).";
export const plannerMetaSchema = z.object({
plan: z.string(),
files: z.array(z.string()),
approach: z.string(),
});
export const coderMetaSchema = z.object({
filesChanged: z.array(z.string()),
summary: z.string(),
});
export type PlannerMeta = z.infer<typeof plannerMetaSchema>;
export type CoderMeta = z.infer<typeof coderMetaSchema>;
const PLANNER_DRY_RUN_META: PlannerMeta = {
plan: "",
files: [],
approach: "",
};
const CODER_DRY_RUN_META: CoderMeta = {
filesChanged: [],
summary: "",
};
const REVIEWER_DRY_RUN_META: ReviewerMeta = {
status: "approved",
};
const COMMITTER_DRY_RUN_META: CommitterMeta = {
status: "committed",
branch: "dry-run/placeholder",
commitSha: "0000000",
};
export type SolveIssueMeta = {
planner: PlannerMeta;
coder: CoderMeta;
reviewer: ReviewerMeta;
committer: CommitterMeta;
};
/** Wiring for workflow-role LLM structured extraction. Use `null` for stub extract (dry-run meta from built-in placeholders). */
export type SolveIssueRolesConfig = {
agent: AgentFn;
workdir: string;
extract: { provider: LlmProvider; dryRun: boolean | null } | null;
};
function resolveExtract(config: SolveIssueRolesConfig): {
provider: LlmProvider;
dryRun: boolean | null;
} {
if (config.extract === null) {
return { provider: DRY_RUN_PROVIDER, dryRun: true };
}
return config.extract;
}
export type SolveIssueRoles = {
planner: RoleDefinition<PlannerMeta>;
coder: RoleDefinition<CoderMeta>;
reviewer: RoleDefinition<ReviewerMeta>;
committer: RoleDefinition<CommitterMeta>;
};
export function createSolveIssueRoles(config: SolveIssueRolesConfig): SolveIssueRoles {
const extract = resolveExtract(config);
const reviewerConfig = {
cwd: config.workdir,
};
const committerConfig = {
cwd: config.workdir,
};
const plannerRun = createRole({
name: "planner",
schema: plannerMetaSchema,
systemPrompt: PLANNER_SYSTEM,
agent: config.agent,
extract: {
provider: extract.provider,
dryRun: extract.dryRun,
dryRunMeta: PLANNER_DRY_RUN_META,
},
});
const coderRun = createRole({
name: "coder",
schema: coderMetaSchema,
systemPrompt: CODER_SYSTEM,
agent: config.agent,
extract: {
provider: extract.provider,
dryRun: extract.dryRun,
dryRunMeta: CODER_DRY_RUN_META,
},
});
const reviewerRun = createReviewerRole(
config.agent,
{
provider: extract.provider,
dryRun: extract.dryRun,
dryRunMeta: REVIEWER_DRY_RUN_META,
},
reviewerConfig,
);
const committerRun = createCommitterRole(
config.agent,
{
provider: extract.provider,
dryRun: extract.dryRun,
dryRunMeta: COMMITTER_DRY_RUN_META,
},
committerConfig,
);
return {
planner: {
description: "Analyzes the issue and proposes plan, files, and approach.",
run: plannerRun,
schema: plannerMetaSchema,
},
coder: {
description: "Implements the planner output and summarizes touched files.",
run: coderRun,
schema: coderMetaSchema,
},
reviewer: {
description: "Runs git diff checks and sets approved when the change is ready.",
run: reviewerRun,
schema: reviewerMetaSchema,
},
committer: {
description: "Creates branch, commits, and pushes when review passes.",
run: committerRun,
schema: committerMetaSchema,
},
};
}