package captcha import ( "regexp" "strings" ) // thinkRe matches reasoning-model scratchpad blocks (… or // …). These can themselves contain JSON-looking objects, // so they are stripped before the brace scan to avoid grabbing the wrong object. var thinkRe = regexp.MustCompile(`(?s).*?`) // extractJSON returns the first balanced {...} object found in s, or s unchanged // if no opening brace is present. It scans by brace depth so prose, markdown // fences, or an example object before the real one do not corrupt parsing. // Reasoning-model … blocks are stripped first so a JSON-looking // object inside the scratchpad is not mistaken for the answer. // Note: it does not account for braces inside string literals; that is // acceptable for the short, structured captcha responses this handles. func extractJSON(s string) string { s = thinkRe.ReplaceAllString(s, "") start := strings.IndexByte(s, '{') if start < 0 { return s } depth := 0 for i := start; i < len(s); i++ { switch s[i] { case '{': depth++ case '}': depth-- if depth == 0 { return s[start : i+1] } } } return s[start:] }