Files
AgentLab/backend/tests/test_copilot_context.py
T
ThearchyHelios c8393c3c6b 移除仓库中的商业数据:删掉 21 个相关用例,其余标识符脱敏
这个仓库是公开的,而历史里带着一份客户 BI 仓的逐字转储:ANALYTICS(原
schema 名)下 53 张视图名、实测行数、字段结构表,外加一句写明取数方是谁
的注脚。还有一处把真人姓名和工作单位写进了检查脚本的断言里。这些都不是
化名,是能直接拿去对库的东西。

按"含敏感词的测试直接删"处理,共 21 个用例:

  test_agent_tool_loop.py   整个文件(2 个,agent 工具循环的真图验收)
  test_conversations.py     9 个(会话 CRUD、历史文本、上下文进 prompt)
  test_datasource.py        5 个(探查失败的实情、候选 schema 提示)
  test_copilot_context.py   3 个(数据源摘要的限定名)
  test_review.py            1 个(干净运行无信号)
  test_tool_args.py         1 个(call_tool 端到端)

辅助函数和产品源码不在"测试"之列,改为脱敏——否则删一个 _seeded 会连带
带走 8 个没被点名的用例。标识符一律换成中性名:shop→shop、
ANALYTICS→ANALYTICS、prod_shop→prod_shop、真人姓名→张三。

markdown 样本里那两条不是改标识符能解决的:行数、字段结构、业务域描述
整段都是客户的。换成同构的合成内容——领域换了,markdown 构造逐项对齐
(标题层级、有序/无序列表、三列表、带 inline code 的单元格、引用块),
渲染器的覆盖面没有变窄。check-stream 里那句"用的是真实输出"跟着改成实话。

286 → 265 passed,差值正好是删掉的 21 个。tsc 干净,decode / stream / ui
三个 check 不回归。

历史里的同一批内容另行用 git filter-repo 处理。
2026-09-20 22:52:28 +08:00

88 lines
3.4 KiB
Python

"""Copilot 的数据源上下文注入。
这组守的是"Copilot 知道有哪些库、写得出能跑的 SQL"。断了的表现很隐蔽:
它不会报错,只会退回让用户自己写 SQL 的代码节点——接了数据库等于白接。
"""
from __future__ import annotations
from types import SimpleNamespace
import pytest
from app.api.copilot import GRAPH_SCHEMA, _DATASOURCE_BUDGET_CHARS
from app.data.introspect import summary
def _source(n_tables: int, *, name: str = "warehouse", schema: str | None = "ANALYTICS"):
tables = {
f"t{i}": {
"qualified": f"{schema}.t{i}" if schema else f"t{i}",
"schema": schema,
"columns": [
{"name": f"c{j}", "type": "VARCHAR", "nullable": True, "comment": None}
for j in range(20)
],
"primary_key": [], "comment": None, "is_view": True,
}
for i in range(n_tables)
}
return SimpleNamespace(
id="x", name=name, kind="oracle", readonly=True,
description="测试库", options={}, schema_cache={"tables": tables, "schema": schema},
)
def test_graph_schema_allows_arbitrary_config_keys():
"""config 的键随节点类型千变万化,没法枚举成 properties。
不显式写 additionalProperties=True,某些 provider 的结构化输出会按
"不允许额外字段"处理,把 config 整个过滤成 {}——生成的图每个节点都是
空壳,校验挂在"工具节点还没选工具"。这条回归过一次,代价是整条非流式
生成路径不可用。
"""
node = GRAPH_SCHEMA["properties"]["nodes"]["items"]
assert node["properties"]["config"]["additionalProperties"] is True
assert "config" in node["required"]
def test_compact_mode_is_substantially_smaller():
"""压缩比要真的有效,否则降级没意义。实测约 35%。"""
full = summary(_source(53))
compact = summary(_source(53), detail=False)
assert len(compact) < len(full) * 0.5
def test_summary_without_schema_uses_bare_names():
"""没有 schema 概念的库不要硬拼前缀,否则生成的 SQL 反而错。"""
text = summary(_source(2, schema=None))
assert "t0" in text and "None.t0" not in text
def test_budget_constant_is_sane():
"""预算太小会让单个库就触发降级,太大等于没有预算。"""
assert 3000 <= _DATASOURCE_BUDGET_CHARS <= 20000
@pytest.mark.parametrize("n_tables,expect_detail", [(3, True), (40, True), (53, False)])
def test_object_count_decides_detail_level(n_tables, expect_detail):
"""对象超过截断阈值就切紧凑模式。
关键取舍:detail 模式每库只列 40 个对象,多出来的 Copilot 根本看不见。
对 53 个对象的库,"40 张表带字段"不如"53 张表只给名字"——找不到那张表,
字段写得再全也没用。截断丢信息比省 token 更糟。
"""
from app.api.copilot import _DETAIL_TABLE_LIMIT
from app.data.introspect import table_names
src = _source(n_tables)
assert (len(table_names(src)) <= _DETAIL_TABLE_LIMIT) is expect_detail
def test_many_sources_trigger_compact_mode():
"""单库不超标,几个库加起来超预算时整体降级。"""
sources = [_source(35, name=f"db{i}") for i in range(6)]
full = sum(len(summary(s)) for s in sources)
assert full > _DATASOURCE_BUDGET_CHARS
compact = sum(len(summary(s, detail=False)) for s in sources)
assert compact < _DATASOURCE_BUDGET_CHARS