mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 03:01:58 +00:00
口径召回的通知按种类分开写答案的条数
验收:ledger.recall 消息里写「答案:2 个」,实际是 1 个问数回答加 1 个正式运行。notify_recall 拿 _uses_of 的长度直接 拼成「N 个」,不分种类。 改法:notify/service 加 _answers_text,按用法的种类数(ledger.uses.KINDS 的顺序、KIND_TEXT 的叫法,同版本用量和召回 批次的说法)写成「问数回答 1 个、正式运行 1 个」;全局渠道按这一批汇总、个人渠道只数他的,两处都用它。只写条数,照旧 不放旧值、新值、差值和原答案的值。 测试(test_ledger_recall):新增一条:同一周一个问数回答、一次正式运行,升版召回之后全局渠道收到的「答案」一行是 「问数回答 1 个、正式运行 1 个」,消息里没有数;原来两条按「1 个」「2 个」断言的改成带种类的写法。去掉修复回跑挂 3 条。
This commit is contained in:
@@ -342,6 +342,18 @@ async def notify_task(task_id: str, event: str, *, users: list[str], exclude: fr
|
||||
task_id=task_id)
|
||||
|
||||
|
||||
def _answers_text(uses: list[dict[str, Any]]) -> str:
|
||||
"""召回消息里「答案」那一行:按种类分开写条数(「问数回答 1 个、正式运行 1 个」,种类的叫法同版本用量 ledger.uses.KIND_TEXT),
|
||||
只写条数、不放数。以前合成一个「2 个」,一个问数回答加一次正式运行读起来像两个问数回答。一个都没有写「0 个」。"""
|
||||
from collections import Counter
|
||||
|
||||
from app.ledger.uses import KIND_TEXT, KINDS
|
||||
|
||||
counts = Counter(str(u.get("kind") or "") for u in uses)
|
||||
order = [k for k in KINDS if counts.get(k)] + sorted(k for k in counts if k not in KINDS)
|
||||
return "、".join(f"{KIND_TEXT.get(k, k or '答案')} {counts[k]} 个" for k in order) or "0 个"
|
||||
|
||||
|
||||
async def notify_recall(task_id: str, users: list[str]) -> int:
|
||||
"""口径召回的待办开出来了(app/ledger/recall):口径升版、数真变了的那一种推 ledger.recall——订阅了它的全局渠道、答案主人
|
||||
自己的个人渠道;然后照别的待办推 task.opened(已经推过 ledger.recall 的渠道不再推,同一个渠道只推一次)。目录、表结构变了
|
||||
@@ -352,8 +364,9 @@ async def notify_recall(task_id: str, users: list[str]) -> int:
|
||||
答案、待办按这一批汇总,链到待办箱(各人在那里看到派给自己的那条);别的几条连 task.opened 也不再推全局渠道。个人渠道
|
||||
照旧每个主人各一条,只数他的答案、链到他的那条待办。
|
||||
|
||||
消息照模块说明的规矩(X6):口径名(搭建时起的工作流名)、新旧版本号、几个答案(几条待办)、召回编号、去处理的链接;不放
|
||||
旧口径的值、新口径的值、差值和原答案的值。返回推了几个渠道。"""
|
||||
消息照模块说明的规矩(X6):口径名(搭建时起的工作流名)、新旧版本号、几个答案(按种类分开写条数:问数回答几个、正式运行
|
||||
几个……,见 _answers_text;几条待办)、召回编号、去处理的链接;不放旧口径的值、新口径的值、差值和原答案的值。返回推了几个
|
||||
渠道。"""
|
||||
from app.ledger import recall
|
||||
|
||||
try:
|
||||
@@ -387,13 +400,13 @@ async def notify_recall(task_id: str, users: list[str]) -> int:
|
||||
head = [("状态", "待处理"), ("口径", f"「{name[:80]}」"),
|
||||
("版本", f"v{origin.get('from_version')} → v{origin.get('to_version')}")]
|
||||
tail = [("召回", f"#{task.run_id[:6]}")]
|
||||
mine = len(recall._uses_of(origin, recall._owner_of_key(key)))
|
||||
everyone = len(recall._uses_of(origin, ("anyone", "")))
|
||||
mine = _answers_text(recall._uses_of(origin, recall._owner_of_key(key)))
|
||||
everyone = _answers_text(recall._uses_of(origin, ("anyone", "")))
|
||||
|
||||
def message(answers: int, tasks: int, link: tuple[str, str] | None) -> dict[str, Any]:
|
||||
def message(answers: str, tasks: int, link: tuple[str, str] | None) -> dict[str, Any]:
|
||||
return {"event": event, "status": "pending", "ok": False,
|
||||
"title": recall.CHANGED_TITLE.format(name=name[:80] or "口径", version=origin.get("to_version")),
|
||||
"lines": [*head, ("答案", f"{answers} 个"), *([("待办", f"{tasks} 条")] if tasks > 1 else []), *tail],
|
||||
"lines": [*head, ("答案", answers), *([("待办", f"{tasks} 条")] if tasks > 1 else []), *tail],
|
||||
"links": [link] if base and link else [],
|
||||
"subject": {"task_id": task_id, "run_id": task.run_id, "workflow_id": origin.get("workflow_id")}}
|
||||
|
||||
|
||||
@@ -464,11 +464,57 @@ async def test_recall_notification_has_no_numbers(monkeypatch):
|
||||
text = mine[0]["title"] + "".join(f"{k}{v}" for k, v in mine[0]["lines"])
|
||||
for number in ("170.5", "208.5", "38.0", "38.00"):
|
||||
assert number not in text, f"消息里不放数:{number}"
|
||||
assert dict(mine[0]["lines"]) == {"状态": "待处理", "口径": "「周销售」", "版本": "v1 → v2", "答案": "1 个",
|
||||
assert dict(mine[0]["lines"]) == {"状态": "待处理", "口径": "「周销售」", "版本": "v1 → v2", "答案": "问数回答 1 个",
|
||||
"召回": dict(mine[0]["lines"])["召回"]}
|
||||
assert "周销售" in mine[0]["title"] and "v2" in mine[0]["title"]
|
||||
|
||||
|
||||
async def test_recall_message_counts_answers_by_kind(monkeypatch):
|
||||
"""召回消息按种类分开写条数:一个问数回答、一次正式运行写「问数回答 1 个、正式运行 1 个」(下一轮验收:以前写「答案:2 个」,
|
||||
读的人以为是两个问数回答)。只写条数,照旧不放数。"""
|
||||
from app.core.crypto import encrypt
|
||||
from app.db.models import NotifyChannel
|
||||
from app.engine.launch import launch_run
|
||||
from app.notify import service
|
||||
|
||||
sent: list[dict] = []
|
||||
|
||||
async def capture(channel, message):
|
||||
sent.append({"channel": channel.name, **message})
|
||||
from app.notify.core import Outcome
|
||||
|
||||
return Outcome(True, 200, 1, None)
|
||||
|
||||
monkeypatch.setattr("app.notify.send", capture)
|
||||
async with SessionLocal() as session:
|
||||
row = NotifyChannel(name="召回-按种类", scope="global", url=encrypt("https://hooks.example.com/recall-kinds"),
|
||||
events=["ledger.recall"])
|
||||
session.add(row)
|
||||
await session.commit()
|
||||
channel_id = row.id
|
||||
try:
|
||||
wf = await S.publish()
|
||||
await answer(monkeypatch)
|
||||
S.script(monkeypatch, "本周销售额 [[m:gmv]]。")
|
||||
async with SessionLocal() as session:
|
||||
formal = await launch_run(session, workflow_id=wf, run_class="formal", version=1, input_payload=WEEK1,
|
||||
actor="analyst")
|
||||
assert (await S.wait(formal.id)).status == "succeeded"
|
||||
await publish_v2(wf)
|
||||
await run_recall(wf)
|
||||
await service.drain()
|
||||
finally:
|
||||
async with SessionLocal() as session:
|
||||
await session.delete(await session.get(NotifyChannel, channel_id))
|
||||
await session.commit()
|
||||
mine = [m for m in sent if m["channel"] == "召回-按种类"]
|
||||
assert mine, sent
|
||||
answers = [v for m in mine for k, v in m["lines"] if k == "答案"]
|
||||
assert "问数回答 1 个、正式运行 1 个" in answers, answers
|
||||
for number in ("170.5", "208.5", "38.0"):
|
||||
assert all(number not in v for m in mine for _, v in m["lines"]), "消息里不放数"
|
||||
|
||||
|
||||
async def test_recall_pushes_the_shared_channel_once_per_recall_run(monkeypatch):
|
||||
"""开登录时一组答案有几个主人就开几条待办,但全局渠道(团队群)按召回运行只收一条(答案、待办都按这次召回汇总,链到
|
||||
待办箱);订阅了 task.opened 的全局渠道也不再按每条待办各推一次。每个主人自己的个人渠道各收他那一条。"""
|
||||
@@ -522,12 +568,12 @@ async def test_recall_pushes_the_shared_channel_once_per_recall_run(monkeypatch)
|
||||
team = [m for m in sent if m["channel"] == "团队-召回"]
|
||||
assert [m["event"] for m in team] == ["ledger.recall"], [m["event"] for m in team]
|
||||
lines = dict(team[0]["lines"])
|
||||
assert lines["答案"] == "2 个" and lines["待办"] == "2 条", lines
|
||||
assert lines["答案"] == "问数回答 2 个" and lines["待办"] == "2 条", lines
|
||||
assert [label for label, _ in team[0]["links"]] == ["去待办箱"] or team[0]["links"] == []
|
||||
assert [m["event"] for m in sent if m["channel"] == "团队-待办"] == ["task.opened"], "只订阅了新待办的团队渠道也只收一条"
|
||||
for name in ("analyst_a", "analyst_b"):
|
||||
mine = [m for m in sent if m["channel"] == f"个人-{name}"]
|
||||
assert [m["event"] for m in mine] == ["ledger.recall"] and dict(mine[0]["lines"])["答案"] == "1 个", mine
|
||||
assert [m["event"] for m in mine] == ["ledger.recall"] and dict(mine[0]["lines"])["答案"] == "问数回答 1 个", mine
|
||||
# 账本接口里的召回待办只列看的这个人手上的:第一个答案的主人看得到自己那条,另一个主人看不到
|
||||
from app.api.deps import Principal
|
||||
|
||||
|
||||
Reference in New Issue
Block a user