refactor(sense-generator): extract prompts to prompt.md templates

Each role's prompt is now a separate markdown file with {{mustache}} placeholders,
loaded at module init and interpolated at runtime.

小橘 🍊(NEKO Team)
This commit is contained in:
小橘 2026-04-28 03:32:51 +00:00
parent 516a28533a
commit a811660a33
4 changed files with 52 additions and 39 deletions

View File

@ -1,8 +1,14 @@
import { createCursorRole } from "@uncaged/nerve-workflow-utils"; import { createCursorRole } from "@uncaged/nerve-workflow-utils";
import { readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { resolveDashScopeProvider, NERVE_ROOT, SENSES_DIR } from "../shared.js"; import { resolveDashScopeProvider, NERVE_ROOT, SENSES_DIR } from "../shared.js";
import { coderMetaSchema } from "../types.js"; import { coderMetaSchema } from "../types.js";
import type { SenseMeta } from "../types.js"; import type { SenseMeta } from "../types.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROMPT = readFileSync(join(__dirname, "prompt.md"), "utf-8");
export async function buildCoderRole() { export async function buildCoderRole() {
const provider = await resolveDashScopeProvider(); const provider = await resolveDashScopeProvider();
if (provider === null) { if (provider === null) {
@ -12,19 +18,10 @@ export async function buildCoderRole() {
cwd: NERVE_ROOT, cwd: NERVE_ROOT,
mode: "default", mode: "default",
prompt: async (threadId) => prompt: async (threadId) =>
`Read the workflow thread for the planner's sense design: \`nerve thread ${threadId}\` PROMPT
.replace("{{threadId}}", threadId)
Implement the sense. Create exactly: .replace("{{sensesDir}}", SENSES_DIR)
1. The sense directory under ${SENSES_DIR}/<sense-name>/ .replace("{{nerveRoot}}", NERVE_ROOT),
2. index.js export async function compute(db, _peers), import schema from "./schema.ts" extract: { provider, schema: coderMetaSchema },
3. schema.ts drizzle-orm/sqlite-core
4. migrations/0001_init.sql must match schema.ts
5. Update ${NERVE_ROOT}/nerve.yaml add sense config + reflex entry
Follow the patterns from existing senses. Create all files now.`,
extract: {
provider,
schema: coderMetaSchema,
},
}); });
} }

View File

@ -0,0 +1,10 @@
Read the workflow thread for the planner's sense design: `nerve thread {{threadId}}`
Implement the sense. Create exactly:
1. The sense directory under {{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 {{nerveRoot}}/nerve.yaml — add sense config + reflex entry
Follow the patterns from existing senses. Create all files now.

View File

@ -1,8 +1,13 @@
import { createCursorRole } from "@uncaged/nerve-workflow-utils"; import { createCursorRole } from "@uncaged/nerve-workflow-utils";
import { readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { resolveDashScopeProvider, buildSenseExamples, getNerveYaml, NERVE_ROOT } from "../shared.js"; import { resolveDashScopeProvider, buildSenseExamples, getNerveYaml, NERVE_ROOT } from "../shared.js";
import { plannerMetaSchema } from "../types.js"; import { plannerMetaSchema } from "../types.js";
import type { SenseMeta } from "../types.js"; import type { SenseMeta } from "../types.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROMPT = readFileSync(join(__dirname, "prompt.md"), "utf-8");
const senseExamples = buildSenseExamples(); const senseExamples = buildSenseExamples();
const nerveYaml = getNerveYaml(); const nerveYaml = getNerveYaml();
@ -15,30 +20,10 @@ export async function buildPlannerRole() {
cwd: NERVE_ROOT, cwd: NERVE_ROOT,
mode: "ask", mode: "ask",
prompt: async (threadId) => prompt: async (threadId) =>
`You are planning a new Nerve sense. PROMPT
.replace("{{threadId}}", threadId)
Read the workflow thread for the user's request: \`nerve thread ${threadId}\` .replace("{{senseExamples}}", senseExamples)
.replace("{{nerveYaml}}", nerveYaml),
Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdown: extract: { provider, schema: plannerMetaSchema },
## Sense Design
### Name kebab-case
### Fields name, type (integer/real/text), description
### Compute Logic step-by-step, specific Node.js APIs or shell commands
### Trigger Config group, interval, throttle, timeout
Reference senses:
${senseExamples}
Current nerve.yaml:
\`\`\`yaml
${nerveYaml}
\`\`\`
Output ONLY the plan. Be precise and implementation-ready.`,
extract: {
provider,
schema: plannerMetaSchema,
},
}); });
} }

View File

@ -0,0 +1,21 @@
You are planning a new Nerve sense.
Read the workflow thread for the user's request: `nerve thread {{threadId}}`
Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdown:
## Sense Design
### Name — kebab-case
### Fields — name, type (integer/real/text), description
### Compute Logic — step-by-step, specific Node.js APIs or shell commands
### Trigger Config — group, interval, throttle, timeout
Reference senses:
{{senseExamples}}
Current nerve.yaml:
```yaml
{{nerveYaml}}
```
Output ONLY the plan. Be precise and implementation-ready.