File size: 2,165 Bytes
6132f30 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | export type ResponseShellSections = {
result: string;
why: string;
nextAction: string;
rest: string;
hasShell: boolean;
};
type HeadingKind = "result" | "why" | "nextAction";
const SHELL_HEADING_RE = /^\s*\*\*(Result|Why|Next action|Action)\*\*\s*$/gim;
function headingKind(raw: string): HeadingKind | null {
const low = String(raw || "").trim().toLowerCase();
if (low === "result") return "result";
if (low === "why") return "why";
if (low === "next action" || low === "action") return "nextAction";
return null;
}
export function splitResponseShellMarkdown(content: string): ResponseShellSections {
const text = String(content || "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
const matches: Array<{ kind: HeadingKind; start: number; bodyStart: number }> = [];
let match: RegExpExecArray | null = null;
while ((match = SHELL_HEADING_RE.exec(text)) !== null) {
const kind = headingKind(match[1]);
if (!kind) continue;
matches.push({ kind, start: match.index, bodyStart: SHELL_HEADING_RE.lastIndex });
}
if (!matches.length) {
return {
result: text.trim(),
why: "",
nextAction: "",
rest: "",
hasShell: false,
};
}
const buckets: Record<HeadingKind, string> = {
result: "",
why: "",
nextAction: "",
};
const consumed: Array<[number, number]> = [];
for (let i = 0; i < matches.length; i += 1) {
const curr = matches[i];
const next = matches[i + 1];
const end = next ? next.start : text.length;
const body = text.slice(curr.bodyStart, end).trim();
if (body && !buckets[curr.kind]) buckets[curr.kind] = body;
consumed.push([curr.start, end]);
}
let rest = "";
let cursor = 0;
for (const [start, end] of consumed.sort((a, b) => a[0] - b[0])) {
if (start > cursor) rest += text.slice(cursor, start);
cursor = Math.max(cursor, end);
}
if (cursor < text.length) rest += text.slice(cursor);
return {
result: buckets.result.trim(),
why: buckets.why.trim(),
nextAction: buckets.nextAction.trim(),
rest: rest.trim(),
hasShell: Boolean(buckets.result || buckets.why || buckets.nextAction),
};
}
|