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),
  };
}