跳到主要内容

规范与代码出入:定案记录(原「待定」)

什么时候读:想知道某个曾经待定的出入是怎么定的、平台侧还剩什么落地项时。 2026-10 按 routers + 平台核心层(executor / pipeline / compat / actor_ctx)现行代码统一定案,原则「按正式代码来」: 文档跟代码走;代码自相矛盾的,以已在线上执行的那条为准,另一条列为平台落地项。 技能作者只需看每条的「技能侧怎么写」;「平台落地项」是给平台维护者的,不影响技能写法。


ISSUE-1 · workspace_dir —— 已定案:由 executor 注入(2026-10 二次核对推翻首轮结论)​

定案:workspace_dir 是注入键,注入点在 backend/core/skills/executor.py 的 execute() 末段:

_w = compat.workspace_dir(merged_ctx) # = $AGENT_WORKSPACE_DIR/<role_id>/<session_id 或 shared>
if _w is not None:
merged_ctx.setdefault("workspace_dir", str(_w))

为什么之前判错:2026-08 的 grep 只搜了 "workspace_dir": 与 ["workspace_dir"] = 两种写法,漏了 setdefault(...); 2026-10 首轮只拿到 routers,看到 build_runtime_ctx / _build_skill_runtime_ctx / _run_async_skill 三处都不写这个键, 就沿用了「不注入」。拿到 executor.py 后确认:这三条线最后都调 executor.execute,键在那里补上。

覆盖面:对话线、call_skill、页面面板、试运行、链、异步后台全部经 executor.execute,都有。 唯一缺失:合并后的 role_id 为空(如面板请求没带 role_id 时 _build_skill_runtime_ctx 写入的 role_id="" 覆盖了执行器参数)。 子进程:SKILL_CONTEXT 里有同名键(字符串可序列化),另有环境变量 SKILL_WORKSPACE(compat.build_skill_env,同值)。

技能侧怎么写:ctx.get("workspace_dir"),缺则按同式自推兜底(code-facts §4 _workspace(ctx))。

连带结论:此前点名的两个市场技能不需要为工作区路径修改—— trade-macro 的 (ctx or {}).get("workspace_dir") or os.getcwd() 与 xkeyai_image 的 _workspace_dir() 都先读 workspace_dir,正常执行时拿到的就是注入值,回退分支走不到。它们当初被点名,只是因为 2026-08 grep 时恰好搜到这两处在读 这个键,被当作「读了却拿空」的样本——这个前提不成立。(xkeyai_image 另有与工作区无关的信封问题,见其修订说明。)

平台落地项:无。


ISSUE-2 · datatable 结构类鉴权 —— 已定案:owner / admin​

定案:结构类操作(create_table / add_field / update_field / delete_field / delete_table,及 SQL 通道的 CREATE / 结构变更)仅 team_role ∈ {owner, admin}。即规范 §7.2 原文。

