Files
Agent-System/deploy/pi-agent/reasoning-materialize.mjs
T
weichen f6046bba7e fix(docgov): materialize reasoning narrative under --no-tools
Embed Facts in the PI narrative prompt and teach the bind-mounted runner
to write assistant text into missing reasoning targets, matching pi-native.
2026-09-23 15:11:22 +00:00

79 lines
1.9 KiB
JavaScript

/**
* Reasoning / --no-tools runs cannot write deliverables via tools.
* Mirror pi-native: when targets are missing, materialize assistant text.
*/
export function stripThinkBlocks(text) {
return String(text || "")
.replace(/<think>[\s\S]*?<\/think>/gi, "")
.replace(/```(?:json)?\s*/gi, "")
.replace(/```/g, "")
.trim();
}
export function extractAssistantText(ev) {
if (!ev || typeof ev !== "object") {
return "";
}
const t = ev.type || "";
if (t !== "message_end" && t !== "turn_end") {
return "";
}
const msg = ev.message;
if (!msg || typeof msg !== "object" || msg.role !== "assistant") {
return "";
}
const parts = Array.isArray(msg.content) ? msg.content : [];
const chunks = [];
for (const part of parts) {
if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string") {
chunks.push(part.text);
}
}
return chunks.join("");
}
/**
* Write assistant text into missing/empty targets. Returns list of paths written.
*/
export function materializeReasoningTargets({
workspace,
targets,
assistantText,
existsSync,
readFileSync,
writeFileSync,
mkdirSync,
resolve,
dirname,
}) {
const cleaned = stripThinkBlocks(assistantText);
if (!cleaned || !workspace) {
return [];
}
const written = [];
for (const rel of Array.isArray(targets) ? targets : []) {
if (!rel || typeof rel !== "string") {
continue;
}
const abs = resolve(workspace, rel);
if (existsSync(abs)) {
try {
if (String(readFileSync(abs, "utf8")).trim()) {
continue;
}
} catch {
// fall through and overwrite empty/unreadable
}
}
try {
mkdirSync(dirname(abs), { recursive: true });
writeFileSync(abs, cleaned, "utf8");
written.push(rel);
} catch {
// leave missing; caller will classify
}
}
return written;
}