refactor: extractPrompt out of ExtractContext, into ExtractFn parameter
ExtractFn = (schema, prompt, ctx) => Promise<T> extractPrompt stays in RoleDefinition (definition layer), not in context (state layer). Callers pass their own prompt — engine uses roleDef.extractPrompt, cursor agent uses its own. 小橘 <xiaoju@shazhou.work>
This commit is contained in:
@@ -5,6 +5,7 @@ import { createCursorAgent, validateCursorAgentConfig } from "../src/index.js";
|
|||||||
|
|
||||||
const testExtract: ExtractFn = async <T extends Record<string, unknown>>(
|
const testExtract: ExtractFn = async <T extends Record<string, unknown>>(
|
||||||
_schema: z.ZodType<T>,
|
_schema: z.ZodType<T>,
|
||||||
|
_prompt: string,
|
||||||
_ctx: ExtractContext,
|
_ctx: ExtractContext,
|
||||||
): Promise<T> => ({ workspace: "/tmp" }) as unknown as T;
|
): Promise<T> => ({ workspace: "/tmp" }) as unknown as T;
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,12 @@ export function createCursorAgent(config: CursorAgentConfig): AgentFn {
|
|||||||
const extractCtx: ExtractContext = {
|
const extractCtx: ExtractContext = {
|
||||||
...ctx,
|
...ctx,
|
||||||
agentContent: "",
|
agentContent: "",
|
||||||
extractPrompt:
|
|
||||||
"From the thread context, determine the absolute filesystem path where the project/repository is located.",
|
|
||||||
};
|
};
|
||||||
const { workspace } = await config.extract(cursorWorkspaceSchema, extractCtx);
|
const { workspace } = await config.extract(
|
||||||
|
cursorWorkspaceSchema,
|
||||||
|
"From the thread context, determine the absolute filesystem path where the project/repository is located.",
|
||||||
|
extractCtx,
|
||||||
|
);
|
||||||
const fullPrompt = buildAgentPrompt(ctx);
|
const fullPrompt = buildAgentPrompt(ctx);
|
||||||
const args = [
|
const args = [
|
||||||
"-p",
|
"-p",
|
||||||
|
|||||||
@@ -88,10 +88,13 @@ export function createWorkflow<M extends RoleMeta>(
|
|||||||
const extractCtx: ExtractContext<M> = {
|
const extractCtx: ExtractContext<M> = {
|
||||||
...agentCtx,
|
...agentCtx,
|
||||||
agentContent: raw,
|
agentContent: raw,
|
||||||
extractPrompt: roleDef.extractPrompt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta = await extract(roleDef.schema, extractCtx as unknown as ExtractContext);
|
const meta = await extract(
|
||||||
|
roleDef.schema,
|
||||||
|
roleDef.extractPrompt,
|
||||||
|
extractCtx as unknown as ExtractContext,
|
||||||
|
);
|
||||||
|
|
||||||
const ts = Date.now();
|
const ts = Date.now();
|
||||||
const step = {
|
const step = {
|
||||||
|
|||||||
@@ -5,16 +5,18 @@ import type { ExtractContext, LlmProvider } from "./types.js";
|
|||||||
|
|
||||||
export type ExtractFn = <T extends Record<string, unknown>>(
|
export type ExtractFn = <T extends Record<string, unknown>>(
|
||||||
schema: z.ZodType<T>,
|
schema: z.ZodType<T>,
|
||||||
|
prompt: string,
|
||||||
ctx: ExtractContext,
|
ctx: ExtractContext,
|
||||||
) => Promise<T>;
|
) => Promise<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an ExtractFn backed by an LLM provider.
|
* Create an ExtractFn backed by an LLM provider.
|
||||||
* Builds prompt text from {@link ExtractContext} and calls structured extraction.
|
* Builds prompt text from {@link ExtractContext} plus `prompt` and calls structured extraction.
|
||||||
*/
|
*/
|
||||||
export function createExtract(provider: LlmProvider): ExtractFn {
|
export function createExtract(provider: LlmProvider): ExtractFn {
|
||||||
return async <T extends Record<string, unknown>>(
|
return async <T extends Record<string, unknown>>(
|
||||||
schema: z.ZodType<T>,
|
schema: z.ZodType<T>,
|
||||||
|
prompt: string,
|
||||||
ctx: ExtractContext,
|
ctx: ExtractContext,
|
||||||
): Promise<T> => {
|
): Promise<T> => {
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
@@ -37,7 +39,7 @@ export function createExtract(provider: LlmProvider): ExtractFn {
|
|||||||
lines.push(ctx.agentContent);
|
lines.push(ctx.agentContent);
|
||||||
lines.push("");
|
lines.push("");
|
||||||
lines.push("## Extraction Instruction");
|
lines.push("## Extraction Instruction");
|
||||||
lines.push(ctx.extractPrompt);
|
lines.push(prompt);
|
||||||
|
|
||||||
const text = lines.join("\n");
|
const text = lines.join("\n");
|
||||||
const result = await llmExtractWithRetry({ text, schema, provider });
|
const result = await llmExtractWithRetry({ text, schema, provider });
|
||||||
|
|||||||
@@ -73,10 +73,9 @@ export type AgentContext<M extends RoleMeta = RoleMeta> = ModeratorContext<M> &
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Phase 3: Extractor runs — has agent output and extract instruction. */
|
/** Phase 3: Extractor runs — has agent output; the extraction instruction is a separate argument to the extract function. */
|
||||||
export type ExtractContext<M extends RoleMeta = RoleMeta> = AgentContext<M> & {
|
export type ExtractContext<M extends RoleMeta = RoleMeta> = AgentContext<M> & {
|
||||||
agentContent: string;
|
agentContent: string;
|
||||||
extractPrompt: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Alias — most external consumers see the agent-phase context. */
|
/** Alias — most external consumers see the agent-phase context. */
|
||||||
|
|||||||
Reference in New Issue
Block a user