证据(2026-10):

  • 正式在线接口 backend/api/routers/nocodb.py(Web 数据管理,/api/v1/nocodb/*)对建表 / 加改删字段 / 删表 / 只读 SQL / 授权管理全部走 _require_struct_admin:team_role not in {"owner","admin"} → 403。
  • team_role 判定(nocodb._resolve_team_role,与对话线 roles_chat_helpers 解析 SkillRunContext.team_role 同口径): 用户所属团队 Team.owner_id == user_id → owner;否则 TeamMember.role;都取不到 → member。
  • 2026-08 记录的「团队关联角色(含 member)可建表、子账号不可」在任何代码里都没有对应实现:代码里「子账号」= 非 owner 的团队成员(topology.py / org_backup.py),而线上接口恰恰允许 admin 子账号改结构、禁止 member。 该规则与正式代码冲突,撤回。

技能侧怎么写:

  • 技能线(datatable handler)的两处判断仍是注释状态(见下方落地项),经 call_skill 调用时任何角色都能建表—— 不要把「会被拒」当安全边界。
  • 只该由管理员做的结构操作,技能自己先判:ctx.get("team_role") in ("owner", "admin"),否则返回 {"success": False, "error_type": "config", "non_retriable": True, "error": "仅团队 owner/admin 可修改表结构", "user_message": …}。 页面面板线不注入 team_role,按缺失拒绝。

平台落地项:恢复 skills/builtin/datatable/handler.py 两处注释(约 755、1010 行),并对缺失 team_role fail-closed:

_tr = (ctx.get("team_role") or "").strip()
if action in _STRUCT_ACTIONS and _tr not in _ADMIN_TEAM_ROLES:
return {"success": False, "error_type": "config", "non_retriable": True,
"error": f"结构类操作仅 owner/admin,当前 team_role={_tr or '空'}",
"user_message": "只有团队管理员(owner/admin)可以新建表、修改结构或删除表。"}
# SQL 建表分支(_stmt in ("create","alter_add_unique"))同样接一份

各执行线的 team_role 现状(2026-10 按 pipeline.py / skills.py / roles_chat_helpers.py 核对)——恢复鉴权后, datatable 读 ctx.get("team_role", "member"),拿不到就是 member(会被拒):

线team_role 来源恢复后 owner/admin 能否改结构
对话线roles_chat_helpers 解析(Team.owner_id / TeamMember.role)写进 SkillRunContext能
技能内 call_skill_CALL_PASS_BASE 透传调用方的值能(随调用方)
页面面板 / 试运行 / 下拉选项 / 链试跑(_build_skill_runtime_ctx)原先不注入 → member。本次随附 skills.py 补丁,按同口径注入打补丁后能
异步后台固定上下文只含词表键,无 team_role不能(datatable 不是异步技能,不受影响)
技能链(chain 型技能 / /chain/test)runner _to_run_context 原先缺失时塞 member;本次 runner.py 补丁改为留空,交给 pipeline 解析能(按链 ctx 里的 user_id)
定时任务 steps(skill_schedule)已核对 scheduler_handlers.py:不走 runner,自己逐步调 pipeline.execute_skill;SkillRunContext 填了 user_id=action["user_id"](任务创建人),未填 team_role → 由 pipeline 按创建人解析创建人是 owner/admin 就能
定时任务(instruction 型)起一条 scheduler 渠道会话(user_id = 创建人)跑完整对话循环,team_role 走对话线解析同上
定时触发工作流(workflow 型)trigger_workflow 不带 user_id;工作流上下文里没有 user_id 时按 member不能(如需要,由 extra_context 传入 user_id,未核对 automate 是否读取)
工作流「执行技能」automate._run_skill_node 构造 SkillRunContext 不填 team_role → 由 pipeline 按工作流上下文的 user_id 解析;没有 user_id 则 member取决于工作流的 user_id

统一兜底(本次 pipeline.py 补丁):SkillRunContext.team_role 默认值由 member 改为空串;build_runtime_ctx 发现为空时按 user_id 用同一口径解析(resolve_team_role),解析不出才 member。这样链、定时任务、工作流不用各自改,automate.py 无需改动。 定时任务执行端已于 2026-10 按 scheduler_handlers.py 核对:skill_schedule 直接把任务记录里的 user_id 放进 SkillRunContext, 无需额外修改。剩余边角:定时触发的工作流拿不到 user_id,其中的建表步骤按 member 处理(多数工作流只读写数据,不受影响)。


ISSUE-3 · ctx["db"] 预注入下线 —— 规则已定,迁移进行中​

定案:新技能直连库一律 db_factory 现开现还、不读 ctx["db"](spec §7A、code-facts §3.7)。这是写法约束,不是运行时强制。

现状(2026-10 按 executor.py / pipeline.py 核对):SELF_ACQUIRE_SKILLS 已扩到 9 个——datatable trade-bot trade-hltrade trade-research trade-factor trade-regimecalc trade-macro trade-okxbn-kline trade-backtest。名单内技能在 call_skill 不预开、 在 pipeline 不开 skill_scope(db=None)。名单外技能仍会拿到预开的 ctx["db"];页面 / 试运行线(请求级会话)、异步后台(懒会话)也注入。

下线路径:

  1. 各直连技能逐个改成 _db() 现开现还。
  2. 每迁一个,加入 executor 的 SELF_ACQUIRE_SKILLS,使 call_skill / pipeline 不再为它预开。
  3. 全部迁完后移除各处预开 / 注入,runtime-context / spec §4.3 的 db 行改「已移除」。

在迁完前:检查器对读 ctx["db"] 报 WARN(建议改 db_factory),不报 ERROR。


2026-10 新增定案(routers 核对,详见 code-facts.md §5)​

出入点定案(按代码)改在哪
入口函数签名安装预检要求 async def execute(input_data, runtime_context);create_skill / edit_skill 把预检问题当拦截SKILL.md 第 1 条、type-handler-python.md、模板、检查器
页面动作网关只按 action.enum 挡未知动作;x-actions / invocable_from / structural 不再校验(40303 已不存在)ui-panel.md、input-schema.md §8
页面驱动身份带可信 session_id 时解析完整 actor_*;不再「工号强制为空」;team_role 原不注入(本次随附 skills.py 补丁注入);channel 不可依赖ui-panel.md §5、runtime-context.md §9
外部面板 JWTheader 无 kid;aud = URL netloc;公钥端点 /api/v1/skills/panel/public-key(PEM)ui-panel.md §8
失败预算FAIL_PER_TOOL 默认 4、FAIL_TOTAL 默认 8、同参第 4 次判死循环;可恢复类不计数output-envelope.md §2、spec §6.1
墙钟技能墙钟默认 600 秒(SKILL_WALL_DEFAULT,可声明 wall_sec 至 1800);对话线外层 TOOL_WALL_SEC 1800(原写 240)output-envelope.md §7、spec §8
display_only对话线未实现,只有追加语义output-envelope.md §3、spec §6.2
attachments 结构经 build_ctx 归一为 {type, att_type, filename, local_path, url}——规范原文正确(首轮只看 routers 误判,已撤回)runtime-context.md §7
async 后台 provider后台同走 executor.execute,provider 照常注入llm-call.md、spec §10.5
配置项声明控制台表单读顶层 env 等键;未声明时按正文嗅探config-secrets.md
frontmatter 读取平台从顶层读 category / cost-tier;category 只认 13 个值;YAML 失败退逐行解析SKILL.md、模板、checklist
技能链保存校验链名 ^[a-z][a-z0-9_]*$、别名规则、{入参} 必须声明且被用、$steps 只能引前序、按 output_schema 校验字段、禁链套链chain.md
API 型文档技能有 openapi / endpoints_whitelist 或 skillClass: *api-skill 即走端点执行器type-skill-md.md

已定案速查(2026-08,在 spec-revised.md 标 【订正 2026-08】)​

出入点定案
create_table 字段类型枚举(无 JSON/高精度数字)改文档 §7.5
create_table.fields 形状补文档 §7.3
call_skill 返回不包 data改文档 §9.1
send_message web 用 session_id / 成功判据改文档 §9.2
user_message 可当失败原因补文档 §6.1
filters 残留引用 non_retriable补文档 §7.4
allow_sql 保留未启用改文档 §4.3 标注
入口第二参数默认值文档从严,维持「不得给」,标订正
直连库:db_factory 现开现还、不读 ctx["db"]新增 spec §7A;§4.3 / §7.8 / §11 订正;下线迁移见 ISSUE-3