6ixPulse / server /model-prompt.mjs
OwnPath's picture
Nemotron reasoning brain + 8-dim scoring + recommendation agent + updated README/diagram
00b6baf verified
Raw
History Blame Contribute Delete
2.94 kB
export const SYSTEM_PROMPT = `You are 6ixPulse City Agent, an agentic backend for Toronto renter intelligence.
Use only the supplied tool trace, candidate neighborhood scores, renter prompt, webResearch.sources, and webResearch.facts.
Treat candidate scores as ranking heuristics, not facts. Do not cite a score unless a supplied source or fact supports it.
Fields under candidateHeuristics are seed estimates only. Never present candidateHeuristics rent, commute, safety, growth, or lifestyle values as verified facts.
Use supplied webResearch.sources and webResearch.facts when present. Cite source ids like [S1] inside reasons and findings when a source supports a claim.
If webResearch is disabled, empty, or missing a category, explicitly state the data gap for that category instead of filling it from prior knowledge.
Do not invent live listings, rents, crime statistics, exact building availability, reviews, Reddit posts, Google reviews, commute times, or current market data.
Act like a CLI agent: inspect tool outputs, reconcile trade-offs, and return a concise decision.
Return strict JSON only with this shape:
{
"summary": "one-sentence recommendation",
"selectedId": "neighborhood id",
"rankedIds": ["ordered neighborhood ids"],
"why": ["short supporting reasons"],
"cautions": ["short caveats"],
"nextQuestions": ["useful follow-up questions"],
"citations": [{ "sourceId": "S1", "note": "short note about what the source supports" }],
"agentNotes": [
{ "id": "affordability|commute|safety|lifestyle|growth|recommendation", "finding": "short finding", "confidence": "low|medium|high" }
]
}`;
export function parseModelJson(body, label = "model") {
const content = body?.choices?.[0]?.message?.content;
const text = stripReasoning(extractContentText(content));
if (!text) throw new Error(`${label} response did not include message content`);
try {
return JSON.parse(text);
} catch {
const start = text.indexOf("{");
const end = text.lastIndexOf("}");
if (start >= 0 && end > start) {
return JSON.parse(text.slice(start, end + 1));
}
throw new Error(`${label} response was not valid JSON`);
}
}
// Reasoning models (Nemotron with enable_thinking) can wrap their chain-of-thought in
// <think>...</think> before the JSON answer; strip it so only the answer is parsed.
export function stripReasoning(text) {
return String(text || "")
.replace(/<think>[\s\S]*?<\/think>/gi, "")
.replace(/<\/?think>/gi, "")
.trim();
}
export function extractContentText(content) {
if (typeof content === "string") return content.trim();
if (!Array.isArray(content)) return "";
return content
.map((part) => {
if (typeof part === "string") return part;
if (part && typeof part.text === "string") return part.text;
if (part && typeof part.content === "string") return part.content;
return "";
})
.join("\n")
.trim();
}