fix(read_file): 截断显式告知+offset分段读——根治静默截断同类病

This commit is contained in:
ymq 2026-08-31 22:01:26 +08:00
parent 06130bcbef
commit 2d913c1d12
2 changed files with 45 additions and 17 deletions

View File

@ -985,10 +985,16 @@ class AgentExecutor:
xml = z.read('word/document.xml').decode('utf-8', errors='ignore')
texts = _re.findall(r'<w:t[^>]*>(.*?)</w:t>', xml)
return ('\n'.join(texts)[:30000]) or '(docx 无文本内容)'
# 纯文本类:直接读
# 纯文本类:直接读offset 分段 + 截断显式告知——禁止静默截断)
if ext in ('.txt', '.md', '.json', '.csv', '.py', '.log', '.yaml', '.yml', '.xml', '.html', '.ini', ''):
offset = int(p.get("offset") or 0)
with open(full, encoding="utf-8", errors="ignore") as f:
return f.read()[:30000]
full_txt = f.read()
chunk = full_txt[offset:offset + 30000]
if offset + 30000 < len(full_txt):
chunk += (f"\n\n[⚠️ 截断提示:以上为第 {offset}~{offset + len(chunk.rstrip())} 字符,"
f"全文共 {len(full_txt)} 字符。读后文请再次 read_file 并传 offset={offset + 30000}。]")
return chunk
# 其他二进制
return f"该文件是二进制格式({ext or '无扩展名'}),无法直接读取文本。可改用 run_command 处理,或让用户上传文本版本。"
except Exception as e:
@ -1285,13 +1291,18 @@ class AgentExecutor:
async with db.sqlorContext("pipeline") as sor:
# 会话级隔离web 多 tab 独立会话)
if self.session_id:
recs = await sor.sqlExe(
"SELECT role, content FROM pipeline_conversations "
"WHERE session_id=${sid}$ AND created_by=${uid}$ "
"ORDER BY created_at ASC LIMIT ${lim}$",
{"sid": self.session_id, "uid": self.user_id or "",
"lim": self.config.history_limit},
)
# 产线隔离2026-08-31 修复跨产线串扰):各产线页面默认 tab 共用
# session_id='default',历史若不按产线过滤,投标页会加载开发页的
# 对话(如"元景项目/新建demo项目"LLM 跟着最后上下文答错产线。
sql = ("SELECT role, content FROM pipeline_conversations "
"WHERE session_id=${sid}$ AND created_by=${uid}$ ")
params = {"sid": self.session_id, "uid": self.user_id or "",
"lim": self.config.history_limit}
if self.pipeline_id and not self.generic:
sql += "AND pipeline_id=${pl}$ "
params["pl"] = self.pipeline_id
sql += "ORDER BY created_at ASC LIMIT ${lim}$"
recs = await sor.sqlExe(sql, params)
else:
# 项目隔离
pid = self.project_id
@ -1349,6 +1360,7 @@ class AgentExecutor:
"created_by": self.user_id or "",
"iteration_id": self.project_id or "",
"session_id": self.session_id or "",
"pipeline_id": self.pipeline_id or "",
})
# 助手回复(不含 tool_call JSON
reply_clean = reply
@ -1361,6 +1373,7 @@ class AgentExecutor:
"created_by": self.user_id or "",
"iteration_id": self.project_id or "",
"session_id": self.session_id or "",
"pipeline_id": self.pipeline_id or "",
})
except Exception as e:
logger.warning(f"Session save failed: {e}")

View File

@ -100,27 +100,42 @@ async def get_max_task_retry(sor):
return 3
async def get_session_project_id(sor, uid, session_id=''):
async def get_session_project_id(sor, uid, session_id='', pipeline_id=''):
"""按会话解析当前项目 id。
session_id 非空时优先读 pipeline_session_settingsweb tab 各自项目上下文
无记录或表不存在时回退全局 pipeline_agent_settings.current_project_id
pipeline_id 产线隔离2026-08-31 修复跨产线串扰各产线页面默认 tab 共用
session_id='default' session/全局记录不区分产线投标页会读到开发页切换
的项目传入 pipeline_id 解析出的项目必须属于该产线sd_projects.pipeline_id
匹配才生效否则视为无记录继续回退不匹配的记录**不删除**它属于另一产线
的合法上下文
存在性校验悬空引用防护记录指向的项目若已从 sd_projects 删除
视为无效顺手清掉死记录自愈避免每次请求重复命中继续回退全局
全局也无效则返回 ''若不清理删除项目后该会话的所有项目相关入口
工作空间/任务/菜单都会被死引用遮蔽请先在会话中切换项目
"""
async def _valid(pid):
"""pid 对应项目存在则原样返回;不存在返回 '';查询异常保守放行(不因校验误伤功能)。"""
if not pid:
return ''
async def _project_pipeline(pid):
"""项目所属 pipeline_id不存在返回 None查询异常返回 ''(保守放行)。"""
try:
recs = await sor.sqlExe(
"SELECT 1 FROM sd_projects WHERE id=${p}$ LIMIT 1", {"p": pid})
return pid if recs else ''
"SELECT pipeline_id FROM sd_projects WHERE id=${p}$ LIMIT 1", {"p": pid})
if not recs:
return None
return getattr(recs[0], 'pipeline_id', '') or ''
except Exception:
return pid
return ''
async def _valid(pid):
"""pid 存在(且产线匹配,若指定)则返回 pid否则 ''"""
pl = await _project_pipeline(pid)
if pl is None:
return ''
if pipeline_id and pl and pl != pipeline_id:
return ''
return pid
if session_id:
try: