mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 15:21:58 +00:00
d2b398563b
- 蓝图格式:写回卡片多一项 reconciler(一组人或组),旧蓝图没有这一项照旧可读;只收用户的操作(同「谁能看」),助手整张换写回卡片时留着用户选好的人 - 是否需要(templates/_common.needs_reconciler,和应用骨架加核实岗位同一个判断):模板用到写回卡片、选了目标能力、能力没登记查询;交给前端的蓝图带 reconciler_needed,界面不自己判 - 蓝图检查 bp.reconciler_unbound:试运行只提醒(待办派给试运行的人自己),发布挡住;发布单上应用检查说同一件事的 app.reconciler_unbound 和核实岗位的 app.slot_unbound 不再重复列 - 岗位绑定:选了的人绑到应用的核实岗位;能力补登了查询就不再要、也不再绑,卡片上留着的人照样摆出来、写明用不上 - 卡片:需要时摆这一项,标「缺」、写明为什么要人核实,选人控件只能选人或组;「缺」只挡发布;蓝图助手的提示词写明这一项由用户定 - 示例蓝图(核对写回)补上核实人,审批、核对写回的卡片说明写上这一项;测试和检查脚本跟上
409 lines
33 KiB
Python
409 lines
33 KiB
Python
"""白话层(docs/design/normal-user-apps.md N10):问题编号 → 一句话、为什么要紧、谁来改、怎么办。
|
||
|
||
覆盖工作流发布门禁(contract.* / governed.* / action.* / process.*)、应用检查(app.*)、蓝图(bp.*)、模板(tpl.*)、
|
||
个人应用(personal.*)、发布单步骤失败(plan.*)。没登记白话的照旧显示技术说法;检查脚本报「有问题编号没有白话」。
|
||
who:you(你来定)/ assistant(助手可以修)/ admin(要找管理员),按自动修复的 kind、APP_HUMAN_ONLY、要管理员的编号判。
|
||
|
||
框架在这里;内容由包 B2 补齐(B1、B3、B4 新增的编号各自补进来)。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from typing import Any
|
||
|
||
WHO = ("you", "assistant", "admin")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Plain:
|
||
title: str
|
||
why: str = ""
|
||
who: str = "you"
|
||
action: str = ""
|
||
|
||
|
||
_Y, _A, _M = "you", "assistant", "admin"
|
||
|
||
#: 问题编号 → 白话。前缀匹配用 PLAIN_PREFIX(如 "subgraph_version_" 一类)
|
||
PLAIN: dict[str, Plain] = {
|
||
# ---------------------------------------------------------------- 出具契约(engine/governance.py)
|
||
"contract.not_object": Plain(
|
||
"成果的出具规则格式不对", "出具规则读不出来,系统就判不了这份成果能不能正式交出去。", _A,
|
||
"交给助手按出具规则的格式重写,或在成果节点上重新设置。"),
|
||
"contract.metrics_from_missing": Plain(
|
||
"没说指标从哪张口径卡来", "报告里的数对不上任何指标,核对不了出处。", _A,
|
||
"在成果节点的出具规则里选上提供指标的口径卡。"),
|
||
"contract.metrics_from_invalid": Plain(
|
||
"出具规则选的口径卡不存在", "选错了口径卡,核对时找不到指标。", _A, "改选工作流里实际存在的口径卡。"),
|
||
"contract.report_from_missing": Plain(
|
||
"没说核对哪一份报告", "不指明报告,报告里的数就没人核对。", _A, "在出具规则里选上写报告的那个节点。"),
|
||
"contract.report_from_invalid": Plain(
|
||
"出具规则选的报告节点不对", "选的不是写报告的节点,或者不在成果的上游,核对会落空。", _A,
|
||
"改选成果上游的报告撰写节点。"),
|
||
"contract.required_missing": Plain(
|
||
"没列出必须有的指标", "不列出必需指标,缺了关键的数也会交出去。", _Y,
|
||
"选出这份成果里必须有的指标(哪些缺了就不交出去由你定)。"),
|
||
"contract.cells_undeclared": Plain(
|
||
"报告直接引用了查询结果的格子,却没声明", "受管级别不认没声明的引用,正式运行时报告会写不出来。", _Y,
|
||
"选择允许直接引用查询结果,或者加一张口径卡把数登记成指标。"),
|
||
"contract.strict_off": Plain(
|
||
"出具规则没开严格模式", "不开的话,说不清出处的数只会让成果降档,不会被拦下。", _A, "打开严格模式。"),
|
||
"contract.claims_ignored": Plain(
|
||
"「没附依据的结论句」那一项设了也不生效", "受管级别仍会把没附依据的结论句算进缺口,这项设置只会误导人。", _A,
|
||
"改成降档或不予出具。"),
|
||
# ---------------------------------------------------------------- 受管级门禁(engine/governance.py)
|
||
"governed.supervisor": Plain(
|
||
"用了由模型临场分工的节点", "分工和轮数在运行时才定,事先没法审核,受管级别不收。", _Y,
|
||
"改用配置固定的 Agent 或「模型调用」节点(结构要拆成哪几步由你定)。"),
|
||
"governed.subgraph_unpinned": Plain(
|
||
"引用的工作流没固定版本", "上游一改,这边的口径跟着变,没人知道。", _Y, "选定一个已发布的版本。"),
|
||
"governed.agent_approval_never": Plain(
|
||
"Agent 调危险工具不用审批", "受管级别要求危险工具至少经人审批。", _A, "把审批策略改为「仅危险工具需要审批」。"),
|
||
"governed.default_approval_never": Plain(
|
||
"全图默认不用审批", "跟着全图默认的 Agent 调危险工具时没人把关。", _A, "把全图默认的审批策略改为需要审批。"),
|
||
"governed.agent_no_tools": Plain(
|
||
"Agent 没配工具", "不调工具的 Agent 只是在写文字,用「模型调用」节点更合适。", _Y, "改用「模型调用」节点,或给它配上工具。"),
|
||
"governed.agent_tools_wide": Plain(
|
||
"Agent 的工具太多", "授权范围越宽,越难说清它会做什么。", _Y, "只留下完成任务要用的工具。"),
|
||
"governed.code_network": Plain(
|
||
"代码节点开了联网", "在代码里取的数不留快照,事后查不了出处。", _Y, "把取数改到「调用工具」节点。"),
|
||
"governed.no_contract": Plain(
|
||
"成果没有出具规则", "没有出具规则,系统判不了这份成果完不完整。", _A, "给成果节点加上出具规则。"),
|
||
"governed.metric_untraced": Plain(
|
||
"有指标追不到原始数据", "按指标出具时,指标的出处就是全部依据;追不到的那一个,「完整出具」就没有根据。", _A,
|
||
"在口径卡里按格取数,或让整形节点原样解析查询结果。"),
|
||
"governed.report_from_required": Plain(
|
||
"出具规则核对的是叙述,不是报告", "按数值找出处可能对上好几个地方,受管级别要求每个数只有一个出处。", _A,
|
||
"把核对对象改为上游的报告撰写节点。"),
|
||
"governed.exit_text_source": Plain(
|
||
"成果里的文字不是报告写的", "别的节点写的文字说不清出处。", _A, "成果字段改取报告撰写节点的正文。"),
|
||
"governed.text_bypass": Plain(
|
||
"模型写的文字绕过了报告直接进了成果", "这些文字里的数和表名都没法追溯。", _A, "改由报告撰写节点来写,成果取报告正文。"),
|
||
"governed.report_policy": Plain(
|
||
"报告的核对规则不够严", "受管级别要求报告用最严的核对规则。", _A, "把报告撰写节点的核对规则调到最严。"),
|
||
"governed.judge_budget": Plain(
|
||
"模型裁判没设金额上限", "裁判的花费不能沿用默认值,要事先说清。", _Y, "写一个每份报告的裁判金额上限,或明确选择不限。"),
|
||
"governed.caliber_compute_input": Plain(
|
||
"口径卡的数来自代码计算", "沙箱里算出来的数追溯不了出处。", _Y,
|
||
"若这一步是在取数,把它标成取数;若是在计算,把计算挪到口径卡的表达式里(是哪一种由你定)。"),
|
||
"governed.caliber_agent_schema": Plain(
|
||
"给口径卡供数的 Agent 交的是自由文本", "口径卡读到的数没法核对到查询结果。", _A,
|
||
"给 Agent 配上结构化输出,并打开按出处核对字段。"),
|
||
"governed.caliber_agent_cite_fields": Plain(
|
||
"给口径卡供数的 Agent 没核对字段出处", "口径卡读到的仍是模型给的数。", _A, "打开按出处核对字段。"),
|
||
"governed.caliber_model_input": Plain(
|
||
"口径卡的数来自「模型调用」节点", "这种节点不调工具,写出的数没有出处。", _A, "改由「调用工具」节点或配好结构化输出的 Agent 取数。"),
|
||
# ---------------------------------------------------------------- 写外部系统(engine/lint_capabilities.py)
|
||
"action.write_in_agent": Plain(
|
||
"Agent 的工具里有会写外部系统的能力", "写入只能放在「调用工具」节点里,先确认再发送、留生效记录。", _Y,
|
||
"从 Agent 的工具清单里移除它,改用「调用工具」节点。"),
|
||
"action.unattended_write": Plain(
|
||
"写入外部系统不经确认,而这项能力不允许无人值守", "没人确认就写进外部系统,出了错没人拦。", _Y,
|
||
"把这一步改为需要确认;确实要无人值守的,请管理员在能力登记里放开。"),
|
||
"action.prod_missing": Plain(
|
||
"写入能力没有生产环境", "正式运行要写的时候无处可发。", _M, "请管理员在「工具 → 端点」里补上生产环境。"),
|
||
"action.reconcile_unplanned": Plain(
|
||
"写入能力没有登记查询", "写入结果不明时没法自动核实,只能转人工核实。", _M, "请管理员在能力登记里给它指定查询能力。"),
|
||
# ---------------------------------------------------------------- 按流程使用(engine/lint_process.py)
|
||
"process.wait_mid_agent": Plain(
|
||
"Agent 中途可能停下来等审批", "按流程使用时,停在 Agent 中途的断点在系统升级后恢复不了。", _Y,
|
||
"把需要审批的调用挪到「调用工具」节点。"),
|
||
"process.human_in_subgraph": Plain(
|
||
"人工步骤放在了引用的工作流里", "引用的工作流不保存断点,恢复时整段从头再来,可能重复办。", _Y,
|
||
"把人工步骤挪到外层工作流。"),
|
||
"process.code_network": Plain(
|
||
"代码节点联网,可能在写外部系统", "按流程使用时,写外部系统要先留生效记录,结果不明时才能核实。", _Y,
|
||
"把对外部系统的写入挪到「调用工具」节点。"),
|
||
# ---------------------------------------------------------------- 应用检查(apps/lint.py、apps/resolve.py)
|
||
"app.format": Plain(
|
||
"应用描述的格式不对", "格式不对的应用发布不了。", _A, "交给助手按应用格式修好。"),
|
||
"app.pin_unpublished": Plain(
|
||
"应用用的工作流版本还没发布", "应用只能用已发布的版本,正式运行只从已发布的版本发起。", _Y,
|
||
"先发布这一版,或换成一个已发布的版本。"),
|
||
"app.pin_retired": Plain(
|
||
"应用用的工作流版本已退役", "退役的版本不再接受新的正式运行。", _Y, "升级到一个在用的发布版本。"),
|
||
"app.pin_hash": Plain(
|
||
"应用记下的版本和库里的对不上", "按内容指纹认版本,对不上就说不清运行的是哪张图。", _Y, "重新选择这一版。"),
|
||
"app.upgrade_policy": Plain(
|
||
"口径变了,还没选以前的数怎么办", "换版本可能改了口径,新旧数放在一起比之前要先说清。", _Y,
|
||
"选一种处置:按新口径重算、新旧并列,或注明前后不可比。"),
|
||
"app.binding_target_missing": Plain(
|
||
"页面上有一块绑的东西不存在", "这一块会显示不出来。", _A, "改绑到存在的视图、指标或节点,或删掉这一块。"),
|
||
"app.view_source_empty": Plain(
|
||
"这个视图暂时还没有数", "页面会写明还没有数据,等第一次正式运行完成就有了。", _Y, "不用改;想马上有数,发布后运行一次。"),
|
||
"app.on_demand_ttl": Plain(
|
||
"按需查看的缓存时效没设好", "查活库的视图不设时效,同样的条件会一直给旧结果。", _A, "设一个缓存时效。"),
|
||
"app.component_unknown": Plain(
|
||
"用了组件目录里没有的组件", "界面画不出来不认识的组件。", _A, "换成组件目录里有的组件。"),
|
||
"app.props_invalid": Plain(
|
||
"组件的设置不对", "设置不对,这一块可能显示错或显示不出来。", _A, "按组件的说明改设置。"),
|
||
"app.text_number": Plain(
|
||
"页面的固定文字里写了数字", "写死的数不会随数据更新,也说不清出处。", _A, "改成绑定到指标或查询结果。"),
|
||
"app.binding_not_evidenced": Plain(
|
||
"成果字段里的数不是报告里的原文", "说不清出处的数不展示。", _A, "改绑报告,或让成果字段逐字取自报告。"),
|
||
"app.metric_untraced": Plain(
|
||
"页面上的指标追不到原始数据", "这个数点开看不到出处。", _A, "换一个能追到原始数据的指标,或先改口径卡。"),
|
||
"app.expr_arith": Plain(
|
||
"显示条件里做了计算", "页面层不做算术,数要在工作流里算好。", _A, "把计算挪到口径卡,条件里只做比较。"),
|
||
"app.expr_invalid": Plain(
|
||
"显示条件写法不对", "条件算不出来时这一块按不显示处理。", _A, "改正条件的写法。"),
|
||
"app.expr_root": Plain(
|
||
"显示条件用了不认识的名字", "条件算不出来时这一块按不显示处理。", _A, "改用条件里能用的名字。"),
|
||
"app.entry_form_mismatch": Plain(
|
||
"发起表单和工作流的输入对不上", "填的东西传不到工作流里,或者传错位置。", _A, "让表单字段和工作流的输入一一对应。"),
|
||
"app.entry_unmapped_required": Plain(
|
||
"工作流必填的输入,发起表单没给", "发起时会因为缺输入而失败。", _A, "在发起表单里加上这一项,或给它一个固定值。"),
|
||
"app.slot_unbound": Plain(
|
||
"有一步还没指定谁来做", "没人的那一步会派给任何人,审批、升级都会悄悄失效。", _Y, "在「谁来做」里给这一步选人或组。"),
|
||
"app.slot_principal_unknown": Plain(
|
||
"「谁来做」里选的人或组在名录里对不上", "派给这个名字的待办没有人能处理。", _Y, "从候选中重新选择,或移除。"),
|
||
"app.reconciler_unbound": Plain(
|
||
"写入结果不明时没人核实", "写外部系统的结果不明时,要有人去外部系统里查。", _Y, "指定负责核实写入结果的人或组。"),
|
||
"app.process_unsafe": Plain(
|
||
"这个工作流按流程使用不安全", "流程要能停下等人、断了能接着走,这张图有一处做不到。", _Y,
|
||
"按问题里说的改工作流,再发布新版本。"),
|
||
"app.hook_entry_missing": Plain(
|
||
"外部系统发起用的入口不存在", "外部系统发来的请求会被拒收。", _A, "改选存在的入口。"),
|
||
"app.notify_channel_missing": Plain(
|
||
"订阅的通知渠道不存在", "这条通知发不出去。", _Y, "换一个存在的渠道,或请管理员建好它。"),
|
||
"app.acl_empty": Plain(
|
||
"还没给任何人用", "开了登录时,除了管理员和搭建者谁都打不开。", _Y, "在「谁能看」里给要用的人或组授权。"),
|
||
"app.acl_principal_unknown": Plain(
|
||
"授权给的人或组在名录里对不上", "以后建了同名的人会直接拿到这一档权限,或者停用的人重新启用后又能用。", _Y,
|
||
"从候选中重新选择,或移除。"),
|
||
"app.polish_refused": Plain(
|
||
"助手想改的地方超出了它能改的范围", "助手只能改页面的呈现,改数据、改流程要人来。", _Y, "确实要改的,由你在对应的地方改。"),
|
||
# ---------------------------------------------------------------- 发布单(blueprints/publish_plan.py)
|
||
"plan.not_instantiated": Plain(
|
||
"蓝图还没生成工作流", "没有图就没有东西可以发布。", _Y, "先把卡片补齐,用真数试运行一次。"),
|
||
"plan.graph_changed": Plain(
|
||
"出单之后蓝图又改过", "要发布的已经不是这份发布单看过的那张图。", _Y, "重新出一份发布单。"),
|
||
"plan.trial_failed": Plain(
|
||
"最近一次试运行失败了", "用真数运行出了错,这样发布出去,每次出数都会是同一个错。", _Y,
|
||
"回到试运行看出错的原因(可以交给助手修),修好后再用真数试一次。"),
|
||
"plan.untrialed": Plain(
|
||
"还没用真数试运行过", "没看过真数就发布,可能不是你要的结果。", _Y, "先试运行一次,看过结果再发布。"),
|
||
"plan.trial_differs": Plain(
|
||
"发布的内容和最近一次试运行不同", "试运行之后又改过,发布的这一版没用真数看过。", _Y, "建议再试运行一次。"),
|
||
"plan.admin_required": Plain(
|
||
"受管级别只有管理员能发布", "受管级别的工作流按最严的规则出具,发布由管理员签字。", _M, "请管理员来发布,或改按已发布级别发布。"),
|
||
"plan.downgrade_admin": Plain(
|
||
"这会把受管工作流降为已发布", "降级之后正式运行不再过受管级别的检查,要管理员决定。", _M, "请管理员来发布,或改按受管级别发布。"),
|
||
"plan.preflight": Plain(
|
||
"发布前检查没通过", "有问题没解决,这时发布会留下半截状态,所以什么都没写。", _Y, "按下面列出的问题逐条处理,再接着做。"),
|
||
"plan.workflow_publish": Plain(
|
||
"工作流没能发布", "工作流不发布,就不会有正式运行。", _Y, "按问题处理后接着做。"),
|
||
"plan.schedule_invalid": Plain(
|
||
"定时设置不对", "按这个设置建不了定时任务。", _Y, "回到「多久更新」卡片改好,再接着做。"),
|
||
"plan.app_publish": Plain(
|
||
"应用没能发布", "工作流已经发布了,应用还没有;使用者暂时看不到它。", _Y, "按问题处理后接着做。"),
|
||
"plan.app_archived": Plain(
|
||
"这个蓝图对应的应用已归档", "归档的应用不再改草稿、不再发布。", _Y, "如需继续,请新建一个应用。"),
|
||
"plan.app_forbidden": Plain(
|
||
"你对这个蓝图发布成的应用没有管理权限", "发布单会改这个应用的页面、发布新的一版、替换它的授权,这些要管理权限。", _M,
|
||
"请应用的管理者或管理员来发布,或请他们在应用的授权里给你管理权限。"),
|
||
"plan.grant_refused": Plain(
|
||
"「谁能看」里有人或组在名录里对不上", "授权只能给名录里在用的人和组。", _Y, "回到「谁能看」卡片重新选择。"),
|
||
"plan.first_run": Plain(
|
||
"第一次运行没能发起", "应用已经发布好了,只是打开时还没有数。", _Y, "稍后在应用里运行一次,或等定时任务出数。"),
|
||
"plan.object_missing": Plain(
|
||
"前面某一步建好的东西不见了", "接着做之前要确认前面几步的结果还在。", _Y, "重新出一份发布单。"),
|
||
"plan.interrupted": Plain(
|
||
"执行到一半服务重启了", "这一步可能只做了一半,后面的步骤都没有做。", _Y,
|
||
"接着做:已经存好的版本、建好的应用会按原样复用,不会另建一份。"),
|
||
"plan.step_failed": Plain(
|
||
"这一步出了意外的错", "这一步没做完,后面的步骤都没有做。", _Y, "稍后接着做;一直不行请把错误信息交给管理员。"),
|
||
}
|
||
# ---------------------------------------------------------------- 个人应用与页面编辑(包 B4:blueprints/personal.py、
|
||
# apps/lint.py 的 _lint_personal / _lint_views / _lint_hidden、api/personal.py)
|
||
PLAIN.update({
|
||
"app.view_source_personal": Plain(
|
||
"视图的数据来源和应用的类型对不上", "探索运行的结果没经过发布审核,只能给个人应用的拥有者自己看;个人应用又只有"
|
||
"探索运行,取别的来源永远是空的。", _Y,
|
||
"共享应用的视图改成取正式运行(最近一次出数、按条件查看或本实例);个人应用的视图改回取它自己的刷新结果。"),
|
||
"app.hidden_bound": Plain(
|
||
"隐藏的这块是唯一显示这组数的地方", "隐藏之后,页面上一处都看不到这组数了。", _Y,
|
||
"确实不要了可以删掉它;还要看的话取消隐藏。"),
|
||
"personal.policy": Plain(
|
||
"个人应用里有使用者不能用的东西", "个人应用只能读数据、整理、撰写,不能审批、不能写入别的系统,也不能执行代码,"
|
||
"这样它的结果才能只给你自己看。", _Y, "回到蓝图换一种做法;需要审批或写回的,请提交给搭建者做成正式应用。"),
|
||
"personal.off": Plain(
|
||
"管理员还没有开放个人应用", "个人应用由管理员决定开不开放。", _M, "请管理员在设置里打开,或请搭建者做成应用。"),
|
||
"personal.not_trialed": Plain(
|
||
"还没有用真数试过", "没看过真数就存,可能不是你要的结果。", _Y, "先试运行一次,看过结果再存成你的应用。"),
|
||
"personal.graph_changed": Plain(
|
||
"蓝图改过,还没重新存成你的应用", "刷新按存下的那张图运行,改过的蓝图还没生效。", _Y,
|
||
"回到蓝图「存成我的应用」,再刷新。"),
|
||
"personal.daily_limit": Plain(
|
||
"今天的刷新次数用完了", "每人每天能刷新的次数有上限,控制运行的花费。", _M, "明天再试,或请管理员调高上限。"),
|
||
"personal.no_run": Plain(
|
||
"还没有成功刷新过", "审核的人要看到这个应用用真数出的结果。", _Y, "先刷新一次,成功之后再提交审核。"),
|
||
"personal.in_review": Plain(
|
||
"已经提交过审核", "同一个应用同时只能有一份在审核。", _Y, "等搭建者发布或退回之后再提交。"),
|
||
"personal.review_target": Plain(
|
||
"审核要交给搭建者", "只有搭建者能把它做成正式应用。", _Y, "从候选里选一位搭建者,或者交给一个组。"),
|
||
"personal.review_forbidden": Plain(
|
||
"审核个人应用要搭建者来做", "审核的人要在副本上试运行、发布成正式应用,这些只有搭建者能做。", _M,
|
||
"请一位搭建者处理这条审核,或请管理员调整你的角色。"),
|
||
"personal.not_personal": Plain(
|
||
"这不是个人应用,或者它出自的蓝图已经不在了", "刷新、提交审核只对还能找到蓝图的个人应用。", _Y,
|
||
"共享应用请用它自己的刷新;蓝图删了的个人应用可以归档。"),
|
||
"personal.not_shareable": Plain(
|
||
"个人应用不能发布或授权给别人", "个人应用的结果没经过发布审核,只给拥有者自己看。", _Y,
|
||
"想给别人用,请提交审核,由搭建者发布成正式应用。"),
|
||
})
|
||
# ---------------------------------------------------------------- 记录表与文件(包 B3:records/、files/、api/files.py、
|
||
# apps/lint.py 的 _lint_records_rows)。records.* 是写记录表被拒的原因,files.* 是上传、提交、下载文件被拒的原因
|
||
PLAIN.update({
|
||
"app.records_rows_exposed": Plain(
|
||
"看板上的表格把记录一条条都列出来了", "看板的数是用全部记录算的,这样每个能用应用的人都能看到别人提交的记录。", _Y,
|
||
"要看自己提交了什么,请用「记录列表」组件(按看的人过滤);看板上的表格改成汇总。确实要公开给所有人看的可以不改。"),
|
||
"records.column_invalid": Plain(
|
||
"表单里有字段存不进记录表", "字段名重复、以下划线开头或者类型不认识,记录表建不起来。", _Y,
|
||
"回到「填什么」卡片改字段名或类型。"),
|
||
"records.column_unknown": Plain(
|
||
"要写入的字段记录表里没有", "表单改过,应用还在用改之前的那一版。", _Y, "重新发布应用,让表单和记录表对上。"),
|
||
"records.required_missing": Plain(
|
||
"必填的字段没有值", "必填的字段空着,这条记录就是不完整的。", _Y, "把必填的字段填上再提交。"),
|
||
"records.value_invalid": Plain(
|
||
"有字段的值和类型对不上", "比如数字字段填了文字,存进去以后汇总会算错。", _Y, "按字段要求的类型重新填写。"),
|
||
"records.supersede_missing": Plain(
|
||
"要更正的那条记录找不到", "更正要指向这张表里已有的一条记录。", _Y, "从记录列表里选要更正的那一条。"),
|
||
"records.supersede_twice": Plain(
|
||
"这条记录已经被更正过了", "同一条记录只能更正一次,后面的修改要改在最新的那一条上。", _Y, "在最新的那一条上更正。"),
|
||
"records.table_retired": Plain(
|
||
"这一版记录表已经停用", "表单改过之后出了新版本,旧记录照原样保留、只能查看。", _Y, "重新发布应用,写到新版本里。"),
|
||
"records.table_foreign": Plain(
|
||
"写的记录表不属于这个应用", "正式运行只能写自己应用的记录表,不然别的应用的记录会被混进来、被不该看的人看到。", _Y,
|
||
"回到写记录表那一步,改成这个应用自己的记录表,再重新发布。"),
|
||
"records.table_missing": Plain(
|
||
"记录表的数据文件不见了", "数据文件被移走或删掉,记录写不进去、也查不了。", _M, "请管理员检查数据目录。"),
|
||
"records.file_exists": Plain(
|
||
"记录表的数据文件已经有数据,不能重建", "为了不覆盖已有的记录,系统拒绝了重建。", _M, "请管理员检查数据目录。"),
|
||
"records.action_key_missing": Plain(
|
||
"写记录表没有经过动作流程", "只有经过动作流程,同一次提交才保证只写一条。", _A,
|
||
"把写入放在「调用工具」节点里,不要放进 Agent。"),
|
||
"files.missing": Plain("没有选文件", "", _Y, "选择要上传的文件。"),
|
||
"files.empty": Plain("文件是空的", "空文件里没有可用的内容。", _Y, "检查后重新选择文件。"),
|
||
"files.type_not_allowed": Plain(
|
||
"这种类型的文件不能上传", "只收常见的文档、表格、图片和文字文件,别的类型可能带来风险。", _Y,
|
||
"另存为 PDF、Word、Excel、CSV、图片或文字文件再上传。"),
|
||
"files.type_not_accepted": Plain(
|
||
"这里不收这种文件", "表单的这一项限定了文件类型或大小。", _Y, "按提示换一个文件。"),
|
||
"files.content_mismatch": Plain(
|
||
"文件内容和扩展名对不上", "改过扩展名的文件,系统没法按它说的类型读。", _Y, "用原始文件重新上传。"),
|
||
"files.context_invalid": Plain(
|
||
"没说清文件是给哪里用的", "上传要对应一个入口、一条待办或一个蓝图,系统才知道谁能用它。", _A,
|
||
"从表单里的文件控件上传。"),
|
||
"files.forbidden": Plain(
|
||
"没有权限", "只有能用这个入口、处理这条待办、看得到这次运行或这条记录的人,才能上传或下载。", _M,
|
||
"请应用的管理者给你授权。"),
|
||
"files.ref_invalid": Plain(
|
||
"文件没有上传好", "提交的是文件的引用,要先上传、拿到引用。", _Y, "重新上传这个文件再提交。"),
|
||
"files.not_found": Plain(
|
||
"文件不见了", "上传后 24 小时还没提交的文件会被清理。", _Y, "重新上传再提交。"),
|
||
"files.not_yours": Plain(
|
||
"这个文件不是你上传的", "只能提交自己上传的文件。", _Y, "自己上传一份再提交。"),
|
||
"files.already_bound": Plain(
|
||
"这个文件已经提交过一次", "一次上传只能随一次提交进运行,这样每次运行用的是哪份文件说得清。", _Y,
|
||
"再提交的话请重新上传。"),
|
||
"files.context_mismatch": Plain(
|
||
"文件是在别的地方上传的", "文件只能用在上传时说明的那个入口或那条待办上。", _Y, "在这里重新上传。"),
|
||
"files.bound": Plain(
|
||
"已经提交的文件不能删除", "它是那次运行的证据,删掉就说不清当时用的是什么。", _Y, "不需要处理。"),
|
||
"files.content_lost": Plain(
|
||
"文件内容不在了或被改动过", "下载到的内容如果和当时登记的不一样,就不能当证据用。", _M, "请管理员检查数据目录。"),
|
||
})
|
||
# ---------------------------------------------------------------- 蓝图与模板(包 B1:blueprints/ops.py 的 bp.*、
|
||
# blueprints/instantiate.py、blueprints/generation.py 的 tpl.*)
|
||
PLAIN.update({
|
||
"bp.missing": Plain(
|
||
"蓝图上还有没填的卡片", "缺了这一项,模板没法生成能运行的工作流。", _Y, "在卡片上补上,或者告诉助手这一项是什么。"),
|
||
"bp.unconfirmed": Plain(
|
||
"有助手或模板提的项还没确认", "没确认的项是猜的,发布出去就成了正式的口径和规则。", _Y, "逐项看过,对的点确认,不对的直接改。"),
|
||
"bp.data_unmapped": Plain(
|
||
"有要看的数还没对到表或口径", "对不到数据,就算不出这个数。", _A,
|
||
"请助手按数据目录对到表(或复用已发布的口径),对到之后由你确认。"),
|
||
"bp.data_source_unknown": Plain(
|
||
"有要看的数对到的数据源不存在", "试运行和发布时找不到这个数据源,这个数算不出来。", _Y,
|
||
"在「看哪些数」里点「改」重新选数据源;填报登记汇总本应用的记录,选「本应用的记录表」。"),
|
||
"bp.data_table_unknown": Plain(
|
||
"有要看的数对到的表不在那个数据源里", "查不到这张表,这个数算不出来。", _Y,
|
||
"在「看哪些数」里点「改」重新选表;表刚建的话,先到「数据」页读取一次表结构。"),
|
||
"bp.people_unbound": Plain(
|
||
"有一步还没定谁来处理", "流程走到这一步就没人接手。", _Y, "在「谁来做」里选人、组或岗位。"),
|
||
"bp.reconciler_unbound": Plain(
|
||
"写回的结果不明时没人核实", "这项写入能力没登记查询:结果不明时平台查不了,也不会自动重发,要有人去目标系统里看写进去没有。",
|
||
_Y, "在「写回哪里」卡片的「结果不明时谁去核实」里选人或组。"),
|
||
"bp.template_mismatch": Plain(
|
||
"卡片上写的超出了这个场景能做的", "超出的那部分不会生效,做出来的应用和你说的对不上。", _Y,
|
||
"按提示删掉或改小,或者换一个场景。"),
|
||
"bp.refused": Plain(
|
||
"这处修改没有采纳", "改动不符合这张卡片的写法。", _Y, "按提示的写法重新改。"),
|
||
"tpl.skeleton_changed": Plain(
|
||
"改动超出了模板留出的位置", "模板的结构是锁住的,审批、写入、出具这些地方不能被顺手改掉。", _A,
|
||
"只改模板留给助手的取数和指标;结构要变,请换一个场景或回画布。"),
|
||
"tpl.joint_unfilled": Plain(
|
||
"还有取数或指标没写好", "缺了它,试运行算不出数。", _A, "请助手填上;填不上时补充说明数从哪来、怎么算。"),
|
||
"tpl.joint_refused": Plain(
|
||
"助手想改模板锁住的地方,没有采纳", "模板锁住的结构不归助手改。", _A, "不需要处理;要改结构请回到卡片或换一个场景。"),
|
||
"tpl.metric_expr": Plain(
|
||
"指标的算法写得不合规矩", "指标只能从取数结果里按格取数再算,这样每个数都能追到出处。", _A, "请助手按规矩重写这个指标。"),
|
||
"tpl.metric_column": Plain(
|
||
"指标要用的列,取数的 SQL 里没有", "运行时这个指标会算不出来。", _A, "请助手让取数的 SQL 交出这一列,或改指标。"),
|
||
"tpl.sql_rejected": Plain(
|
||
"取数的 SQL 不是只读的一条查询", "取数只能读,不能改数据,也只能是一条语句。", _A, "请助手重写成一条只读的查询。"),
|
||
})
|
||
PLAIN_PREFIX: dict[str, Plain] = {
|
||
# 子工作流、口径卡固定的版本不是「已发布且未退役」的(apps/versions.py)
|
||
"subgraph_version_": Plain(
|
||
"引用的工作流版本没发布或已退役", "正式运行发起时会被拒绝。", _Y, "在那个工作流里发布新版本,再把这里的引用换过去。"),
|
||
"caliber_version_": Plain(
|
||
"引用的口径卡版本没发布或已退役", "正式运行发起时会被拒绝。", _Y, "在那个工作流里发布新版本,再把这里的引用换过去。"),
|
||
}
|
||
|
||
#: 要管理员处理的编号:端点、能力登记归管理员管(受管级发布、降级的权限在发布单里另报 plan.admin_required、
|
||
#: plan.downgrade_admin)
|
||
ADMIN_CODES = frozenset(code for code, plain in PLAIN.items() if plain.who == _M)
|
||
|
||
|
||
def plain_of(code: str | None) -> Plain | None:
|
||
if not code:
|
||
return None
|
||
if code in PLAIN:
|
||
return PLAIN[code]
|
||
for prefix, plain in PLAIN_PREFIX.items():
|
||
if code.startswith(prefix):
|
||
return plain
|
||
return None
|
||
|
||
|
||
def who_of(issue: dict[str, Any]) -> str:
|
||
"""这条问题归谁处理(you / assistant / admin)。依次看:要管理员的编号;自动修复给的修复种类(fix_kind:choice 要人
|
||
选,auto、assist 助手能做);应用检查只有人能处理的(api/copilot_gen.APP_HUMAN_ONLY);白话里登记的那一档(应用检查
|
||
其余的登记成「助手可以修」:助手的自查会修它们);没登记的应用检查算「助手可以修」,别的算「你来定」。"""
|
||
from app.api.copilot_gen import APP_HUMAN_ONLY
|
||
|
||
code = str(issue.get("code") or "")
|
||
if code in ADMIN_CODES:
|
||
return _M
|
||
kind = issue.get("fix_kind")
|
||
if kind == "choice":
|
||
return _Y
|
||
if kind in ("auto", "assist"):
|
||
return _A
|
||
if code in APP_HUMAN_ONLY:
|
||
return _Y
|
||
plain = plain_of(code)
|
||
if plain is not None:
|
||
return plain.who
|
||
return _A if code.startswith("app.") else _Y
|
||
|
||
|
||
def with_plain(issue: dict[str, Any]) -> dict[str, Any]:
|
||
"""给一条问题补上 plain = {title, why, who, action};没登记的不补(照旧显示技术说法)。who 按 who_of 判。"""
|
||
plain = plain_of(issue.get("code"))
|
||
if plain is None:
|
||
return issue
|
||
return {**issue, "plain": {"title": plain.title, "why": plain.why, "who": who_of(issue), "action": plain.action}}
|