mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 04:31:58 +00:00
表助手的背景在宽表上不至于太长:这张表的目录最多列 600 项(表级的项、关联关系在前),其余写明还有几项没列出;导入时界面直接交来的文件原文(JSON 文字)也认,不是 JSON 的 422;导入冲突说明里的状态用界面的叫法
This commit is contained in:
@@ -79,9 +79,11 @@ TOOL_CHARS = 12_000
|
||||
RETRY_DELAYS_S = (3.0, 10.0)
|
||||
#: 等模型的时候每隔几秒发一行 SSE 注释
|
||||
HEARTBEAT_S = 10.0
|
||||
#: 背景里「目录里还没有中文名和含义的列」最多列几个;别的表指过来的关联关系最多列几条
|
||||
#: 背景里「目录里还没有中文名和含义的列」最多列几个;别的表指过来的关联关系最多列几条;这张表的目录最多列几项
|
||||
#: (几百列的宽表全部起草过有上千项,全列出来提示词就太长了:表级的项、关联关系在前,列的项在后)
|
||||
UNNAMED_SHOWN = 30
|
||||
INCOMING_SHOWN = 30
|
||||
CATALOG_ITEMS_SHOWN = 600
|
||||
|
||||
QUERY_TOOL = "run_query"
|
||||
PROPOSE_TOOL = "propose_changes"
|
||||
@@ -166,6 +168,7 @@ ASSISTANT_PROMPT_LABELS = {
|
||||
"catalog_empty": "这张表还没有数据目录。",
|
||||
"item": "- {path}({label}):{value}〔{source},{status}〕",
|
||||
"item_note": " 备注:{text}",
|
||||
"catalog_more": "(还有 {n} 项没有列出:这张表的目录太长。要改的项照上面的路径写法提,核对时按当前目录算)",
|
||||
"relation": "{columns} → {to_table}.{to_columns}{extra}",
|
||||
"relation_extra": "({text})",
|
||||
"cardinality": "基数 {value}",
|
||||
@@ -357,10 +360,14 @@ def _catalog_lines(notes: Mapping[str, Any] | None, masked: set[str]) -> list[st
|
||||
(剖析的备注里有取值范围)。"""
|
||||
labels = ASSISTANT_PROMPT_LABELS
|
||||
lines: list[str] = []
|
||||
for key, item in catalog._slots(notes).items():
|
||||
# 表级的项、关联关系在前,列的项在后(稳定排序,各自照目录里的顺序);遮罩列上的码值不算
|
||||
slots = [(key, item) for key, item in sorted(catalog._slots(notes).items(), key=lambda kv: kv[0][0] == "c")
|
||||
if not (key[0] == "c" and key[2] == "codes" and key[1].lower() in masked)]
|
||||
for shown, (key, item) in enumerate(slots):
|
||||
if shown >= CATALOG_ITEMS_SHOWN:
|
||||
lines.append(labels["catalog_more"].format(n=len(slots) - shown))
|
||||
break
|
||||
hidden = _touches_masked(key, item, masked)
|
||||
if hidden and key[0] == "c" and key[2] == "codes":
|
||||
continue
|
||||
if key[0] == "r":
|
||||
label, value = labels["field_relation"], _relation_line(item)
|
||||
else:
|
||||
|
||||
@@ -30,6 +30,7 @@ tables: {表名: {notes, version}}},含全部状态的项,表结构里已经
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import json
|
||||
import re
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass, field
|
||||
@@ -51,7 +52,8 @@ _UNNAMED = "数据源"
|
||||
|
||||
#: 状态:照带的、只填空缺的
|
||||
_LOCKED = ("confirmed", "rejected")
|
||||
_STATUS_LABEL = {"proposed": "推断", "verified": "有确证", "confirmed": "已确认", "rejected": "已驳回"}
|
||||
#: 状态的界面叫法(同 frontend/src/lib/terms.ts 的 CATALOG_STATUS_LABEL)
|
||||
_STATUS_LABEL = {"proposed": "推断", "verified": "已验证", "confirmed": "已确认", "rejected": "已驳回"}
|
||||
|
||||
#: 写入一直撞上别人刚改过(重读重算三次仍冲突)
|
||||
WRITE_CONFLICT_ERROR = "这张表的数据目录正被其他人修改,没有导入,请稍后重新导入"
|
||||
@@ -106,7 +108,12 @@ class ImportFile:
|
||||
|
||||
|
||||
def read_file(content: Any, *, include_guidance: bool) -> ImportFile:
|
||||
"""导出的那个对象 → ImportFile。格式不对抛 TransferInvalid(说法给人看)。"""
|
||||
"""导出的那个对象 → ImportFile。界面直接交来文件的原文(一段 JSON 文字)也认。格式不对抛 TransferInvalid(说法给人看)。"""
|
||||
if isinstance(content, str):
|
||||
try:
|
||||
content = json.loads(content)
|
||||
except ValueError as e:
|
||||
raise TransferInvalid("文件内容不是合法的 JSON,请选择从 AgentLab 导出的数据目录文件") from e
|
||||
if not isinstance(content, Mapping):
|
||||
raise TransferInvalid("文件内容不是数据目录导出的格式,请选择从 AgentLab 导出的数据目录文件")
|
||||
if content.get("format") != FORMAT:
|
||||
|
||||
@@ -351,6 +351,18 @@ async def test_background_has_structure_catalog_and_hides_masked_values(client,
|
||||
assert "没开剖析" not in system
|
||||
|
||||
|
||||
async def test_long_catalogs_are_cut_with_a_note(client, tmp_path, monkeypatch):
|
||||
sid = await _source(client, tmp_path)
|
||||
monkeypatch.setattr(catalog_assistant, "CATALOG_ITEMS_SHOWN", 2)
|
||||
model = Scripted([Turn(text=["好。"])])
|
||||
use(monkeypatch, model)
|
||||
await _talk(client, sid, _ask("看看"))
|
||||
system = model.seen[0][0].content
|
||||
# 表级的项在前;遮罩列的码值本来就不算;剩下的说明还有几项
|
||||
assert "- label(中文名):订单" in system and "- grain(粒度)" in system and "- kind(表类型)" not in system
|
||||
assert "还有 3 项没有列出" in system
|
||||
|
||||
|
||||
async def test_without_profiling_there_is_no_query_tool(client, tmp_path, monkeypatch):
|
||||
sid = await _source(client, tmp_path, profile=False)
|
||||
model = Scripted([Turn(text=["只能根据表结构推断。"])])
|
||||
|
||||
@@ -334,6 +334,11 @@ async def test_import_waits_for_draft_jobs_and_rejects_bad_files(client):
|
||||
r = await client.post(f"{_base(local)}/import/preview", json={"content": body})
|
||||
assert r.status_code == 422, body
|
||||
assert any("一" <= ch <= "鿿" for ch in r.json()["detail"])
|
||||
# 界面直接交来文件原文也认;不是 JSON 的 422
|
||||
as_text = await client.post(f"{_base(local)}/import/preview", json={"content": json.dumps(content)})
|
||||
assert as_text.status_code == 200 and as_text.json()["totals"]["tables"] == 2
|
||||
not_json = await client.post(f"{_base(local)}/import/preview", json={"content": "{不是 JSON"})
|
||||
assert not_json.status_code == 422 and "JSON" in not_json.json()["detail"]
|
||||
too_long = {**content, "guidance": "长" * (catalog_jobs.GUIDANCE_MAX + 1)}
|
||||
r = await client.post(f"{_base(local)}/import/preview", json={"content": too_long, "include_guidance": True})
|
||||
assert r.status_code == 422 and "起草要求" in r.json()["detail"]
|
||||
|
||||
Reference in New Issue
Block a user