refactor: migrate all workflows to RFC-005 ThreadContext signatures
- Role: (start, messages) → (ctx: ThreadContext) - AgentFn prompt callbacks: (start) → (ctx) - ModeratorContext → ThreadContext - 13 files updated across knowledge-extraction and solve-issue workflows 小橘 <xiaoju@shazhou.work>
This commit is contained in:
parent
1c512435de
commit
e4fd5d6ba4
@ -20,7 +20,7 @@ const workflow = createKnowledgeExtractionWorkflow({
|
|||||||
adapters: {
|
adapters: {
|
||||||
explorer: createCursorAdapter({
|
explorer: createCursorAdapter({
|
||||||
type: "cursor",
|
type: "cursor",
|
||||||
model: "auto",
|
model: "claude-sonnet-4",
|
||||||
timeout: CURSOR_TIMEOUT_MS,
|
timeout: CURSOR_TIMEOUT_MS,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,7 +2,20 @@ import type { StartStep } from "@uncaged/nerve-core";
|
|||||||
|
|
||||||
type StartMetaWithWorkdir = StartStep["meta"] & { workdir?: string | null };
|
type StartMetaWithWorkdir = StartStep["meta"] & { workdir?: string | null };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the target repo working directory.
|
||||||
|
* Priority: start.meta.workdir → prompt second line (if absolute path) → cwd.
|
||||||
|
*/
|
||||||
export function resolveWorkdir(start: StartStep): string {
|
export function resolveWorkdir(start: StartStep): string {
|
||||||
const m = start.meta as StartMetaWithWorkdir;
|
const m = start.meta as StartMetaWithWorkdir;
|
||||||
return m.workdir ?? process.cwd();
|
if (m.workdir) return m.workdir;
|
||||||
|
|
||||||
|
// Allow prompt to carry workdir on the second line: "seed\n/abs/path"
|
||||||
|
const lines = start.content.split(/\r?\n/);
|
||||||
|
if (lines.length >= 2) {
|
||||||
|
const candidate = lines[1]!.trim();
|
||||||
|
if (candidate.startsWith("/")) return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.cwd();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { END } from "@uncaged/nerve-core";
|
import { END } from "@uncaged/nerve-core";
|
||||||
import type { Moderator, ModeratorContext } from "@uncaged/nerve-core";
|
import type { Moderator, ThreadContext } from "@uncaged/nerve-core";
|
||||||
|
|
||||||
import type { AnswererMeta } from "./roles/answerer.js";
|
import type { AnswererMeta } from "./roles/answerer.js";
|
||||||
import type { ExplorerMeta } from "./roles/explorer.js";
|
import type { ExplorerMeta } from "./roles/explorer.js";
|
||||||
@ -11,7 +11,7 @@ export type WorkflowMeta = {
|
|||||||
explorer: ExplorerMeta;
|
explorer: ExplorerMeta;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Steps = ModeratorContext<WorkflowMeta>["steps"];
|
type Steps = ThreadContext<WorkflowMeta>["steps"];
|
||||||
|
|
||||||
function lastQuestionerRemaining(steps: Steps): QuestionerMeta | undefined {
|
function lastQuestionerRemaining(steps: Steps): QuestionerMeta | undefined {
|
||||||
for (let i = steps.length - 1; i >= 0; i--) {
|
for (let i = steps.length - 1; i >= 0; i--) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { Role, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { Role, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { llmExtract, nerveCommandEnv, spawnSafe } from "@uncaged/nerve-workflow-utils";
|
import { llmExtract, nerveCommandEnv, spawnSafe } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -37,8 +37,9 @@ function lastQuestionerMeta(messages: WorkflowMessage[]): QuestionerMeta | undef
|
|||||||
export function createAnswererRole(deps: CreateAnswererRoleDeps): Role<AnswererMeta> {
|
export function createAnswererRole(deps: CreateAnswererRoleDeps): Role<AnswererMeta> {
|
||||||
const { extract } = deps;
|
const { extract } = deps;
|
||||||
|
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]) => {
|
return async (ctx: ThreadContext) => {
|
||||||
const cwd = resolveWorkdir(start);
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
||||||
|
const cwd = resolveWorkdir(ctx.start);
|
||||||
const qm = lastQuestionerMeta(messages);
|
const qm = lastQuestionerMeta(messages);
|
||||||
if (!qm || qm.questions.length === 0) {
|
if (!qm || qm.questions.length === 0) {
|
||||||
return {
|
return {
|
||||||
@ -49,7 +50,7 @@ export function createAnswererRole(deps: CreateAnswererRoleDeps): Role<AnswererM
|
|||||||
|
|
||||||
const blocks: string[] = [];
|
const blocks: string[] = [];
|
||||||
for (const q of qm.questions) {
|
for (const q of qm.questions) {
|
||||||
if (start.meta.dryRun) {
|
if ((ctx.start.meta as Record<string, unknown>).dryRun) {
|
||||||
blocks.push(`### ${q.id}\n[dryRun] skipped nerve knowledge query\n`);
|
blocks.push(`### ${q.id}\n[dryRun] skipped nerve knowledge query\n`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -93,7 +94,7 @@ export function createAnswererRole(deps: CreateAnswererRoleDeps): Role<AnswererM
|
|||||||
text: bundle,
|
text: bundle,
|
||||||
schema: answererMetaSchema,
|
schema: answererMetaSchema,
|
||||||
provider: extract.provider,
|
provider: extract.provider,
|
||||||
dryRun: start.meta.dryRun,
|
dryRun: false,
|
||||||
});
|
});
|
||||||
if (!metaR.ok) {
|
if (!metaR.ok) {
|
||||||
throw new Error(`answerer llmExtract: ${JSON.stringify(metaR.error)}`);
|
throw new Error(`answerer llmExtract: ${JSON.stringify(metaR.error)}`);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -33,11 +33,12 @@ function lastMeta<M>(messages: WorkflowMessage[], role: string): M | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function explorerPrompt(start: StartStep, messages: WorkflowMessage[]): string {
|
export function explorerPrompt(ctx: ThreadContext): string {
|
||||||
const threadId = start.meta.threadId;
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
||||||
|
const threadId = ctx.start.meta.threadId;
|
||||||
const qm = lastMeta<QuestionerMeta>(messages, "questioner");
|
const qm = lastMeta<QuestionerMeta>(messages, "questioner");
|
||||||
const am = lastMeta<AnswererMeta>(messages, "answerer");
|
const am = lastMeta<AnswererMeta>(messages, "answerer");
|
||||||
const cwd = resolveWorkdir(start);
|
const cwd = resolveWorkdir(ctx.start);
|
||||||
|
|
||||||
const unanswered =
|
const unanswered =
|
||||||
am?.results.filter((r) => !r.found).map((r) => r.id) ?? [];
|
am?.results.filter((r) => !r.found).map((r) => r.id) ?? [];
|
||||||
@ -85,7 +86,7 @@ export function createExplorerRole(
|
|||||||
): Role<ExplorerMeta> {
|
): Role<ExplorerMeta> {
|
||||||
return createRole(
|
return createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (innerStart: StartStep, msgs: WorkflowMessage[]) => explorerPrompt(innerStart, msgs),
|
async (ctx: ThreadContext) => explorerPrompt(ctx),
|
||||||
explorerMetaSchema,
|
explorerMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
|
|
||||||
import type { Role, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { Role, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createLlmRole } from "@uncaged/nerve-workflow-utils";
|
import { createLlmRole } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -18,7 +18,7 @@ const questionerExtractSchema = z.object({
|
|||||||
domain: z.string(),
|
domain: z.string(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.length(3),
|
.length(5),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type QuestionerMeta = {
|
export type QuestionerMeta = {
|
||||||
@ -35,11 +35,11 @@ export type CreateQuestionerRoleDeps = {
|
|||||||
function questionerSystem(): string {
|
function questionerSystem(): string {
|
||||||
return `You are the **questioner** in a knowledge-extraction workflow.
|
return `You are the **questioner** in a knowledge-extraction workflow.
|
||||||
|
|
||||||
Read the given markdown knowledge card. Propose exactly **three** technical questions that are **not** already answered or covered by that card.
|
Read the given markdown knowledge card. Propose exactly **five** technical questions that are **not** already answered or covered by that card.
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
- Questions must be concrete and technical.
|
- Questions must be concrete and technical.
|
||||||
- Each question needs a stable string id (e.g. q1, q2, q3), a short domain label (e.g. routing, storage), and the question text.
|
- Each question needs a stable string id (e.g. q1, q2, q3, q4, q5), a short domain label (e.g. routing, storage), and the question text.
|
||||||
- Do not assume access to other files or tools — reason only from the card content shown.`;
|
- Do not assume access to other files or tools — reason only from the card content shown.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +56,10 @@ ${cardBody}`;
|
|||||||
export function createQuestionerRole(adapterExtract: CreateQuestionerRoleDeps): Role<QuestionerMeta> {
|
export function createQuestionerRole(adapterExtract: CreateQuestionerRoleDeps): Role<QuestionerMeta> {
|
||||||
const { extract } = adapterExtract;
|
const { extract } = adapterExtract;
|
||||||
|
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]) => {
|
return async (ctx: ThreadContext) => {
|
||||||
const cwd = resolveWorkdir(start);
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
||||||
const queue = await resolveQueueForQuestioner(start, messages, cwd);
|
const cwd = resolveWorkdir(ctx.start);
|
||||||
|
const queue = await resolveQueueForQuestioner(ctx.start, messages, cwd);
|
||||||
if (queue.length === 0) {
|
if (queue.length === 0) {
|
||||||
return {
|
return {
|
||||||
content:
|
content:
|
||||||
@ -93,7 +94,7 @@ export function createQuestionerRole(adapterExtract: CreateQuestionerRoleDeps):
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const r = await inner(start, messages);
|
const r = await inner(ctx);
|
||||||
return {
|
return {
|
||||||
content: r.content,
|
content: r.content,
|
||||||
meta: {
|
meta: {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import type { WorkflowMessage } from "@uncaged/nerve-core";
|
import type { RoleStep, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
|
|
||||||
type SolveIssueParse = {
|
type SolveIssueParse = {
|
||||||
host: string;
|
host: string;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core";
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
import { createRole, decorateRole, withDryRun, onFail } from "@uncaged/nerve-workflow-utils";
|
import { createRole, decorateRole, withDryRun, onFail } from "@uncaged/nerve-workflow-utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -18,7 +18,7 @@ export function createCommitterRole(
|
|||||||
): Role<CommitterMeta> {
|
): Role<CommitterMeta> {
|
||||||
const inner = createRole(
|
const inner = createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) => committerPrompt({ threadId: start.meta.threadId }),
|
async (ctx: ThreadContext) => committerPrompt({ threadId: ctx.start.meta.threadId }),
|
||||||
committerMetaSchema,
|
committerMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -20,7 +20,8 @@ export function createImplementRole(
|
|||||||
adapter: AgentFn,
|
adapter: AgentFn,
|
||||||
{ extract, nerveRoot }: CreateImplementRoleDeps,
|
{ extract, nerveRoot }: CreateImplementRoleDeps,
|
||||||
): Role<ImplementMeta> {
|
): Role<ImplementMeta> {
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<ImplementMeta>> => {
|
return async (ctx: ThreadContext): Promise<RoleResult<ImplementMeta>> => {
|
||||||
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
||||||
const cwd = resolveRepoCwd(messages);
|
const cwd = resolveRepoCwd(messages);
|
||||||
if (cwd === null) {
|
if (cwd === null) {
|
||||||
return {
|
return {
|
||||||
@ -31,22 +32,24 @@ export function createImplementRole(
|
|||||||
|
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (innerStart: StartStep) =>
|
async (innerCtx: ThreadContext) =>
|
||||||
buildImplementPrompt({
|
buildImplementPrompt({
|
||||||
threadId: innerStart.meta.threadId,
|
threadId: innerCtx.start.meta.threadId,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
}),
|
}),
|
||||||
implementMetaSchema,
|
implementMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|
||||||
const innerStart = {
|
const innerCtx: ThreadContext = {
|
||||||
...start,
|
...ctx,
|
||||||
meta: { ...start.meta, workdir: cwd },
|
start: {
|
||||||
} as StartStep;
|
...ctx.start,
|
||||||
|
meta: { ...ctx.start.meta, workdir: cwd },
|
||||||
|
},
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
return await innerRole(innerStart, messages);
|
return await innerRole(innerCtx);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e instanceof Error ? e.message : String(e);
|
const msg = e instanceof Error ? e.message : String(e);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -20,7 +20,8 @@ export function createPlanRole(
|
|||||||
adapter: AgentFn,
|
adapter: AgentFn,
|
||||||
{ extract, nerveRoot }: CreatePlanRoleDeps,
|
{ extract, nerveRoot }: CreatePlanRoleDeps,
|
||||||
): Role<PlanMeta> {
|
): Role<PlanMeta> {
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<PlanMeta>> => {
|
return async (ctx: ThreadContext): Promise<RoleResult<PlanMeta>> => {
|
||||||
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
||||||
const cwd = resolveRepoCwd(messages);
|
const cwd = resolveRepoCwd(messages);
|
||||||
if (cwd === null) {
|
if (cwd === null) {
|
||||||
return {
|
return {
|
||||||
@ -31,22 +32,24 @@ export function createPlanRole(
|
|||||||
|
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (innerStart: StartStep) =>
|
async (innerCtx: ThreadContext) =>
|
||||||
buildPlanPrompt({
|
buildPlanPrompt({
|
||||||
threadId: innerStart.meta.threadId,
|
threadId: innerCtx.start.meta.threadId,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
}),
|
}),
|
||||||
planMetaSchema,
|
planMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|
||||||
const innerStart = {
|
const innerCtx: ThreadContext = {
|
||||||
...start,
|
...ctx,
|
||||||
meta: { ...start.meta, workdir: cwd },
|
start: {
|
||||||
} as StartStep;
|
...ctx.start,
|
||||||
|
meta: { ...ctx.start.meta, workdir: cwd },
|
||||||
|
},
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
return await innerRole(innerStart, messages);
|
return await innerRole(innerCtx);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e instanceof Error ? e.message : String(e);
|
const msg = e instanceof Error ? e.message : String(e);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -13,7 +13,7 @@ export type PrepareMeta = z.infer<typeof prepareMetaSchema>;
|
|||||||
export function createPrepareRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<PrepareMeta> {
|
export function createPrepareRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<PrepareMeta> {
|
||||||
return createRole(
|
return createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }),
|
async (ctx: ThreadContext) => preparePrompt({ threadId: ctx.start.meta.threadId }),
|
||||||
prepareMetaSchema,
|
prepareMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +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 { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, RoleResult, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -27,17 +27,17 @@ export function createPublishRole(
|
|||||||
): Role<PublishMeta> {
|
): Role<PublishMeta> {
|
||||||
const innerRole = createRole(
|
const innerRole = createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) =>
|
async (ctx: ThreadContext) =>
|
||||||
buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
buildPublishPrompt({ threadId: ctx.start.meta.threadId, nerveRoot }),
|
||||||
publishMetaSchema,
|
publishMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|
||||||
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<PublishMeta>> => {
|
return async (ctx: ThreadContext): Promise<RoleResult<PublishMeta>> => {
|
||||||
const file = logPath(nerveRoot);
|
const file = logPath(nerveRoot);
|
||||||
mkdirSync(join(file, ".."), { recursive: true });
|
mkdirSync(join(file, ".."), { recursive: true });
|
||||||
|
|
||||||
if (isDryRun(start)) {
|
if (isDryRun(ctx.start)) {
|
||||||
const msg = "[dry-run] publish skipped (no git push / PR)";
|
const msg = "[dry-run] publish skipped (no git push / PR)";
|
||||||
writeFileSync(file, `${msg}\n`, "utf-8");
|
writeFileSync(file, `${msg}\n`, "utf-8");
|
||||||
return {
|
return {
|
||||||
@ -46,13 +46,16 @@ export function createPublishRole(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const innerStart = {
|
const innerCtx: ThreadContext = {
|
||||||
...start,
|
...ctx,
|
||||||
meta: { ...start.meta, workdir: nerveRoot },
|
start: {
|
||||||
} as StartStep;
|
...ctx.start,
|
||||||
|
meta: { ...ctx.start.meta, workdir: nerveRoot },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await innerRole(innerStart, messages);
|
return await innerRole(innerCtx);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e instanceof Error ? e.message : String(e);
|
const msg = e instanceof Error ? e.message : String(e);
|
||||||
const body = `publish failed: ${msg}\n`;
|
const body = `publish failed: ${msg}\n`;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -13,7 +13,7 @@ export type ReadIssueMeta = z.infer<typeof readIssueMetaSchema>;
|
|||||||
export function createReadIssueRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<ReadIssueMeta> {
|
export function createReadIssueRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<ReadIssueMeta> {
|
||||||
return createRole(
|
return createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }),
|
async (ctx: ThreadContext) => readIssuePrompt({ threadId: ctx.start.meta.threadId }),
|
||||||
readIssueMetaSchema,
|
readIssueMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -17,8 +17,8 @@ export function createReviewRole(
|
|||||||
): Role<ReviewMeta> {
|
): Role<ReviewMeta> {
|
||||||
return createRole(
|
return createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) =>
|
async (ctx: ThreadContext) =>
|
||||||
reviewPrompt({ threadId: start.meta.threadId, nerveRoot }),
|
reviewPrompt({ threadId: ctx.start.meta.threadId, nerveRoot }),
|
||||||
reviewMetaSchema,
|
reviewMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core";
|
import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core";
|
||||||
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";
|
||||||
@ -13,7 +13,7 @@ export type TestMeta = z.infer<typeof testMetaSchema>;
|
|||||||
export function createTestRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<TestMeta> {
|
export function createTestRole(adapter: AgentFn, extract: LlmExtractorConfig): Role<TestMeta> {
|
||||||
return createRole(
|
return createRole(
|
||||||
adapter,
|
adapter,
|
||||||
async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }),
|
async (ctx: ThreadContext) => testPrompt({ threadId: ctx.start.meta.threadId }),
|
||||||
testMetaSchema,
|
testMetaSchema,
|
||||||
extract,
|
extract,
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user