diff --git a/src/tools/council-archive/council-response-extractor.test.ts b/src/tools/council-archive/council-response-extractor.test.ts
index d436d2a0b..65441343b 100644
--- a/src/tools/council-archive/council-response-extractor.test.ts
+++ b/src/tools/council-archive/council-response-extractor.test.ts
@@ -275,5 +275,62 @@ describe("extractCouncilResponse", () => {
})
})
})
+
+ describe("#given leading spaces before opening tag", () => {
+ it("#then recognizes the tag as structural and extracts content", () => {
+ const content = "a".repeat(100)
+ const text = ` \n${content}\n`
+ const result = extractCouncilResponse(text)
+
+ expect(result).toEqual({
+ has_response: true,
+ response_complete: true,
+ result: content,
+ })
+ })
+ })
+
+ describe("#given leading tab before opening tag", () => {
+ it("#then recognizes the tag as structural and extracts content", () => {
+ const content = "a".repeat(100)
+ const text = `\t\n${content}\n`
+ const result = extractCouncilResponse(text)
+
+ expect(result).toEqual({
+ has_response: true,
+ response_complete: true,
+ result: content,
+ })
+ })
+ })
+
+ describe("#given trailing spaces after closing tag", () => {
+ it("#then recognizes the closing tag as structural and extracts content", () => {
+ const content = "a".repeat(100)
+ const text = `\n${content}\n `
+ const result = extractCouncilResponse(text)
+
+ expect(result).toEqual({
+ has_response: true,
+ response_complete: true,
+ result: content,
+ })
+ })
+ })
+
+ describe("#given inline opening tag (text before tag on same line)", () => {
+ it("#then rejects the inline tag and returns has_response false", () => {
+ const content = "a".repeat(100)
+ const text = `text \n${content}\n`
+ const result = extractCouncilResponse(text)
+
+ expect(result).toEqual({
+ has_response: false,
+ response_complete: false,
+ result: null,
+ })
+ })
+ })
+
})
diff --git a/src/tools/council-archive/council-response-extractor.ts b/src/tools/council-archive/council-response-extractor.ts
index f0be4d8f4..a3fd44fe1 100644
--- a/src/tools/council-archive/council-response-extractor.ts
+++ b/src/tools/council-archive/council-response-extractor.ts
@@ -55,12 +55,20 @@ export function hasCouncilResponseTag(sessionMessages: Array<{ info?: { role?: s
}
function isStructuralOpen(text: string, idx: number): boolean {
- return idx === 0 || text[idx - 1] === "\n"
+ if (idx === 0) return true
+ const prevNewline = text.lastIndexOf("\n", idx - 1)
+ const lineStart = prevNewline === -1 ? 0 : prevNewline + 1
+ const between = text.slice(lineStart, idx)
+ return between.split("").every((ch) => ch === " " || ch === "\t")
}
function isStructuralClose(text: string, idx: number): boolean {
const afterIdx = idx + CLOSING_TAG.length
- return afterIdx === text.length || text[afterIdx] === "\n" || text[afterIdx] === "\r"
+ if (afterIdx === text.length) return true
+ const nextNewline = text.indexOf("\n", afterIdx)
+ const lineEnd = nextNewline === -1 ? text.length : nextNewline
+ const between = text.slice(afterIdx, lineEnd)
+ return between.split("").every((ch) => ch === " " || ch === "\t" || ch === "\r")
}
function findLastStructuralClose(text: string): number {