refactor: remove redundant context from prompts, delegate to nerve-dev skill
- Remove nerveYaml injection from planner (skill has it)
- Remove sensesDir/nerveRoot from coder and tester (skill has conventions)
- Prompts now just say 'read the skill' instead of inlining knowledge
- BuildSenseGeneratorDeps reduced to { provider, cwd }
- index.ts drops getNerveYaml(), SENSES_DIR, readFileSync
This commit is contained in:
parent
e460d64786
commit
645f0bacf2
@ -8,23 +8,19 @@ import type { SenseMeta } from "./moderator.js";
|
||||
|
||||
export type BuildSenseGeneratorDeps = {
|
||||
provider: LlmProvider;
|
||||
nerveRoot: string;
|
||||
sensesDir: string;
|
||||
nerveYaml: string;
|
||||
cwd: string;
|
||||
};
|
||||
|
||||
export function buildSenseGenerator({
|
||||
provider,
|
||||
nerveRoot,
|
||||
sensesDir,
|
||||
nerveYaml,
|
||||
cwd,
|
||||
}: BuildSenseGeneratorDeps): WorkflowDefinition<SenseMeta> {
|
||||
return {
|
||||
name: "sense-generator",
|
||||
roles: {
|
||||
planner: buildPlannerRole({ provider, cwd: nerveRoot, nerveYaml }),
|
||||
coder: buildCoderRole({ provider, cwd: nerveRoot, sensesDir, nerveRoot }),
|
||||
tester: buildTesterRole({ provider, sensesDir, nerveRoot }),
|
||||
planner: buildPlannerRole({ provider, cwd }),
|
||||
coder: buildCoderRole({ provider, cwd }),
|
||||
tester: buildTesterRole({ provider }),
|
||||
},
|
||||
moderator,
|
||||
};
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { spawnSafe } from "@uncaged/nerve-workflow-utils";
|
||||
import { buildSenseGenerator } from "./build.js";
|
||||
@ -7,7 +6,6 @@ import { buildSenseGenerator } from "./build.js";
|
||||
|
||||
const HOME = process.env.HOME ?? "/home/azureuser";
|
||||
const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
||||
const SENSES_DIR = join(NERVE_ROOT, "senses");
|
||||
|
||||
// --- Resolve provider ---
|
||||
|
||||
@ -28,23 +26,11 @@ if (!apiKey || !baseUrl) {
|
||||
throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL");
|
||||
}
|
||||
|
||||
// --- Build context ---
|
||||
|
||||
function getNerveYaml(): string {
|
||||
try {
|
||||
return readFileSync(join(NERVE_ROOT, "nerve.yaml"), "utf-8");
|
||||
} catch {
|
||||
return "# nerve.yaml unavailable";
|
||||
}
|
||||
}
|
||||
|
||||
// --- Wire up ---
|
||||
|
||||
const workflow = buildSenseGenerator({
|
||||
provider: { apiKey, baseUrl, model },
|
||||
nerveRoot: NERVE_ROOT,
|
||||
sensesDir: SENSES_DIR,
|
||||
nerveYaml: getNerveYaml(),
|
||||
cwd: NERVE_ROOT,
|
||||
});
|
||||
|
||||
export default workflow;
|
||||
|
||||
@ -11,17 +11,13 @@ export const coderMetaSchema = z.object({
|
||||
export type BuildCoderDeps = {
|
||||
provider: LlmProvider;
|
||||
cwd: string;
|
||||
sensesDir: string;
|
||||
nerveRoot: string;
|
||||
};
|
||||
|
||||
export function buildCoderRole({ provider, cwd, sensesDir, nerveRoot }: BuildCoderDeps) {
|
||||
export function buildCoderRole({ provider, cwd }: BuildCoderDeps) {
|
||||
return createCursorRole<CoderMeta>({
|
||||
cwd,
|
||||
mode: "default",
|
||||
prompt: async (threadId) => coderPrompt({ threadId, sensesDir, nerveRoot }),
|
||||
prompt: async (threadId) => coderPrompt({ threadId }),
|
||||
extract: { provider, schema: coderMetaSchema },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,16 +1,7 @@
|
||||
export function coderPrompt(vars: {
|
||||
threadId: string;
|
||||
sensesDir: string;
|
||||
nerveRoot: string;
|
||||
}): string {
|
||||
return `Read the workflow thread for the planner's sense design: \`nerve thread ${vars.threadId}\`
|
||||
export function coderPrompt({ threadId }: { threadId: string }): string {
|
||||
return `Read the workflow thread for the planner's sense design: \`nerve thread ${threadId}\`
|
||||
Read the nerve-dev skill for sense file structure and conventions: \`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||
|
||||
Implement the sense. Create exactly:
|
||||
1. The sense directory under ${vars.sensesDir}/<sense-name>/
|
||||
2. index.js — export async function compute(db, _peers), import schema from "./schema.ts"
|
||||
3. schema.ts — drizzle-orm/sqlite-core
|
||||
4. migrations/0001_init.sql — must match schema.ts
|
||||
5. Update ${vars.nerveRoot}/nerve.yaml — add sense config + reflex entry
|
||||
|
||||
Follow the patterns from existing senses. Create all files now.`;
|
||||
Implement the sense following the patterns from existing senses and the skill guide.
|
||||
Create all required files and update nerve.yaml.`;
|
||||
}
|
||||
|
||||
@ -11,16 +11,13 @@ export const plannerMetaSchema = z.object({
|
||||
export type BuildPlannerDeps = {
|
||||
provider: LlmProvider;
|
||||
cwd: string;
|
||||
nerveYaml: string;
|
||||
};
|
||||
|
||||
export function buildPlannerRole({ provider, cwd, nerveYaml }: BuildPlannerDeps) {
|
||||
export function buildPlannerRole({ provider, cwd }: BuildPlannerDeps) {
|
||||
return createCursorRole<PlannerMeta>({
|
||||
cwd,
|
||||
mode: "ask",
|
||||
prompt: async (threadId) => plannerPrompt({ threadId, nerveYaml }),
|
||||
prompt: async (threadId) => plannerPrompt({ threadId }),
|
||||
extract: { provider, schema: plannerMetaSchema },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
export function plannerPrompt({ threadId, nerveYaml }: {
|
||||
threadId: string;
|
||||
nerveYaml: string;
|
||||
}): string {
|
||||
export function plannerPrompt({ threadId }: { threadId: string }): string {
|
||||
return `You are planning a new Nerve sense.
|
||||
|
||||
Read the workflow thread for the user's request: \`nerve thread ${threadId}\`
|
||||
Read the nerve-dev skill for sense conventions: \`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||
Also look at existing senses in the \`senses/\` directory for patterns.
|
||||
|
||||
Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdown:
|
||||
|
||||
@ -14,14 +13,5 @@ Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdow
|
||||
### Compute Logic — step-by-step, specific Node.js APIs or shell commands
|
||||
### Trigger Config — group, interval, throttle, timeout
|
||||
|
||||
For reference examples of existing senses (schema, compute logic, migrations), read the nerve-dev skill:
|
||||
\`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||
Also look at existing senses in the \`senses/\` directory for patterns.
|
||||
|
||||
Current nerve.yaml:
|
||||
\`\`\`yaml
|
||||
${nerveYaml}
|
||||
\`\`\`
|
||||
|
||||
Output ONLY the plan. Be precise and implementation-ready.`;
|
||||
}
|
||||
|
||||
@ -10,15 +10,11 @@ export const testerMetaSchema = z.object({
|
||||
|
||||
export type BuildTesterDeps = {
|
||||
provider: LlmProvider;
|
||||
sensesDir: string;
|
||||
nerveRoot: string;
|
||||
};
|
||||
|
||||
export function buildTesterRole({ provider, sensesDir, nerveRoot }: BuildTesterDeps) {
|
||||
export function buildTesterRole({ provider }: BuildTesterDeps) {
|
||||
return createHermesRole<TesterMeta>({
|
||||
prompt: async (threadId) => testerPrompt({ threadId, sensesDir, nerveRoot }),
|
||||
prompt: async (threadId) => testerPrompt({ threadId }),
|
||||
extract: { provider, schema: testerMetaSchema },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,32 +1,16 @@
|
||||
export function testerPrompt(vars: {
|
||||
threadId: string;
|
||||
sensesDir: string;
|
||||
nerveRoot: string;
|
||||
}): string {
|
||||
export function testerPrompt({ threadId }: { threadId: string }): string {
|
||||
return `You are testing a newly created Nerve sense end-to-end.
|
||||
|
||||
Read the workflow thread for context: \`nerve thread ${vars.threadId}\`
|
||||
The planner named the sense and the coder created the files.
|
||||
Read the workflow thread for context: \`nerve thread ${threadId}\`
|
||||
Read the nerve-dev skill for expected file structure: \`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||
|
||||
Verify the full lifecycle:
|
||||
|
||||
1. Check files exist under ${vars.sensesDir}/<sense-name>/
|
||||
- index.js, schema.ts, migrations/0001_init.sql
|
||||
All three must exist.
|
||||
|
||||
2. Check ${vars.nerveRoot}/nerve.yaml has the sense config and reflex entry
|
||||
The sense name should appear under \`senses:\` with group, throttle, etc.
|
||||
|
||||
3. Run \`nerve sense list\` — confirm the sense appears in the output
|
||||
|
||||
1. Check all required sense files exist
|
||||
2. Check nerve.yaml has the sense config
|
||||
3. Run \`nerve sense list\` — confirm the sense appears
|
||||
4. Run \`nerve sense trigger <sense-name>\` — should complete without error
|
||||
|
||||
5. Wait a few seconds, then run \`nerve sense query <sense-name>\`
|
||||
Keep retrying (up to ~20 seconds) until it returns at least one row.
|
||||
If it still says "0 rows", that's a failure.
|
||||
|
||||
6. If any step fails, run \`nerve logs\` to check for errors and include
|
||||
relevant log lines in your report.
|
||||
5. Run \`nerve sense query <sense-name>\` — retry up to 20s until rows appear
|
||||
6. If any step fails, run \`nerve logs\` and include relevant errors
|
||||
|
||||
Output a clear summary: what you checked, what passed, what failed, and why.`;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user