""" 回复文本解析模块 负责处理 Agent 返回的原始文本,提取最终正式回复。 模型思考标记格式(按优先级检测): 1. str: """ 从 SSE 收集的完整文本中提取最终正式回复。 策略: 1. 去除 ?", "", text) # 步骤2:兼容 💭 emoji 分割(旧版格式) if "💭" in text: text = text.split("💭")[-1] # 清理前导空白 text = text.strip() # 步骤3:去重 text = _deduplicate(text) return text def _deduplicate(text: str) -> str: """ 对回复文本去重。 ADK 最后一个 SSE event 会重复发送完整内容(含思考+回复), 去除 后可能出现连续两份相同的正式回复。 支持行级和字符级去重。 """ if not text: return text # 行级去重 lines = text.split("\n") non_empty = [l for l in lines if l.strip()] if len(non_empty) > 1: mid = len(non_empty) // 2 if non_empty[:mid] == non_empty[mid:]: return "\n".join(non_empty[:mid]) for overlap_len in range(min(len(non_empty) // 2, 20), 0, -1): if non_empty[-overlap_len:] == non_empty[:overlap_len]: return "\n".join(non_empty[overlap_len:]) # 字符级去重:检查文本是否由两个相同的子串拼接而成 length = len(text) for sub_len in range(length // 2, 0, -1): if length % sub_len == 0 and text[:sub_len] * (length // sub_len) == text: return text[:sub_len] # 部分重叠:前缀和后缀相同,中间有重复 for overlap in range(min(length // 2, 500), 0, -1): if text[:overlap] == text[-overlap:]: trimmed = text[overlap:] trimmed_len = len(trimmed) for sub_len in range(trimmed_len // 2, 0, -1): if trimmed_len % sub_len == 0 and trimmed[:sub_len] * (trimmed_len // sub_len) == trimmed: return trimmed[:sub_len] return text