解析器内部辅助
开场解释
这个 Stage 在解决什么问题:当主循环已经拿到模型原始回复后,它要把“差一点就合法”的 XML/JSON 文本尽量救成可用结果,而不是因为一个缺标签、半截 JSON、或输出被截断就整轮失败。它的位置在解析子系统内部,属于公开解析入口后面的“修补与抢救层”。输入是上游交来的原始响应;输出是解析结果,或明确的失败结论,再加上一路累积的警告,交回外层解析边界处理。
主流程
- 先按格式做正常解析
这里的第一目标不是“聪明修”,而是先判断原始回复本身能不能直接读。 因为很多回复其实已经合法,没必要动它。 这一步的产出只有两类:
- 解析成功:直接得到结果
- 解析失败:进入下一层修补
- 失败后,先做保守的 auto-fix(自动修补)
这一层处理的是常见、低风险的小毛病。 比如:
- XML 少了外层
<response>标签 - JSON 结尾被截断,结构明显没闭合
- 一些格式相关的小修正
之所以把这层放在前面,是因为它改动小、误修风险低。 目标不是“猜作者想说什么”,而是把明显的格式瑕疵补平,让解析器再试一次。
- XML 少了外层
- 每次修补后重试,并把 warning(警告)累积起来
这里的关键不是单纯“再 parse 一遍”,而是要留下痕迹:
- 修过什么
- 为什么修
- 这次结果是否可信但有瑕疵
这就是
_combine_warnings()这一类内部 helper 存在的原因。 系统不能只返回“成功了”,还要告诉外层:这个成功是不是靠修补得来的。 这样外层后面做决策时,才知道该不该更保守地看待这份结果。 - 只有前面还失败,而且看起来是“被截断”时,才做 salvage(抢救)
salvage_truncated_response()可以理解成“最后的抢救手段”。 它不是常规路径,而是兜底路径。为什么要放在 auto-fix 之后? 因为 salvage 更激进。它面对的是输出只来了一半的情况,会尽量从残缺文本里抠出还能用的部分。 如果一上来就走这条路,很容易把本来只需小修的文本过度处理,反而引入误判。 所以顺序必须是:
- 先做保守修补
- 再做激进抢救
这样能把“救回成功率”和“误修风险”平衡住。
- XML 和 JSON 各有策略,但职责相同
这个 Stage 里同时有 XML plain parser 和 JSON plain parser 的内部 helper。 它们看起来处理细节不同,但职责是一致的:
- 找出最常见的坏格式
- 做最小修补
- 重试解析
- 记录警告
- 必要时对截断输出做最后抢救
比如 XML 会更关心顶层标签是否完整、能不能提取
<response>内容; JSON 会更关心括号、数组、对象是否收尾完整。 但从流水线视角看,它们都是“格式专属修补器”。 - 最后把结论交回外层解析边界
这个 Stage 不负责决定“整轮 run 要不要结束”“要不要重试模型”。 它只负责把内部解析结论整理好后交出去:
- 成功的结果
- 或失败结论
- 以及修补/抢救过程中累积的警告
外层再根据这个边界结果,决定后面的 loop 控制或 teardown(收尾)。
状态流动
- 读: 无可见 register-id — 输入契约是“上游交来的模型原始响应文本及其目标格式(XML/JSON)”;但本题给出的 skeleton 未提供任何真实寄存器名,无法按 Tier 2 要求把它映射成已命名 register。
- 写: 无可见 register-id — 本 Stage 会产出“解析结果 / 失败结论 + warnings”,并在内部经历“正常解析→auto-fix→重试→必要时 salvage”的顺序;但这些状态项在输入材料中没有对应的显式 register-id。
- 清: 无可见 register-id — 从给出的成员列表看,这里主要是解析器内部 helper;看不出有显式清空某个共享寄存器的动作。
- 触发下游: 无可见 register-id — 可确定的是:本 Stage 完成后,控制权返回外层解析边界;由外层决定后续 loop / teardown 行为。由于缺少寄存器与边界代码,本稿无法按本 tier 验证更细的数据流。
与前后 Stage 的衔接
上游已经结束本轮生成,把“模型原始回复”交给解析子系统;本 Stage 负责把这份原始文本尽量变成稳定的结构化结论。它产出的是“解析结果或失败状态,加上警告”,然后返回外层解析边界,由外层决定是继续控制循环、结束,还是进入 teardown。
TerminusXMLPlainParser.__init__terminus_xml_plain_parser.py:25–26 ↗
解析器实例的最小化构造入口
stage 上下文: 该条目位于 parser internal helpers stage,但就给定源码可见内容而言,此函数仅执行实例属性初始化。它无条件触发于对象构造时,且本 unit 是该 stage 当前唯一已翻译条目,因此不存在可对照的兄弟实现。
这段代码在干什么
__init__(self) 只接收实例自身 self。函数体仅把 self.required_sections 赋值为新列表 ["analysis", "plan", "commands"],随后隐式返回 None。除此之外,它不读取现有实例状态,也不调用其他函数。
接口 · 参数 / IO
(self)
- 参数:
self:?— 当前TerminusXMLPlainParser实例 - 返回: 隐式返回
None;实际产出是把属性self.required_sections写成新列表["analysis", "plan", "commands"] - 副作用: 写入属性
self.required_sections为["analysis", "plan", "commands"]
执行流
- 进入
__init__(self)。 - 执行一次属性赋值:将
self.required_sections设为字面量列表["analysis", "plan", "commands"]。 - 函数结束,并隐式返回
None。
源码
def __init__(self):
self.required_sections = ["analysis", "plan", "commands"]
Non-obvious 设计决策
- 源码可直接观察到,
required_sections的内容采用硬编码字面量,并且顺序固定为analysis、plan、commands。除此之外,给定代码未显式呈现其他可证实的设计取舍。
上下游关系
- 调用方: 对象构造路径(具体调用方未在给定源码中出现)
- 核心被调用: 无:函数体中没有显式函数调用
- 配置/状态来源: 无:未读取参数以外的任何配置或实例状态; 代码内字面量列表
["analysis", "plan", "commands"] - 结果去向: 实例属性
self.required_sections
TerminusXMLPlainParser._get_auto_fixesterminus_xml_plain_parser.py:171–178 ↗
生成自动修复候选列表的辅助函数
stage 上下文: 该函数位于 parser 子系统内部辅助层,职责是把当前可用的自动修复项整理成返回值,而不直接执行修复。相较同 stage 中仅做初始化赋值的
__init__,这里同样保持极小职责范围:读取一个实例方法引用并构造固定列表。
这段代码在干什么
_get_auto_fixes(self) 不接收除 self 外的任何输入。函数体直接返回一个新列表,列表当前只有一个二元组:提示文本 "Missing </response> tag was automatically inserted" 与方法引用 self._fix_missing_response_tag。该过程不写入任何实例状态,也没有外部副作用。
接口 · 参数 / IO
(self)
- 参数:
self:?— 解析器实例,提供_fix_missing_response_tag方法引用 - 读状态:
self._fix_missing_response_tag - 返回: 返回一个新列表,当前实现的精确内容为
[("Missing </response> tag was automatically inserted", self._fix_missing_response_tag)]。
执行流
- 进入函数后,不进行条件判断、循环或异常处理。
- 构造并返回一个列表字面量;该列表当前只包含一个二元组。
- 该二元组的第一个元素是固定说明字符串
"Missing </response> tag was automatically inserted"。 - 该二元组的第二个元素是当前实例上的方法引用
self._fix_missing_response_tag。
源码
def _get_auto_fixes(self):
"""Return list of auto-fix functions to try in order."""
return [
(
"Missing </response> tag was automatically inserted",
self._fix_missing_response_tag,
),
]
Non-obvious 设计决策
- 返回值采用“说明文本 + 修复函数”的二元组结构;这一点可由列表中的单个 tuple 直接定位到代码。
- 修复项被放在列表中而非单独返回函数引用,因此候选项的顺序由列表位置编码;当前实现中列表只有一个元素。
- 函数本身只负责暴露候选集合,不在此处调用
self._fix_missing_response_tag,从而把“列出候选项”和“执行修复”分离。
上下游关系
- 调用方: 未知:该片段自身未显示调用方
- 核心被调用: 无直接调用;仅返回方法引用
self._fix_missing_response_tag而不执行它 - 配置/状态来源: self._fix_missing_response_tag 方法属性; 函数体内硬编码字符串
"Missing </response> tag was automatically inserted" - 结果去向: 直接返回给本函数调用者; 返回值中的第二项携带
self._fix_missing_response_tag供调用者后续使用 - 同类 sibling: 与同 stage 的
TerminusXMLPlainParser.__init__一样都很短小;__init__只做实例字段初始化,而本函数只组装并返回固定候选列表。
TerminusXMLPlainParser._fix_missing_response_tagterminus_xml_plain_parser.py:187–194 ↗
补齐 response 结束标签的窄修复器
stage 上下文: 该条目位于 parser 内部辅助函数集合中,职责是对一类非常具体的字符串错误进行本地修补。它与同阶段的
__init__、_get_auto_fixes不同,不配置实例状态,也不组织修复列表;这里只根据传入的response与error计算返回值。
这段代码在干什么
_fix_missing_response_tag(self, response, error) 只检查 error 是否包含固定子串 "Missing </response> closing tag"。若不包含,则原样返回 response 与 False;若包含,则返回 response.rstrip() + "\n</response>" 与 True。函数不读取任何 self 属性,self 在函数体内实际未被使用,也没有副作用。
接口 · 参数 / IO
(self, response: str, error: str) -> tuple[str, bool]
- 参数:
self:?— 实例引用;在该函数体内未被使用;response:str— 待处理的原始响应文本;在命中修复条件时作为拼接基础;error:str— 错误描述字符串;仅通过子串包含判断决定是否执行修复 - 返回: 二元组
(str, bool):若error不含"Missing </response> closing tag",返回(response, False);若包含,则返回(response.rstrip() + "\n</response>", True)。
执行流
- 先对参数
error做一次子串包含判断:检查其中是否出现固定文本"Missing </response> closing tag"。 - 若判断失败,立即返回原始
response与布尔值False,表示本次未做任何修正。 - 若判断成立,先计算
corrected = response.rstrip() + "\n</response>",即去掉response末尾空白后补上一行关闭标签。 - 最后返回
corrected与布尔值True,把修正后的文本交还调用方。
源码
def _fix_missing_response_tag(self, response: str, error: str) -> tuple[str, bool]:
"""Fix missing </response> closing tag by appending it."""
if "Missing </response> closing tag" not in error:
return response, False
# Simply append </response> at the end
corrected = response.rstrip() + "\n</response>"
return corrected, True
Non-obvious 设计决策
- 修复触发条件被收窄为对
error固定子串的精确包含判断,而不是对response内容做更宽松的猜测式修补;从代码可见,这一选择限制了函数只处理一种已知错误形态。 - 在补标签前先调用
response.rstrip(),说明实现刻意去除尾随空白后再追加"\n</response>";这样可避免把关闭标签插在一串末尾空白之后。 - 返回值显式携带布尔标记
True/False,而不是仅返回字符串;从接口形状可见,调用方可以直接区分“未改动的原文返回”与“已生成修正文”。
上下游关系
- 调用方: 外部调用方可传入
response与error请求一次缺失结束标签修复 - 核心被调用: str.__contains__:用于判断
error是否包含固定错误文本; str.rstrip:用于去除response末尾空白 - 配置/状态来源: 无实例配置或
self状态输入;全部判断依据均来自形参response与error - 结果去向: 返回给调用方一个
(文本, 是否已修复)二元组 - 同类 sibling: TerminusXMLPlainParser.__init__:只初始化
self.required_sections,而本函数完全不接触实例状态。; TerminusXMLPlainParser._get_auto_fixes:返回修复项列表;本函数本身只实现其中一个具体修复动作。
TerminusXMLPlainParser._combine_warningsterminus_xml_plain_parser.py:180–185 ↗
警告文本拼接格式化助手
stage 上下文: 该条目对应解析器内部的一个极小型字符串整理辅助函数。它本身不处理解析状态,只负责把一条新警告按固定格式并入已有警告文本。与同 stage 中直接返回固定列表或按条件修补字符串的兄弟函数一样,这里也不读取实例内部字段。
这段代码在干什么
_combine_warnings(self, auto_warning, existing_warning) 接收两段警告文本,返回一段新的组合结果。若 existing_warning 为真值,则返回 f"- {auto_warning}\n{existing_warning}";若其为假值,则返回 f"- {auto_warning}"。函数不读取 self 上的任何属性,也不产生副作用。
接口 · 参数 / IO
(self, auto_warning: str, existing_warning: str) -> str
- 参数:
self:?— 实例自身;在函数体内未被使用;auto_warning:str— 将被格式化为前导项目符号行的新警告文本;existing_warning:str— 已有警告文本;其真值性决定是否追加换行并保留原文本 - 返回: 返回组合后的警告字符串:
existing_warning为真值时插入一个前导-和一个换行后接上原文本;为假值时仅返回- {auto_warning}。
执行流
- 先对参数
existing_warning做真值判断。 - 若
existing_warning为真值,则生成并返回f"- {auto_warning}\n{existing_warning}",即把新警告写成带-前缀的首行,并用一个换行连接旧文本。 - 若
existing_warning为假值,则直接返回f"- {auto_warning}",不附加换行,也不拼接旧文本。
源码
def _combine_warnings(self, auto_warning: str, existing_warning: str) -> str:
"""Combine auto-correction warning with existing warnings."""
if existing_warning:
return f"- {auto_warning}\n{existing_warning}"
else:
return f"- {auto_warning}"
Non-obvious 设计决策
- 新警告始终放在返回字符串的最前面;这从两个分支都以
- {auto_warning}起始可以直接看出,而不是把新内容追加到旧文本尾部。 - 只有在
existing_warning为真值时才插入换行;这样可避免在没有可接续文本时产生多余的尾随分隔符。
上下游关系
- 调用方: 未知;该函数源码片段未展示调用点
- 核心被调用: 无;函数体未调用其他函数
- 配置/状态来源: 参数
auto_warning; 参数existing_warning - 结果去向: 直接作为返回值交还给调用方; 返回结果内容取决于
existing_warning的真值性分支 - 同类 sibling: 同 stage 的
__init__直接设置固定实例字段;本函数则完全不接触实例状态。; 同 stage 的_get_auto_fixes直接返回固定列表;本函数改为依据参数真值性返回两种字符串之一。; 同 stage 的_fix_missing_response_tag也是条件分支后返回字符串与布尔值;本函数同样是纯函数式返回,但只产出字符串。
TerminusXMLPlainParser._extract_response_contentterminus_xml_plain_parser.py:225–236 ↗
提取 response 包裹内容的字符串助手
stage 上下文: 该条目位于 parser 内部辅助函数分组中,职责是对单个字符串做局部内容抽取。就函数体可见信息而言,它不依赖实例状态,也不像 XML 解析器那样解释结构;同组已知兄弟函数也多为这类短小、无副作用的字符串处理或修复助手。
这段代码在干什么
_extract_response_content(self, response: str) -> str 在输入字符串 response 中查找字面量 <response> 与 </response>,并返回两者之间、或从起始标签到字符串末尾的子串,再对结果执行 .strip()。若找不到起始标签,则直接返回空字符串 ""。整个过程不读取任何 self 属性,也不写入状态或产生外部副作用。它使用普通字符串搜索与切片,而不是 XML 解析,因此不验证标签结构、嵌套或配对正确性。
接口 · 参数 / IO
(self, response: str) -> str
- 参数:
self:?— 实例自身;本函数体内未使用;response:str— 待搜索的输入字符串 - 返回: 返回字符串结果:若不存在
"<response>",返回空字符串;若存在起始标签但不存在"</response>",返回从起始标签之后到字符串末尾的切片并.strip();若两个标签都存在,返回两标签之间的切片并.strip()。
执行流
- 先在
response上用response.find("<response>")查找起始标签位置,结果保存到start_pos。 - 若
start_pos == -1,说明输入中没有字面量<response>,函数立即返回空字符串""。 - 若找到起始标签,再从
start_pos开始用response.find("</response>", start_pos)查找结束标签位置,结果保存到end_pos。 - 若
end_pos == -1,则截取response[start_pos + len("<response>") :],并对该子串调用.strip()后返回。 - 若结束标签存在,则截取
response[start_pos + len("<response>") : end_pos],并对该子串调用.strip()后返回。
源码
def _extract_response_content(self, response: str) -> str:
"""Extract content from <response> tags."""
start_pos = response.find("<response>")
if start_pos == -1:
return ""
end_pos = response.find("</response>", start_pos)
if end_pos == -1:
# Missing closing tag - return content from opening tag to end
return response[start_pos + len("<response>") :].strip()
return response[start_pos + len("<response>") : end_pos].strip()
Non-obvious 设计决策
- 实现选择了
str.find与切片,而非 XML 解析 API;这样可在极简成本下完成固定标签的内容提取,但相应地不会校验标签是否合法、不会处理嵌套,也不做标签平衡判断。 - 函数把缺失结束标签视为可接受情形:当
end_pos == -1时仍返回从起始标签后到字符串末尾的内容,而不是报错或返回空值。这体现出对不完整文本输入的容忍策略。 - 两条成功返回路径都统一执行
.strip(),说明该函数有意去除提取片段首尾空白,使调用方获得规整化文本,而不是保留原始边界空格与换行。
上下游关系
- 调用方: 未在本函数源码中直接体现具体调用者; 任何需要从普通字符串中抽取
<response>...</response>包裹内容的同类内部逻辑 - 核心被调用: response.find; len; str.strip
- 配置/状态来源: 无配置来源;行为仅由字面量标签
"<response>"与"</response>"决定 - 结果去向: 返回给直接调用方作为提取后的纯字符串内容; 在未找到起始标签时向调用方提供空字符串哨兵值; 在缺失结束标签时向调用方提供宽容截取后的字符串结果
- 同类 sibling: TerminusXMLPlainParser.__init__:同样是短小实现,但该函数只初始化
required_sections,而本函数只做字符串提取。; TerminusXMLPlainParser._fix_missing_response_tag:两者都围绕response标签文本处理;该兄弟负责修补缺失结束标签,本函数则在缺失结束标签时直接截到末尾。; TerminusXMLPlainParser._combine_warnings:同属无状态、无副作用的纯字符串加工助手。
TerminusXMLPlainParser._find_top_level_tagsterminus_xml_plain_parser.py:393–440 ↗
扫描字符串顶层标签名的辅助函数
stage 上下文: 该函数属于解析子系统内部辅助例程,职责仅限于对给定字符串做局部标签扫描并产出标签名列表。它与同组里
_extract_response_content这类字符串级辅助函数相似,都不依赖实例状态;相比_combine_warnings之类纯拼接逻辑,本函数额外维护一个局部depth计数来区分当前是否处于零层级。
这段代码在干什么
_find_top_level_tags(self, content: str) -> List[str] 顺序扫描输入字符串 content,收集所有在当前扫描深度 depth == 0 时遇到的、非闭合标签的标签名,并按出现顺序返回。它跳过标签内容以 ! 或 ? 开头的片段,遇到闭合标签时只做 depth -= 1,遇到找不到配对 > 的起始 < 时直接停止扫描。函数不读取任何 self 属性,也不写入实例或外部状态。
接口 · 参数 / IO
(self, content: str) -> List[str]
- 参数:
self:?— 实例自身;在函数体内未被读取;content:str— 被逐字符扫描的输入字符串,标签发现与层级判断均基于它 - 返回: 返回
List[str]:扫描过程中在depth == 0时遇到的非闭合标签名,保持原始出现顺序。标签名提取规则是:若标签内容含空格则取split()[0],否则取整个标签内容;之后若结果以/结尾再去掉该尾随/。由于闭合标签会无条件令depth减一,畸形输入可能使depth变成负数,从而影响后续哪些标签会被计为“顶层”。
执行流
- 初始化局部列表
top_level_tags = []、层级计数depth = 0和扫描下标i = 0,随后用while i < len(content)逐字符推进整个字符串。 - 当
content[i]不是<时,仅把i加一并继续;当遇到<时,用content.find(">", i)查找本次标签的结束位置。若未找到>(得到-1),立即break,后续内容不再处理。 - 取出
tag_content = content[i + 1 : tag_end]作为尖括号内文本。若它以!或?开头,则直接把i移到tag_end + 1并跳过,不参与层级与结果列表处理。 - 若
tag_content以/开头,则把它视为闭合标签,只执行depth -= 1,然后把i移到tag_end + 1继续;这里不校验名称是否匹配,也不阻止depth变成负数。 - 对于其余标签,先用
tag_content.endswith("/")判断是否为自闭合标签,再按“有空格取首词,否则取整体”的规则得到tag_name;若tag_name末尾仍有/,再去掉这个尾随字符。 - 在任何深度调整之前,先检查当前
depth == 0;若成立,就把tag_name追加进top_level_tags。之后仅当该标签不是自闭合时才执行depth += 1,最后把i移到tag_end + 1。 - 循环结束后返回
top_level_tags。
源码
def _find_top_level_tags(self, content: str) -> List[str]:
"""Find all top-level XML tags (direct children of response), not
nested tags."""
top_level_tags = []
depth = 0
i = 0
while i < len(content):
if content[i] == "<":
# Find the end of this tag
tag_end = content.find(">", i)
if tag_end == -1:
break
tag_content = content[i + 1 : tag_end]
# Skip comments, CDATA, etc.
if tag_content.startswith("!") or tag_content.startswith("?"):
i = tag_end + 1
continue
# Check if this is a closing tag
if tag_content.startswith("/"):
depth -= 1
i = tag_end + 1
continue
# Check if this is a self-closing tag
is_self_closing = tag_content.endswith("/")
# Extract tag name (first word)
tag_name = tag_content.split()[0] if " " in tag_content else tag_content
if tag_name.endswith("/"):
tag_name = tag_name[:-1]
# If we're at depth 0, this is a top-level tag
if depth == 0:
top_level_tags.append(tag_name)
# Adjust depth for opening tags (but not self-closing)
if not is_self_closing:
depth += 1
i = tag_end + 1
else:
i += 1
return top_level_tags
Non-obvious 设计决策
- 该实现采用字符串扫描与局部层级计数,而不是正式 XML 解析器:代码只依赖
<、>、前导/与尾随/等表面标记即可工作,因此实现短小,但也只提供语法层面的近似判断。 - 对以
!或?开头的标签内容采取整段跳过策略,这是代码里唯一显式排除的特殊标签类别;它不再细分这些内容的内部结构,取舍点是简化处理分支。 - “是否记为顶层”发生在打开标签的
depth += 1之前,因此某个非闭合标签会以其进入前的层级来分类;这保证了零层级处的开始标签会被记录,而其内部嵌套内容不会因随后增深而倒置判断。 - 闭合标签路径只做
depth -= 1而不验证合法性,意味着不匹配或多余的闭合标签会把depth拉成负数;该取舍降低了容错处理复杂度,但后续顶层判定会受此状态偏移影响。 - 遇到没有后续
>的<时直接终止扫描,而不是把它当普通字符继续搜索;这一策略避免在不完整标签后继续做可能失真的解析。
上下游关系
- 调用方: 未在给定源码片段中展示调用方; 外部调用关系无法仅凭此函数体确定
- 核心被调用: 字符串方法
content.find(">", i):定位当前标签结束位置; 字符串方法tag_content.startswith("!"):跳过前导!的标签片段; 字符串方法tag_content.startswith("?"):跳过前导?的标签片段; 字符串方法tag_content.startswith("/"):识别闭合标签; 字符串方法tag_content.endswith("/"):识别自闭合标签; 字符串方法tag_content.split():在存在空格时提取首词作为标签名; 列表方法top_level_tags.append(tag_name):记录零深度遇到的标签名 - 配置/状态来源: 无:函数体不读取任何
self属性; 无:函数体不访问任何 register 或外部配置 - 结果去向: 返回给直接调用者的
List[str]结果; 结果仅通过返回值对外暴露,不写入实例状态 - 同类 sibling: 同组的
TerminusXMLPlainParser._extract_response_content也是纯字符串处理辅助函数,但它做固定边界切片;本函数则做逐字符扫描与层级分类。; 同组的TerminusXMLPlainParser._combine_warnings只组合文本,不维护扫描状态;本函数通过局部变量depth表达嵌套层级。
TerminusJSONPlainParser.__init__terminus_json_plain_parser.py:26–27 ↗
JSON/plain 解析器构造初始化
stage 上下文: 该条目对应解析器内部辅助类的构造函数。就源码可见事实而言,它仅在实例初始化时写入一项实例属性;未展示任何进一步解析逻辑,也未与同 stage 其他辅助函数发生可见交互。
这段代码在干什么
__init__(self) 只接收实例自身 self。函数体将 self.required_fields 直接赋值为一个新的列表字面量 ["analysis", "plan", "commands"],随后隐式返回 None。除这次属性写入外,源码中没有其他状态读取、函数调用或外部副作用。
接口 · 参数 / IO
(self)
- 参数:
self:?— 当前解析器实例 - 返回: 隐式返回 None;实际产出是把
self.required_fields设为新的列表字面量 - 副作用: 写入
self.required_fields
执行流
- 接收参数
self,不读取其他输入。 - 将
self.required_fields赋值为新列表["analysis", "plan", "commands"]。 - 函数结束并隐式返回
None。
源码
def __init__(self):
self.required_fields = ["analysis", "plan", "commands"]
Non-obvious 设计决策
- 构造时直接使用硬编码列表字面量,而不是从参数或其他状态推导其值。
- 赋值采用覆盖写入
self.required_fields的方式;每次调用都会放入一个新的列表对象。
上下游关系
- 调用方: 源码片段未展示
- 核心被调用: 无
- 配置/状态来源: 无;仅使用函数体内列表字面量
- 结果去向:
self.required_fields
TerminusJSONPlainParser._get_auto_fixesterminus_json_plain_parser.py:305–313 ↗
JSON 解析器的自动修复表构造器
stage 上下文: 该函数属于 parser 子系统内部辅助逻辑,职责是在 JSON/plain 解析失败后的修复阶段提供候选策略表。它本身不执行修复,只把可尝试的修复器按顺序组织出来。与同 stage 中 XML 版本的
_get_auto_fixes相对应,这里返回的是 JSON/plain 专用的两条修复项。
这段代码在干什么
_get_auto_fixes(self) 接收 TerminusJSONPlainParser 实例自身 self,返回一个新的列表字面量。列表中固定包含两个二元组:说明文本与对应的绑定方法引用,分别是 self._fix_incomplete_json 和 self._fix_mixed_content。函数体内不调用这些方法,也不写入任何实例状态或外部状态。
接口 · 参数 / IO
(self)
- 参数:
self:?— 当前TerminusJSONPlainParser实例;用于读取修复器方法属性并生成返回表 - 读状态:
self._fix_incomplete_json,self._fix_mixed_content - 返回: 返回一个新列表,包含两个
(description, fixer_callable)二元组:("Fixed incomplete JSON by adding missing closing brace", self._fix_incomplete_json)与("Extracted JSON from mixed content", self._fix_mixed_content);其中 callable 以绑定方法引用形式返回,未在本函数内执行。
执行流
- 构造并准备返回一个新的列表字面量,作为自动修复策略表。
- 在第一个元素中放入说明文本
"Fixed incomplete JSON by adding missing closing brace",并通过属性读取取得绑定方法引用self._fix_incomplete_json;该方法在此处仅被返回,不被调用。 - 在第二个元素中放入说明文本
"Extracted JSON from mixed content",并通过属性读取取得绑定方法引用self._fix_mixed_content;同样仅返回引用,不在此处执行。 - 将上述两项按源码中的既定顺序整体返回。
源码
def _get_auto_fixes(self):
"""Return list of auto-fix functions to try in order."""
return [
(
"Fixed incomplete JSON by adding missing closing brace",
self._fix_incomplete_json,
),
("Extracted JSON from mixed content", self._fix_mixed_content),
]
Non-obvious 设计决策
- 函数把“说明文本 + 修复器”成对返回,而不是只返回 callable,这一设计使每个修复策略都自带可读诊断标签;这一点可直接从两个二元组的结构看出。
- 返回顺序被硬编码在列表字面量中,说明策略次序是显式的解析器政策,而不是无序集合或动态发现结果。
- 源码使用
return [ ... ]直接返回列表字面量,意味着每次调用都会产生一个新的列表容器,而不是复用先前保存的列表对象。
上下游关系
- 调用方: TerminusJSONPlainParser.parse_response
- 核心被调用: self._fix_incomplete_json(作为返回的绑定方法引用读取,不在此处调用); self._fix_mixed_content(作为返回的绑定方法引用读取,不在此处调用)
- 配置/状态来源: 无外部配置输入;
self._fix_incomplete_json属性查找;self._fix_mixed_content属性查找 - 结果去向: 返回给
TerminusJSONPlainParser.parse_response; 作为后续自动修复尝试的候选策略表; 为每个修复器提供对应的人类可读说明文本 - 同类 sibling: 与
TerminusXMLPlainParser._get_auto_fixes同属“返回有序自动修复表”的兄弟函数,但该函数返回的是 JSON/plain 路径下的两条修复项。; 与TerminusJSONPlainParser.__init__相比,本函数不设置self.required_fields一类实例字段,只读取两个方法属性来组装返回值。
TerminusJSONPlainParser._fix_incomplete_jsonterminus_json_plain_parser.py:315–328 ↗
JSON 截断响应的局部补全助手
stage 上下文: 该单元位于 parser 内部辅助层,职责仅限于对单次 JSON 修复尝试做局部判断与改写。就源码可见事实而言,它不访问解析器实例状态,只基于
response与error两个入参决定是否补上缺失的}。与同 stage 中若干兄弟函数一致,这里也采用“返回修复后文本与是否修复成功”的纯函数式接口,不在函数内持久化任何状态。
这段代码在干什么
_fix_incomplete_json(self, response: str, error: str) -> tuple[str, bool] 检查错误文本 error 是否包含四类固定提示之一:"Invalid JSON"、"Expecting"、"Unterminated"、"No valid JSON found"。只有在这些条件之一成立,且 response.count("{") - response.count("}") 大于 0 时,函数才会在原始 response 末尾追加对应数量的右花括号 },并返回 (fixed, True);其余情况都原样返回 (response, False)。函数不读取任何 self 属性,也没有实例状态或外部副作用。
接口 · 参数 / IO
(self, response: str, error: str) -> tuple[str, bool]
- 参数:
self:TerminusJSONPlainParser— 实例自身;在该函数体内未被读取;response:str— 待检查并可能补全的原始响应字符串;error:str— 上游提供的错误描述文本,用于决定是否进入补全分支 - 返回: 返回二元组
(文本, 是否已修复):仅当error含四个支持子串之一,且response.count('{') - response.count('}') > 0时,返回在原字符串末尾补足}后的新字符串与True;否则返回原始response与False。
执行流
- 先对入参
error做四个固定子串的包含判断:"Invalid JSON"、"Expecting"、"Unterminated"、"No valid JSON found";若全部不匹配,则直接走到底部返回(response, False)。 - 只有在上述错误门槛命中时,才计算
brace_count = response.count("{") - response.count("}"),即当前文本中未闭合左花括号的净数量。 - 若
brace_count > 0,则构造fixed = response + "}" * brace_count,把同样数量的右花括号追加到字符串末尾,并立即返回(fixed, True)。 - 若错误门槛虽然命中,但
brace_count <= 0,函数不会做任何修改,最终仍返回(response, False)。
源码
def _fix_incomplete_json(self, response: str, error: str) -> tuple[str, bool]:
"""Fix incomplete JSON by adding missing closing braces."""
if (
"Invalid JSON" in error
or "Expecting" in error
or "Unterminated" in error
or "No valid JSON found" in error
):
# Try adding closing braces
brace_count = response.count("{") - response.count("}")
if brace_count > 0:
fixed = response + "}" * brace_count
return fixed, True
return response, False
Non-obvious 设计决策
- 代码把修复尝试严格限制在四种错误文本模式之内,而不是对所有解析失败都补花括号;这一约束直接体现在开头的
if (... in error or ...)条件上。 - 即使错误文本命中,函数也只有在
response中左花括号数量多于右花括号数量时才改写输出;这表明“错误提示匹配”只是必要条件,不是充分条件。 - 修复范围只涉及花括号平衡:源码只统计
{与},并仅追加},不尝试补引号、方括号、逗号或其他 JSON 结构。相较更宽泛的改写,这里的行为边界更容易从返回条件直接判定。
上下游关系
- 调用方: 未在该源码片段中显式出现
- 核心被调用: error.__contains__(通过
"..." in error触发的字符串包含判断); response.count; str.__mul__("}" * brace_count); str.__add__(response + ...) - 配置/状态来源: 参数
response; 参数error - 结果去向: 返回给本函数的直接调用方,形式为
(possibly_fixed_response, did_fix) - 同类 sibling: 同为
TerminusJSONPlainParser的内部辅助函数;与已翻译的__init__、_get_auto_fixes一样,本函数本体不修改解析器持久状态。
TerminusJSONPlainParser._combine_warningsterminus_json_plain_parser.py:345–350 ↗
警告文本拼接格式化辅助函数
stage 上下文: 该函数在本 stage 中承担极小粒度的字符串组合职责:把
auto_warning按固定项目符号格式并入existing_warning。从函数体可见,它只做一次对existing_warning真值性的分支判断,不读取任何解析器实例状态。与同类辅助函数一致,这里返回新字符串而非修改对象内部字段。
这段代码在干什么
_combine_warnings(self, auto_warning, existing_warning) 接收两段字符串输入,并返回一段新的警告文本。若 existing_warning 为真值,返回值精确为 "- {auto_warning}\n{existing_warning}";若其为假值,返回值精确为 "- {auto_warning}"。函数体不读取 self 上的任何属性,也不写入实例或外部状态。
接口 · 参数 / IO
(self, auto_warning: str, existing_warning: str) -> str
- 参数:
self:?— 实例自身;在函数体内未被读取;auto_warning:str— 将被格式化为前导-项的警告文本;existing_warning:str— 用于真值判断;若为真值则作为后续文本原样拼接 - 返回: 返回一个新构造的警告字符串:要么是仅含
- {auto_warning}的单行文本,要么是在其后追加换行和existing_warning的两段文本。
执行流
- 接收
auto_warning与existing_warning两个参数,并进入if existing_warning的真值判断分支。 - 当
existing_warning为真值时,返回格式为- {auto_warning}开头、后接换行与existing_warning原文的新字符串。 - 当
existing_warning为假值时,返回只包含- {auto_warning}的新字符串,不追加换行或其他内容。
源码
def _combine_warnings(self, auto_warning: str, existing_warning: str) -> str:
"""Combine auto-correction warning with existing warnings."""
if existing_warning:
return f"- {auto_warning}\n{existing_warning}"
else:
return f"- {auto_warning}"
Non-obvious 设计决策
- 分支条件使用的是
if existing_warning真值判断,而不是显式比较空字符串;可观察结果是所有假值输入都会走同一路径。 - 当存在
existing_warning时,函数把新条目放在返回字符串的第一行,且对existing_warning不做重新加前缀、拆行或标准化处理,只是原样接在换行之后。 - 函数通过直接返回格式化结果完成工作,不在
self上缓存中间结果;其直接后果是调用方若需保留组合后的文本,必须接收返回值。
上下游关系
- 调用方: 未在给定源码片段中出现; 需由外层调用方传入
auto_warning与existing_warning - 核心被调用: 无显式函数调用; 仅使用 f-string 构造返回字符串
- 配置/状态来源: 参数
auto_warning; 参数existing_warning - 结果去向: 直接作为函数返回值返回给调用方; 返回结果内容完全由两个入参决定
- 同类 sibling: 同 stage 的
TerminusXMLPlainParser._combine_warnings采用相同的二分支返回结构:有现有文本时前置新条目并追加换行,否则只返回单条项目符号文本。
TerminusXMLPlainParser.salvage_truncated_responseterminus_xml_plain_parser.py:528–580 ↗
截断回复的保守式补救判定器
stage 上下文: 该条目位于 parser 内部辅助层,源码只体现它对一段
truncated_response做一次最佳努力的补救判定。它先从字符串中寻找完整的</commands>与后续</response>边界,再把截出的片段交给self.parse_response(clean_response)复验;若结构不完整、复验报错、出现特定多块警告,或解析抛出异常,则直接放弃补救。
这段代码在干什么
salvage_truncated_response 接收一段可能被截断的响应文本 truncated_response,尝试从中截出一个以 </response> 结束的完整片段,并判断该片段是否可作为有效回复返回。它依赖 self.parse_response(clean_response) 的结果对象中的 warning 与 error 字段来决定输出。返回值是 (salvaged_response, has_multiple_blocks):成功时返回清理后的字符串与 False,失败时返回 None,并在识别出特定“只能一次发一个块”的警告时把第二项置为 True。函数本身不写入实例状态,也无外部副作用。
接口 · 参数 / IO
(self, truncated_response: str) -> tuple[str | None, bool]
- 参数:
self:?— 解析器实例;函数通过self.parse_response(clean_response)复验截出的片段,并依据返回对象的warning/error字段决定是否补救成功;truncated_response:str— 可能被截断的原始回复文本,作为字符串搜索与切片的输入 - 读状态:
可调用成员self.parse_response`,self.parse_response(clean_response)返回对象的warning字段,self.parse_response(clean_response)返回对象的error字段` - 返回: 返回二元组
(salvaged_response, has_multiple_blocks)。当文本中能找到</commands>与其后的</response>,且self.parse_response(clean_response)未给出error、也未触发特定多块警告时,返回(clean_response, False);其余情况下返回(None, has_multiple_blocks_or_False)。
执行流
- 先在
truncated_response中查找"</commands>";若commands_end == -1,立即返回(None, False),不再尝试后续补救。 - 若找到
</commands>,再从该位置之后查找"</response>";若response_end == -1,同样立即返回(None, False)。 - 当两个闭合标签都存在时,以
response_end + len("</response>")为边界切出clean_response,即只保留到完整</response>结束的前缀。 - 在
try块内调用self.parse_response(clean_response)得到parse_result,随后把has_multiple_blocks初始化为False。 - 若
parse_result.warning为真值,则先转成小写warning_lower,并仅在同时包含"only issue one"与"block at a time"这两个子串时,把has_multiple_blocks设为True。 - 若
parse_result.error为假值且has_multiple_blocks仍为False,则把当前clean_response视为可用结果,返回(clean_response, False)。 - 否则,若存在解析错误或识别出多块警告,则放弃补救,返回
(None, has_multiple_blocks)。 - 若
self.parse_response(clean_response)或后续字段访问在try中抛出任意异常,except Exception会统一吞掉异常并返回(None, False)。
源码
def salvage_truncated_response(
self, truncated_response: str
) -> tuple[str | None, bool]:
"""
Try to salvage a valid response from truncated output.
Args:
truncated_response: The truncated response from the LLM
Returns:
Tuple of (salvaged_response, has_multiple_blocks)
- salvaged_response: Clean response up to </response> if salvageable, "
"None otherwise
- has_multiple_blocks: True if multiple response/commands blocks "
"were detected
"""
# Check if we can find a complete response structure
commands_end = truncated_response.find("</commands>")
if commands_end == -1:
return None, False
# Find the </response> tag after </commands>
response_end = truncated_response.find("</response>", commands_end)
if response_end == -1:
return None, False
# We have a complete response up to at least </commands>
# Truncate cleanly at </response>
clean_response = truncated_response[: response_end + len("</response>")]
# Check if this is a valid response with no critical issues
try:
parse_result = self.parse_response(clean_response)
# Check if there are no errors and no "multiple blocks" warnings
has_multiple_blocks = False
if parse_result.warning:
warning_lower = parse_result.warning.lower()
has_multiple_blocks = (
"only issue one" in warning_lower
and "block at a time" in warning_lower
)
if not parse_result.error and not has_multiple_blocks:
# Valid response! Return the clean truncated version
return clean_response, False
else:
# Has errors or multiple blocks
return None, has_multiple_blocks
except Exception:
# If parsing fails, not salvageable
return None, False
Non-obvious 设计决策
- 函数把“是否值得尝试补救”前置为两个显式闭合标签检查:缺少
</commands>或缺少其后的</response>时直接失败。这意味着它只接受源码中可定位到完整结束边界的片段,不对更模糊的不完整文本做猜测性修复。 - 即使已经通过字符串搜索得到
clean_response,代码仍强制再走一次self.parse_response(clean_response)。这里的取舍是:闭合标签齐全并不足以证明内容有效,真正的通过条件还取决于parse_result.error为空且未触发特定警告。 - 多块判定并不是把任意
warning都视为失败,而是只匹配小写化后同时含有"only issue one"与"block at a time"的警告文本。这个选择把失败条件收窄到一个特定告警模式,其它警告不会单独导致has_multiple_blocks=True。 - 成功返回时固定输出
(clean_response, False),即便此前计算过has_multiple_blocks变量;只有在失败分支中才可能把第二项作为True返回。代码由此把“补救成功”与“检测到多块”设为互斥结果。 - 异常处理采用宽泛的
except Exception并统一降级为(None, False)。直接后果是:任何解析器异常都会被当作“不可补救”而非继续传播,从接口上维持一个纯返回值式的失败信号。
上下游关系
- 调用方: 源码片段未提供,无法从该函数体直接确认调用方
- 核心被调用:
self.parse_response(clean_response);truncated_response.find("</commands>");truncated_response.find("</response>", commands_end);parse_result.warning.lower() - 配置/状态来源:
truncated_response的字符串内容决定两个闭合标签是否存在以及clean_response的截断边界;self.parse_response的可调用行为决定复验是否成功或是否抛出异常;parse_result.warning的文本内容决定是否把结果标记为多块;parse_result.error的真值决定是否接受clean_response - 结果去向: 直接作为本函数返回值输出给其调用者:
(clean_response, False); 直接作为本函数返回值输出给其调用者:(None, False); 直接作为本函数返回值输出给其调用者:(None, True)