refactor: simplify committer — minimal prompt, config simplified

- CommitterGitConfig → CommitterConfig { cwd } (remote dropped)
- threadId from ctx.threadId, not config
- Remove summarizeThreadContext — agent uses uncaged-workflow thread CLI
- Prompt doesn't teach git or require structured output
This commit is contained in:
2026-05-06 10:39:09 +00:00
parent 8ce1dd3cca
commit aee71fd2e7
4 changed files with 16 additions and 46 deletions
@@ -8,6 +8,7 @@ import { createCommitterRole } from "../src/committer.js";
function makeCtx(): ThreadContext {
return {
threadId: "01TEST00000000000000000000",
start: {
role: START,
content: "do thing",
@@ -23,17 +23,12 @@ export const committerMetaSchema = z.discriminatedUnion("status", [
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
export type CommitterGitConfig = {
export type CommitterConfig = {
cwd: string;
remote: string;
/** When non-null, prompts mention `uncaged-workflow thread <id>` for extra context. */
threadId: string | null;
};
export const DEFAULT_COMMITTER_GIT_CONFIG: CommitterGitConfig = {
export const DEFAULT_COMMITTER_CONFIG: CommitterConfig = {
cwd: ".",
remote: "origin",
threadId: null,
};
const DRY_RUN_COMMITTED_META: CommitterMeta = {
@@ -46,55 +41,31 @@ function resolveExtractDryRun(extractDryRun: boolean | null): boolean {
return extractDryRun === true;
}
function summarizeThreadContext(ctx: ThreadContext): string {
const lines: string[] = [`Initial prompt:\n${ctx.start.content}`];
for (const step of ctx.steps) {
const snippet = step.content.length > 800 ? `${step.content.slice(0, 800)}` : step.content;
lines.push(`\n### ${step.role}\n${snippet}`);
}
return lines.join("\n");
}
function committerSystemPrompt(ctx: ThreadContext, config: CommitterConfig): string {
return `You are the git committer for this workflow. The project is at \`${config.cwd}\`.
function committerSystemPrompt(ctx: ThreadContext, gitConfig: CommitterGitConfig): string {
const threadLine =
gitConfig.threadId !== null
? `Optional CLI context: run \`uncaged-workflow thread ${gitConfig.threadId}\` if available.\n`
: "";
## Context
return `You are the **git committer** for this workflow. Prior roles planned, implemented, and reviewed the change; your job is to perform git operations in the repository and report the outcome.
Use \`uncaged-workflow thread ${ctx.threadId}\` to read the full workflow thread for context on what was done and why.
## Repository context
## Task
- Working directory (run git commands here): \`${gitConfig.cwd}\`
- Remote name for push: \`${gitConfig.remote}\`
${threadLine}
## Thread context
${summarizeThreadContext(ctx)}
## Your task
1. Inspect the working tree (e.g. \`git status\`). If there is nothing to commit, stop and explain why in your reply.
2. Create a new branch using **conventional** naming (\`feat/<slug>\`, \`fix/<slug>\`, or \`chore/<slug>\` as appropriate).
3. Stage all intended changes, commit with a **single-line conventional commit subject**, and push the branch to \`${gitConfig.remote}\` (e.g. \`git push -u ${gitConfig.remote} <branch>\`).
4. In your reply, state clearly whether the push succeeded, the **exact branch name** used, and the **full commit SHA** from \`git rev-parse HEAD\` (or explain the failure).
Structured extraction will read \`status\`, branch, commit SHA, or error details from your answer.`;
Create a branch, commit the changes, and push. Report whether the push succeeded or failed, the branch name, and the commit SHA.`;
}
/**
* Git committer role: the agent runs git (branch, commit, push); structured extraction yields {@link CommitterMeta}.
* Dry-run skips the agent and returns a stable committed placeholder; unexpected throws yield \`status: "failed"\`.
* Dry-run skips the agent and returns a stable committed placeholder; unexpected throws yield `status: "failed"`.
*/
export function createCommitterRole(
adapter: AgentFn,
extract: { provider: LlmProvider; dryRun: boolean | null; dryRunMeta: CommitterMeta },
gitConfig: CommitterGitConfig = DEFAULT_COMMITTER_GIT_CONFIG,
config: CommitterConfig = DEFAULT_COMMITTER_CONFIG,
): Role<CommitterMeta> {
const inner: Role<CommitterMeta> = createRole({
name: "committer",
schema: committerMetaSchema,
systemPrompt: async (ctx) => committerSystemPrompt(ctx, gitConfig),
systemPrompt: async (ctx) => committerSystemPrompt(ctx, config),
agent: adapter,
extract,
});
@@ -1,7 +1,7 @@
export {
type CommitterGitConfig,
type CommitterConfig,
type CommitterMeta,
committerMetaSchema,
createCommitterRole,
DEFAULT_COMMITTER_GIT_CONFIG,
DEFAULT_COMMITTER_CONFIG,
} from "./committer.js";
@@ -91,10 +91,8 @@ export function createSolveIssueRoles(config: SolveIssueRolesConfig): SolveIssue
const reviewerConfig = {
cwd: config.workdir,
};
const committerGit = {
const committerConfig = {
cwd: config.workdir,
remote: "origin",
threadId: null,
};
const planner: Role<PlannerMeta> = createRole({
@@ -138,7 +136,7 @@ export function createSolveIssueRoles(config: SolveIssueRolesConfig): SolveIssue
dryRun: extract.dryRun,
dryRunMeta: COMMITTER_DRY_RUN_META,
},
committerGit,
committerConfig,
);
return { planner, coder, reviewer, committer };