Compare commits
4 Commits
a506e5b36b
...
ac47daa42b
| Author | SHA1 | Date | |
|---|---|---|---|
| ac47daa42b | |||
| a609dc2486 | |||
| eaddd88109 | |||
| 1683e41b05 |
@ -1,5 +1,4 @@
|
|||||||
import type { Role, RoleResult, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, StartStep } from "@uncaged/nerve-core";
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -62,15 +61,18 @@ or
|
|||||||
\`\`\``;
|
\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildWorkspaceCommitterRole({
|
export function createWorkspaceCommitterRole(
|
||||||
extract,
|
adapter: AgentFn,
|
||||||
nerveRoot,
|
{
|
||||||
workflowName,
|
extract,
|
||||||
conventionalCommitScopeHint,
|
nerveRoot,
|
||||||
branchCheckoutExample,
|
workflowName,
|
||||||
}: BuildWorkspaceCommitterDeps): Role<CommitterMeta> {
|
conventionalCommitScopeHint,
|
||||||
|
branchCheckoutExample,
|
||||||
|
}: BuildWorkspaceCommitterDeps,
|
||||||
|
): Role<CommitterMeta> {
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
hermesAdapter,
|
adapter,
|
||||||
async (start: StartStep) =>
|
async (start: StartStep) =>
|
||||||
workspaceCommitterPrompt({
|
workspaceCommitterPrompt({
|
||||||
threadId: start.meta.threadId,
|
threadId: start.meta.threadId,
|
||||||
|
|||||||
@ -1,75 +1,34 @@
|
|||||||
import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core";
|
import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core";
|
||||||
import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole } from "@uncaged/nerve-workflow-utils";
|
|
||||||
|
|
||||||
import {
|
|
||||||
coderMetaSchema,
|
|
||||||
coderPrompt,
|
|
||||||
} from "./roles/coder.js";
|
|
||||||
import {
|
|
||||||
buildWorkspaceCommitterRole,
|
|
||||||
} from "./roles/committer.js";
|
|
||||||
import {
|
|
||||||
plannerMetaSchema,
|
|
||||||
plannerPrompt,
|
|
||||||
} from "./roles/planner.js";
|
|
||||||
import {
|
|
||||||
reviewerMetaSchema,
|
|
||||||
reviewerPrompt,
|
|
||||||
} from "./roles/reviewer.js";
|
|
||||||
import {
|
|
||||||
testerMetaSchema,
|
|
||||||
testerPrompt,
|
|
||||||
} from "./roles/tester.js";
|
|
||||||
import { moderator } from "./moderator.js";
|
import { moderator } from "./moderator.js";
|
||||||
import type { SenseMeta } from "./moderator.js";
|
import type { SenseMeta } from "./moderator.js";
|
||||||
|
import { createCoderRole } from "./roles/coder.js";
|
||||||
|
import { createWorkspaceCommitterRole } from "./roles/committer.js";
|
||||||
|
import { createPlannerRole } from "./roles/planner.js";
|
||||||
|
import { createReviewerRole } from "./roles/reviewer.js";
|
||||||
|
import { createTesterRole } from "./roles/tester.js";
|
||||||
|
|
||||||
export type BuildDevelopSenseDeps = {
|
export type CreateDevelopSenseDeps = {
|
||||||
|
defaultAdapter: AgentFn;
|
||||||
|
adapters?: Partial<Record<keyof SenseMeta, AgentFn>>;
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CURSOR_TIMEOUT_MS = 300_000;
|
export function createDevelopSenseWorkflow({
|
||||||
|
defaultAdapter,
|
||||||
export function buildDevelopSenseWorkflow({
|
adapters,
|
||||||
extract,
|
extract,
|
||||||
cwd,
|
cwd,
|
||||||
}: BuildDevelopSenseDeps): WorkflowDefinition<SenseMeta> {
|
}: CreateDevelopSenseDeps): WorkflowDefinition<SenseMeta> {
|
||||||
|
const a = (role: keyof SenseMeta) => adapters?.[role] ?? defaultAdapter;
|
||||||
const roles = {
|
const roles = {
|
||||||
planner: createRole(
|
planner: createPlannerRole(a('planner'), extract),
|
||||||
createCursorAdapter({
|
coder: createCoderRole(a('coder'), extract),
|
||||||
type: "cursor",
|
reviewer: createReviewerRole(a('reviewer'), extract, cwd),
|
||||||
mode: "ask",
|
tester: createTesterRole(a('tester'), extract, cwd),
|
||||||
model: "auto",
|
committer: createWorkspaceCommitterRole(a('committer'), {
|
||||||
timeout: CURSOR_TIMEOUT_MS,
|
|
||||||
}),
|
|
||||||
async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }),
|
|
||||||
plannerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
coder: createRole(
|
|
||||||
cursorAdapter,
|
|
||||||
async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }),
|
|
||||||
coderMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
reviewer: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
reviewerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }),
|
|
||||||
reviewerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
tester: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
testerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }),
|
|
||||||
testerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
committer: buildWorkspaceCommitterRole({
|
|
||||||
extract,
|
extract,
|
||||||
nerveRoot: cwd,
|
nerveRoot: cwd,
|
||||||
workflowName: "develop-sense",
|
workflowName: "develop-sense",
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { buildDevelopSenseWorkflow } from "./build.js";
|
import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
||||||
|
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
||||||
|
import { createDevelopSenseWorkflow } from "./build.js";
|
||||||
|
|
||||||
const HOME = process.env.HOME ?? "/home/azureuser";
|
const HOME = process.env.HOME ?? "/home/azureuser";
|
||||||
const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
||||||
@ -11,7 +13,19 @@ if (!apiKey || !baseUrl) {
|
|||||||
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL");
|
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflow = buildDevelopSenseWorkflow({
|
const CURSOR_TIMEOUT_MS = 300_000;
|
||||||
|
|
||||||
|
const workflow = createDevelopSenseWorkflow({
|
||||||
|
defaultAdapter: hermesAdapter,
|
||||||
|
adapters: {
|
||||||
|
planner: createCursorAdapter({
|
||||||
|
type: "cursor",
|
||||||
|
mode: "ask",
|
||||||
|
model: "auto",
|
||||||
|
timeout: CURSOR_TIMEOUT_MS,
|
||||||
|
}),
|
||||||
|
coder: cursorAdapter,
|
||||||
|
},
|
||||||
extract: { provider: { apiKey, baseUrl, model } },
|
extract: { provider: { apiKey, baseUrl, model } },
|
||||||
cwd: NERVE_ROOT,
|
cwd: NERVE_ROOT,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const coderMetaSchema = z.object({
|
export const coderMetaSchema = z.object({
|
||||||
@ -36,3 +39,12 @@ Return \`done: true\` ONLY when ALL of the following are true:
|
|||||||
|
|
||||||
Return \`done: false\` if you made progress but there is still work to do.`;
|
Return \`done: false\` if you made progress but there is still work to do.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createCoderRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<CoderMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }),
|
||||||
|
coderMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export {
|
export {
|
||||||
buildWorkspaceCommitterRole,
|
createWorkspaceCommitterRole,
|
||||||
committerMetaSchema,
|
committerMetaSchema,
|
||||||
type BuildWorkspaceCommitterDeps,
|
type BuildWorkspaceCommitterDeps,
|
||||||
type CommitterMeta,
|
type CommitterMeta,
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const plannerMetaSchema = z.object({
|
export const plannerMetaSchema = z.object({
|
||||||
@ -22,3 +25,12 @@ Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdow
|
|||||||
|
|
||||||
Output ONLY the plan. Be precise and implementation-ready.`;
|
Output ONLY the plan. Be precise and implementation-ready.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createPlannerRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<PlannerMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }),
|
||||||
|
plannerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const reviewerMetaSchema = z.object({
|
export const reviewerMetaSchema = z.object({
|
||||||
@ -43,3 +46,17 @@ or
|
|||||||
{ "approved": false }
|
{ "approved": false }
|
||||||
\`\`\``;
|
\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createReviewerRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
extract: LlmExtractorConfig,
|
||||||
|
nerveRoot: string,
|
||||||
|
): Role<ReviewerMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
|
reviewerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const testerMetaSchema = z.object({
|
export const testerMetaSchema = z.object({
|
||||||
@ -39,3 +42,17 @@ If any step fails, include the relevant error output.
|
|||||||
|
|
||||||
Output a clear summary: what you checked, what passed, what failed, and why.`;
|
Output a clear summary: what you checked, what passed, what failed, and why.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTesterRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
extract: LlmExtractorConfig,
|
||||||
|
nerveRoot: string,
|
||||||
|
): Role<TesterMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
testerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
|
testerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,75 +1,34 @@
|
|||||||
import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core";
|
import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core";
|
||||||
import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole } from "@uncaged/nerve-workflow-utils";
|
|
||||||
|
|
||||||
import {
|
|
||||||
coderMetaSchema,
|
|
||||||
coderPrompt,
|
|
||||||
} from "./roles/coder.js";
|
|
||||||
import {
|
|
||||||
buildWorkspaceCommitterRole,
|
|
||||||
} from "./roles/committer.js";
|
|
||||||
import {
|
|
||||||
plannerMetaSchema,
|
|
||||||
plannerPrompt,
|
|
||||||
} from "./roles/planner.js";
|
|
||||||
import {
|
|
||||||
reviewerMetaSchema,
|
|
||||||
reviewerPrompt,
|
|
||||||
} from "./roles/reviewer.js";
|
|
||||||
import {
|
|
||||||
testerMetaSchema,
|
|
||||||
testerPrompt,
|
|
||||||
} from "./roles/tester.js";
|
|
||||||
import { moderator } from "./moderator.js";
|
import { moderator } from "./moderator.js";
|
||||||
import type { WorkflowMeta } from "./moderator.js";
|
import type { WorkflowMeta } from "./moderator.js";
|
||||||
|
import { createCoderRole } from "./roles/coder.js";
|
||||||
|
import { createWorkspaceCommitterRole } from "./roles/committer.js";
|
||||||
|
import { createPlannerRole } from "./roles/planner.js";
|
||||||
|
import { createReviewerRole } from "./roles/reviewer.js";
|
||||||
|
import { createTesterRole } from "./roles/tester.js";
|
||||||
|
|
||||||
export type BuildDevelopWorkflowDeps = {
|
export type CreateDevelopWorkflowDeps = {
|
||||||
|
defaultAdapter: AgentFn;
|
||||||
|
adapters?: Partial<Record<keyof WorkflowMeta, AgentFn>>;
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CURSOR_TIMEOUT_MS = 300_000;
|
export function createDevelopWorkflowWorkflow({
|
||||||
|
defaultAdapter,
|
||||||
export function buildDevelopWorkflow({
|
adapters,
|
||||||
extract,
|
extract,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
}: BuildDevelopWorkflowDeps): WorkflowDefinition<WorkflowMeta> {
|
}: CreateDevelopWorkflowDeps): WorkflowDefinition<WorkflowMeta> {
|
||||||
|
const a = (role: keyof WorkflowMeta) => adapters?.[role] ?? defaultAdapter;
|
||||||
const roles = {
|
const roles = {
|
||||||
planner: createRole(
|
planner: createPlannerRole(a('planner'), extract),
|
||||||
createCursorAdapter({
|
coder: createCoderRole(a('coder'), extract),
|
||||||
type: "cursor",
|
reviewer: createReviewerRole(a('reviewer'), extract, nerveRoot),
|
||||||
mode: "ask",
|
tester: createTesterRole(a('tester'), extract, nerveRoot),
|
||||||
model: "auto",
|
committer: createWorkspaceCommitterRole(a('committer'), {
|
||||||
timeout: CURSOR_TIMEOUT_MS,
|
|
||||||
}),
|
|
||||||
async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }),
|
|
||||||
plannerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
coder: createRole(
|
|
||||||
cursorAdapter,
|
|
||||||
async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }),
|
|
||||||
coderMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
reviewer: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
|
||||||
reviewerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
tester: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
testerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
|
||||||
testerMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
committer: buildWorkspaceCommitterRole({
|
|
||||||
extract,
|
extract,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
workflowName: "develop-workflow",
|
workflowName: "develop-workflow",
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { buildDevelopWorkflow } from "./build.js";
|
import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
||||||
|
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
||||||
|
import { createDevelopWorkflowWorkflow } from "./build.js";
|
||||||
|
|
||||||
const HOME = process.env.HOME ?? "/home/azureuser";
|
const HOME = process.env.HOME ?? "/home/azureuser";
|
||||||
const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
||||||
@ -12,7 +14,19 @@ if (!apiKey || !baseUrl) {
|
|||||||
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL");
|
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflow = buildDevelopWorkflow({
|
const CURSOR_TIMEOUT_MS = 300_000;
|
||||||
|
|
||||||
|
const workflow = createDevelopWorkflowWorkflow({
|
||||||
|
defaultAdapter: hermesAdapter,
|
||||||
|
adapters: {
|
||||||
|
planner: createCursorAdapter({
|
||||||
|
type: "cursor",
|
||||||
|
mode: "ask",
|
||||||
|
model: "auto",
|
||||||
|
timeout: CURSOR_TIMEOUT_MS,
|
||||||
|
}),
|
||||||
|
coder: cursorAdapter,
|
||||||
|
},
|
||||||
extract: { provider: { apiKey, baseUrl, model } },
|
extract: { provider: { apiKey, baseUrl, model } },
|
||||||
nerveRoot: NERVE_ROOT,
|
nerveRoot: NERVE_ROOT,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const coderMetaSchema = z.object({
|
export const coderMetaSchema = z.object({
|
||||||
@ -55,3 +58,12 @@ Return \`done: true\` ONLY when ALL of the following are true:
|
|||||||
|
|
||||||
Return \`done: false\` if you made progress but there is still work to do, or if build/lint has errors you plan to fix in the next iteration.`;
|
Return \`done: false\` if you made progress but there is still work to do, or if build/lint has errors you plan to fix in the next iteration.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createCoderRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<CoderMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }),
|
||||||
|
coderMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export {
|
export {
|
||||||
buildWorkspaceCommitterRole,
|
createWorkspaceCommitterRole,
|
||||||
committerMetaSchema,
|
committerMetaSchema,
|
||||||
type BuildWorkspaceCommitterDeps,
|
type BuildWorkspaceCommitterDeps,
|
||||||
type CommitterMeta,
|
type CommitterMeta,
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const plannerMetaSchema = z.object({
|
export const plannerMetaSchema = z.object({
|
||||||
@ -51,3 +54,12 @@ or
|
|||||||
{ "ready": false }
|
{ "ready": false }
|
||||||
\`\`\``;
|
\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createPlannerRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<PlannerMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }),
|
||||||
|
plannerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const reviewerMetaSchema = z.object({
|
export const reviewerMetaSchema = z.object({
|
||||||
@ -43,3 +46,17 @@ or
|
|||||||
{ "approved": false }
|
{ "approved": false }
|
||||||
\`\`\``;
|
\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createReviewerRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
extract: LlmExtractorConfig,
|
||||||
|
nerveRoot: string,
|
||||||
|
): Role<ReviewerMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
|
reviewerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const testerMetaSchema = z.object({
|
export const testerMetaSchema = z.object({
|
||||||
@ -40,3 +43,17 @@ If any step fails, include the relevant error output.
|
|||||||
|
|
||||||
Output a clear summary: what you checked, what passed, what failed, and why.`;
|
Output a clear summary: what you checked, what passed, what failed, and why.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTesterRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
extract: LlmExtractorConfig,
|
||||||
|
nerveRoot: string,
|
||||||
|
): Role<TesterMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
testerPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
|
testerMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,64 +1,42 @@
|
|||||||
import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core";
|
import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core";
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole } from "@uncaged/nerve-workflow-utils";
|
|
||||||
|
|
||||||
import { moderator } from "./moderator.js";
|
import { moderator } from "./moderator.js";
|
||||||
import type { WorkflowMeta } from "./moderator.js";
|
import type { WorkflowMeta } from "./moderator.js";
|
||||||
import { buildCommitterRole } from "./roles/committer/index.js";
|
import { createCommitterRole } from "./roles/committer/index.js";
|
||||||
import { buildImplementRole } from "./roles/implement/index.js";
|
import { createImplementRole } from "./roles/implement/index.js";
|
||||||
import { buildPlanRole } from "./roles/plan/index.js";
|
import { createPlanRole } from "./roles/plan/index.js";
|
||||||
import { prepareMetaSchema } from "./roles/prepare/index.js";
|
import { createPrepareRole } from "./roles/prepare/index.js";
|
||||||
import { preparePrompt } from "./roles/prepare/prompt.js";
|
import { createPublishRole } from "./roles/publish/index.js";
|
||||||
import { buildPublishRole } from "./roles/publish/index.js";
|
import { createReadIssueRole } from "./roles/read-issue/index.js";
|
||||||
import { readIssueMetaSchema } from "./roles/read-issue/index.js";
|
import { createReviewRole } from "./roles/review/index.js";
|
||||||
import { readIssuePrompt } from "./roles/read-issue/prompt.js";
|
import { createTestRole } from "./roles/test/index.js";
|
||||||
import { reviewMetaSchema } from "./roles/review/index.js";
|
|
||||||
import { reviewPrompt } from "./roles/review/prompt.js";
|
|
||||||
import { testMetaSchema } from "./roles/test/index.js";
|
|
||||||
import { testPrompt } from "./roles/test/prompt.js";
|
|
||||||
|
|
||||||
export type BuildSolveIssueDeps = {
|
export type CreateSolveIssueDeps = {
|
||||||
|
defaultAdapter: AgentFn;
|
||||||
|
adapters?: Partial<Record<keyof WorkflowMeta, AgentFn>>;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildSolveIssue({
|
export function createSolveIssueWorkflow({
|
||||||
|
defaultAdapter,
|
||||||
|
adapters,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
extract,
|
extract,
|
||||||
}: BuildSolveIssueDeps): WorkflowDefinition<WorkflowMeta> {
|
}: CreateSolveIssueDeps): WorkflowDefinition<WorkflowMeta> {
|
||||||
|
const a = (role: keyof WorkflowMeta) => adapters?.[role] ?? defaultAdapter;
|
||||||
return {
|
return {
|
||||||
name: "solve-issue",
|
name: "solve-issue",
|
||||||
roles: {
|
roles: {
|
||||||
"read-issue": createRole(
|
"read-issue": createReadIssueRole(a("read-issue"), extract),
|
||||||
hermesAdapter,
|
prepare: createPrepareRole(a("prepare"), extract),
|
||||||
async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }),
|
plan: createPlanRole(a("plan"), { extract, nerveRoot }),
|
||||||
readIssueMetaSchema,
|
implement: createImplementRole(a("implement"), { extract, nerveRoot }),
|
||||||
extract,
|
committer: createCommitterRole(a("committer"), { extract, nerveRoot }),
|
||||||
),
|
review: createReviewRole(a("review"), extract, nerveRoot),
|
||||||
prepare: createRole(
|
test: createTestRole(a("test"), extract),
|
||||||
hermesAdapter,
|
publish: createPublishRole(a("publish"), { extract, nerveRoot }),
|
||||||
async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }),
|
|
||||||
prepareMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
plan: buildPlanRole({ extract, nerveRoot }),
|
|
||||||
implement: buildImplementRole({ extract, nerveRoot }),
|
|
||||||
committer: buildCommitterRole({ extract, nerveRoot }),
|
|
||||||
review: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
reviewPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
|
||||||
reviewMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
test: createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }),
|
|
||||||
testMetaSchema,
|
|
||||||
extract,
|
|
||||||
),
|
|
||||||
publish: buildPublishRole({ extract, nerveRoot }),
|
|
||||||
},
|
},
|
||||||
moderator,
|
moderator,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { buildSolveIssue } from "./build.js";
|
import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
||||||
|
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
||||||
|
import { createSolveIssueWorkflow } from "./build.js";
|
||||||
import { resolveDashScopeProvider } from "./lib/provider.js";
|
import { resolveDashScopeProvider } from "./lib/provider.js";
|
||||||
|
|
||||||
const HOME = process.env.HOME ?? "/home/azureuser";
|
const HOME = process.env.HOME ?? "/home/azureuser";
|
||||||
@ -11,6 +13,25 @@ if (provider === null) {
|
|||||||
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL (or cfg get equivalents)");
|
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL (or cfg get equivalents)");
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflow = buildSolveIssue({ nerveRoot: NERVE_ROOT, extract: { provider } });
|
const CURSOR_TIMEOUT_MS = 300_000;
|
||||||
|
|
||||||
|
const workflow = createSolveIssueWorkflow({
|
||||||
|
defaultAdapter: hermesAdapter,
|
||||||
|
adapters: {
|
||||||
|
plan: createCursorAdapter({
|
||||||
|
type: "cursor",
|
||||||
|
mode: "ask",
|
||||||
|
model: "auto",
|
||||||
|
timeout: CURSOR_TIMEOUT_MS,
|
||||||
|
}),
|
||||||
|
implement: createCursorAdapter({
|
||||||
|
type: "cursor",
|
||||||
|
model: "auto",
|
||||||
|
timeout: CURSOR_TIMEOUT_MS,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
nerveRoot: NERVE_ROOT,
|
||||||
|
extract: { provider },
|
||||||
|
});
|
||||||
|
|
||||||
export default workflow;
|
export default workflow;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -14,14 +13,17 @@ export const committerMetaSchema = z.object({
|
|||||||
});
|
});
|
||||||
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
|
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
|
||||||
|
|
||||||
export type BuildCommitterDeps = {
|
export type CreateCommitterRoleDeps = {
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildCommitterRole({ extract, nerveRoot }: BuildCommitterDeps): Role<CommitterMeta> {
|
export function createCommitterRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
{ extract, nerveRoot }: CreateCommitterRoleDeps,
|
||||||
|
): Role<CommitterMeta> {
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
hermesAdapter,
|
adapter,
|
||||||
async (start: StartStep) =>
|
async (start: StartStep) =>
|
||||||
committerPrompt({
|
committerPrompt({
|
||||||
threadId: start.meta.threadId,
|
threadId: start.meta.threadId,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole } from "@uncaged/nerve-workflow-utils";
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -12,17 +11,15 @@ export const implementMetaSchema = z.object({
|
|||||||
});
|
});
|
||||||
export type ImplementMeta = z.infer<typeof implementMetaSchema>;
|
export type ImplementMeta = z.infer<typeof implementMetaSchema>;
|
||||||
|
|
||||||
export type BuildImplementDeps = {
|
export type CreateImplementRoleDeps = {
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CURSOR_TIMEOUT_MS = 300_000;
|
export function createImplementRole(
|
||||||
|
adapter: AgentFn,
|
||||||
export function buildImplementRole({
|
{ extract, nerveRoot }: CreateImplementRoleDeps,
|
||||||
extract,
|
): Role<ImplementMeta> {
|
||||||
nerveRoot,
|
|
||||||
}: BuildImplementDeps): Role<ImplementMeta> {
|
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<ImplementMeta>> => {
|
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<ImplementMeta>> => {
|
||||||
const cwd = resolveRepoCwd(messages);
|
const cwd = resolveRepoCwd(messages);
|
||||||
if (cwd === null) {
|
if (cwd === null) {
|
||||||
@ -33,11 +30,7 @@ export function buildImplementRole({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
createCursorAdapter({
|
adapter,
|
||||||
type: "cursor",
|
|
||||||
model: "auto",
|
|
||||||
timeout: CURSOR_TIMEOUT_MS,
|
|
||||||
}),
|
|
||||||
async (innerStart: StartStep) =>
|
async (innerStart: StartStep) =>
|
||||||
buildImplementPrompt({
|
buildImplementPrompt({
|
||||||
threadId: innerStart.meta.threadId,
|
threadId: innerStart.meta.threadId,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole } from "@uncaged/nerve-workflow-utils";
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -12,14 +11,15 @@ export const planMetaSchema = z.object({
|
|||||||
});
|
});
|
||||||
export type PlanMeta = z.infer<typeof planMetaSchema>;
|
export type PlanMeta = z.infer<typeof planMetaSchema>;
|
||||||
|
|
||||||
export type BuildPlanDeps = {
|
export type CreatePlanRoleDeps = {
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CURSOR_TIMEOUT_MS = 300_000;
|
export function createPlanRole(
|
||||||
|
adapter: AgentFn,
|
||||||
export function buildPlanRole({ extract, nerveRoot }: BuildPlanDeps): Role<PlanMeta> {
|
{ extract, nerveRoot }: CreatePlanRoleDeps,
|
||||||
|
): Role<PlanMeta> {
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<PlanMeta>> => {
|
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<PlanMeta>> => {
|
||||||
const cwd = resolveRepoCwd(messages);
|
const cwd = resolveRepoCwd(messages);
|
||||||
if (cwd === null) {
|
if (cwd === null) {
|
||||||
@ -30,12 +30,7 @@ export function buildPlanRole({ extract, nerveRoot }: BuildPlanDeps): Role<PlanM
|
|||||||
}
|
}
|
||||||
|
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
createCursorAdapter({
|
adapter,
|
||||||
type: "cursor",
|
|
||||||
mode: "ask",
|
|
||||||
model: "auto",
|
|
||||||
timeout: CURSOR_TIMEOUT_MS,
|
|
||||||
}),
|
|
||||||
async (innerStart: StartStep) =>
|
async (innerStart: StartStep) =>
|
||||||
buildPlanPrompt({
|
buildPlanPrompt({
|
||||||
threadId: innerStart.meta.threadId,
|
threadId: innerStart.meta.threadId,
|
||||||
|
|||||||
@ -1,6 +1,20 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { preparePrompt } from "./prompt.js";
|
||||||
|
|
||||||
export const prepareMetaSchema = z.object({
|
export const prepareMetaSchema = z.object({
|
||||||
ready: z.boolean().describe("true if repo is ready and baseline build ok"),
|
ready: z.boolean().describe("true if repo is ready and baseline build ok"),
|
||||||
});
|
});
|
||||||
export type PrepareMeta = z.infer<typeof prepareMetaSchema>;
|
export type PrepareMeta = z.infer<typeof prepareMetaSchema>;
|
||||||
|
|
||||||
|
export function createPrepareRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<PrepareMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }),
|
||||||
|
prepareMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { mkdirSync, writeFileSync } from "node:fs";
|
import { mkdirSync, writeFileSync } from "node:fs";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -13,7 +12,7 @@ export const publishMetaSchema = z.object({
|
|||||||
});
|
});
|
||||||
export type PublishMeta = z.infer<typeof publishMetaSchema>;
|
export type PublishMeta = z.infer<typeof publishMetaSchema>;
|
||||||
|
|
||||||
export type BuildPublishDeps = {
|
export type CreatePublishRoleDeps = {
|
||||||
extract: LlmExtractorConfig;
|
extract: LlmExtractorConfig;
|
||||||
nerveRoot: string;
|
nerveRoot: string;
|
||||||
};
|
};
|
||||||
@ -22,9 +21,12 @@ function logPath(nerveRoot: string): string {
|
|||||||
return join(nerveRoot, "logs", `solve-issue-publish-${Date.now()}.log`);
|
return join(nerveRoot, "logs", `solve-issue-publish-${Date.now()}.log`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildPublishRole({ extract, nerveRoot }: BuildPublishDeps): Role<PublishMeta> {
|
export function createPublishRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
{ extract, nerveRoot }: CreatePublishRoleDeps,
|
||||||
|
): Role<PublishMeta> {
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
hermesAdapter,
|
adapter,
|
||||||
async (start: StartStep) =>
|
async (start: StartStep) =>
|
||||||
buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
publishMetaSchema,
|
publishMetaSchema,
|
||||||
|
|||||||
@ -1,6 +1,20 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { readIssuePrompt } from "./prompt.js";
|
||||||
|
|
||||||
export const readIssueMetaSchema = z.object({
|
export const readIssueMetaSchema = z.object({
|
||||||
ready: z.boolean().describe("true if issue content was fetched and markers are present"),
|
ready: z.boolean().describe("true if issue content was fetched and markers are present"),
|
||||||
});
|
});
|
||||||
export type ReadIssueMeta = z.infer<typeof readIssueMetaSchema>;
|
export type ReadIssueMeta = z.infer<typeof readIssueMetaSchema>;
|
||||||
|
|
||||||
|
export function createReadIssueRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<ReadIssueMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }),
|
||||||
|
readIssueMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,25 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { reviewPrompt } from "./prompt.js";
|
||||||
|
|
||||||
export const reviewMetaSchema = z.object({
|
export const reviewMetaSchema = z.object({
|
||||||
approved: z.boolean().describe("true if diff is clean and ready for tests"),
|
approved: z.boolean().describe("true if diff is clean and ready for tests"),
|
||||||
});
|
});
|
||||||
export type ReviewMeta = z.infer<typeof reviewMetaSchema>;
|
export type ReviewMeta = z.infer<typeof reviewMetaSchema>;
|
||||||
|
|
||||||
|
export function createReviewRole(
|
||||||
|
adapter: AgentFn,
|
||||||
|
extract: LlmExtractorConfig,
|
||||||
|
nerveRoot: string,
|
||||||
|
): Role<ReviewMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
reviewPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
||||||
|
reviewMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,20 @@
|
|||||||
|
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { testPrompt } from "./prompt.js";
|
||||||
|
|
||||||
export const testMetaSchema = z.object({
|
export const testMetaSchema = z.object({
|
||||||
passed: z.boolean().describe("true if all test commands passed"),
|
passed: z.boolean().describe("true if all test commands passed"),
|
||||||
});
|
});
|
||||||
export type TestMeta = z.infer<typeof testMetaSchema>;
|
export type TestMeta = z.infer<typeof testMetaSchema>;
|
||||||
|
|
||||||
|
export function createTestRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<TestMeta> {
|
||||||
|
return createRole(
|
||||||
|
adapter,
|
||||||
|
async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }),
|
||||||
|
testMetaSchema,
|
||||||
|
extract,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user