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 = {
|
export type BuildSenseGeneratorDeps = {
|
||||||
provider: LlmProvider;
|
provider: LlmProvider;
|
||||||
nerveRoot: string;
|
cwd: string;
|
||||||
sensesDir: string;
|
|
||||||
nerveYaml: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildSenseGenerator({
|
export function buildSenseGenerator({
|
||||||
provider,
|
provider,
|
||||||
nerveRoot,
|
cwd,
|
||||||
sensesDir,
|
|
||||||
nerveYaml,
|
|
||||||
}: BuildSenseGeneratorDeps): WorkflowDefinition<SenseMeta> {
|
}: BuildSenseGeneratorDeps): WorkflowDefinition<SenseMeta> {
|
||||||
return {
|
return {
|
||||||
name: "sense-generator",
|
name: "sense-generator",
|
||||||
roles: {
|
roles: {
|
||||||
planner: buildPlannerRole({ provider, cwd: nerveRoot, nerveYaml }),
|
planner: buildPlannerRole({ provider, cwd }),
|
||||||
coder: buildCoderRole({ provider, cwd: nerveRoot, sensesDir, nerveRoot }),
|
coder: buildCoderRole({ provider, cwd }),
|
||||||
tester: buildTesterRole({ provider, sensesDir, nerveRoot }),
|
tester: buildTesterRole({ provider }),
|
||||||
},
|
},
|
||||||
moderator,
|
moderator,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { readFileSync } from "node:fs";
|
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { spawnSafe } from "@uncaged/nerve-workflow-utils";
|
import { spawnSafe } from "@uncaged/nerve-workflow-utils";
|
||||||
import { buildSenseGenerator } from "./build.js";
|
import { buildSenseGenerator } from "./build.js";
|
||||||
@ -7,7 +6,6 @@ import { buildSenseGenerator } 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");
|
||||||
const SENSES_DIR = join(NERVE_ROOT, "senses");
|
|
||||||
|
|
||||||
// --- Resolve provider ---
|
// --- Resolve provider ---
|
||||||
|
|
||||||
@ -28,23 +26,11 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Build context ---
|
|
||||||
|
|
||||||
function getNerveYaml(): string {
|
|
||||||
try {
|
|
||||||
return readFileSync(join(NERVE_ROOT, "nerve.yaml"), "utf-8");
|
|
||||||
} catch {
|
|
||||||
return "# nerve.yaml unavailable";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Wire up ---
|
// --- Wire up ---
|
||||||
|
|
||||||
const workflow = buildSenseGenerator({
|
const workflow = buildSenseGenerator({
|
||||||
provider: { apiKey, baseUrl, model },
|
provider: { apiKey, baseUrl, model },
|
||||||
nerveRoot: NERVE_ROOT,
|
cwd: NERVE_ROOT,
|
||||||
sensesDir: SENSES_DIR,
|
|
||||||
nerveYaml: getNerveYaml(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default workflow;
|
export default workflow;
|
||||||
|
|||||||
@ -11,17 +11,13 @@ export const coderMetaSchema = z.object({
|
|||||||
export type BuildCoderDeps = {
|
export type BuildCoderDeps = {
|
||||||
provider: LlmProvider;
|
provider: LlmProvider;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
sensesDir: string;
|
|
||||||
nerveRoot: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildCoderRole({ provider, cwd, sensesDir, nerveRoot }: BuildCoderDeps) {
|
export function buildCoderRole({ provider, cwd }: BuildCoderDeps) {
|
||||||
return createCursorRole<CoderMeta>({
|
return createCursorRole<CoderMeta>({
|
||||||
cwd,
|
cwd,
|
||||||
mode: "default",
|
mode: "default",
|
||||||
prompt: async (threadId) => coderPrompt({ threadId, sensesDir, nerveRoot }),
|
prompt: async (threadId) => coderPrompt({ threadId }),
|
||||||
extract: { provider, schema: coderMetaSchema },
|
extract: { provider, schema: coderMetaSchema },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,7 @@
|
|||||||
export function coderPrompt(vars: {
|
export function coderPrompt({ threadId }: { threadId: string }): string {
|
||||||
threadId: string;
|
return `Read the workflow thread for the planner's sense design: \`nerve thread ${threadId}\`
|
||||||
sensesDir: string;
|
Read the nerve-dev skill for sense file structure and conventions: \`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||||
nerveRoot: string;
|
|
||||||
}): string {
|
|
||||||
return `Read the workflow thread for the planner's sense design: \`nerve thread ${vars.threadId}\`
|
|
||||||
|
|
||||||
Implement the sense. Create exactly:
|
Implement the sense following the patterns from existing senses and the skill guide.
|
||||||
1. The sense directory under ${vars.sensesDir}/<sense-name>/
|
Create all required files and update nerve.yaml.`;
|
||||||
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.`;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,16 +11,13 @@ export const plannerMetaSchema = z.object({
|
|||||||
export type BuildPlannerDeps = {
|
export type BuildPlannerDeps = {
|
||||||
provider: LlmProvider;
|
provider: LlmProvider;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
nerveYaml: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildPlannerRole({ provider, cwd, nerveYaml }: BuildPlannerDeps) {
|
export function buildPlannerRole({ provider, cwd }: BuildPlannerDeps) {
|
||||||
return createCursorRole<PlannerMeta>({
|
return createCursorRole<PlannerMeta>({
|
||||||
cwd,
|
cwd,
|
||||||
mode: "ask",
|
mode: "ask",
|
||||||
prompt: async (threadId) => plannerPrompt({ threadId, nerveYaml }),
|
prompt: async (threadId) => plannerPrompt({ threadId }),
|
||||||
extract: { provider, schema: plannerMetaSchema },
|
extract: { provider, schema: plannerMetaSchema },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
export function plannerPrompt({ threadId, nerveYaml }: {
|
export function plannerPrompt({ threadId }: { threadId: string }): string {
|
||||||
threadId: string;
|
|
||||||
nerveYaml: string;
|
|
||||||
}): string {
|
|
||||||
return `You are planning a new Nerve sense.
|
return `You are planning a new Nerve sense.
|
||||||
|
|
||||||
Read the workflow thread for the user's request: \`nerve thread ${threadId}\`
|
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:
|
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
|
### Compute Logic — step-by-step, specific Node.js APIs or shell commands
|
||||||
### Trigger Config — group, interval, throttle, timeout
|
### 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.`;
|
Output ONLY the plan. Be precise and implementation-ready.`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,15 +10,11 @@ export const testerMetaSchema = z.object({
|
|||||||
|
|
||||||
export type BuildTesterDeps = {
|
export type BuildTesterDeps = {
|
||||||
provider: LlmProvider;
|
provider: LlmProvider;
|
||||||
sensesDir: string;
|
|
||||||
nerveRoot: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function buildTesterRole({ provider, sensesDir, nerveRoot }: BuildTesterDeps) {
|
export function buildTesterRole({ provider }: BuildTesterDeps) {
|
||||||
return createHermesRole<TesterMeta>({
|
return createHermesRole<TesterMeta>({
|
||||||
prompt: async (threadId) => testerPrompt({ threadId, sensesDir, nerveRoot }),
|
prompt: async (threadId) => testerPrompt({ threadId }),
|
||||||
extract: { provider, schema: testerMetaSchema },
|
extract: { provider, schema: testerMetaSchema },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,16 @@
|
|||||||
export function testerPrompt(vars: {
|
export function testerPrompt({ threadId }: { threadId: string }): string {
|
||||||
threadId: string;
|
|
||||||
sensesDir: string;
|
|
||||||
nerveRoot: string;
|
|
||||||
}): string {
|
|
||||||
return `You are testing a newly created Nerve sense end-to-end.
|
return `You are testing a newly created Nerve sense end-to-end.
|
||||||
|
|
||||||
Read the workflow thread for context: \`nerve thread ${vars.threadId}\`
|
Read the workflow thread for context: \`nerve thread ${threadId}\`
|
||||||
The planner named the sense and the coder created the files.
|
Read the nerve-dev skill for expected file structure: \`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`
|
||||||
|
|
||||||
Verify the full lifecycle:
|
Verify the full lifecycle:
|
||||||
|
1. Check all required sense files exist
|
||||||
1. Check files exist under ${vars.sensesDir}/<sense-name>/
|
2. Check nerve.yaml has the sense config
|
||||||
- index.js, schema.ts, migrations/0001_init.sql
|
3. Run \`nerve sense list\` — confirm the sense appears
|
||||||
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
|
|
||||||
|
|
||||||
4. Run \`nerve sense trigger <sense-name>\` — should complete without error
|
4. Run \`nerve sense trigger <sense-name>\` — should complete without error
|
||||||
|
5. Run \`nerve sense query <sense-name>\` — retry up to 20s until rows appear
|
||||||
5. Wait a few seconds, then run \`nerve sense query <sense-name>\`
|
6. If any step fails, run \`nerve logs\` and include relevant errors
|
||||||
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.
|
|
||||||
|
|
||||||
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.`;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user