mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 22:11:58 +00:00
83 lines
5.0 KiB
Python
83 lines
5.0 KiB
Python
"""能力登记与登记的端点(应用平台 A6,docs/design/app-platform-and-look.md §2.6、§3.9)。
|
||
|
||
capabilities 一行 = 图里一个可调用的工具(主键就是图里写的工具名),分两层:
|
||
- 系统同步:内置工具、数据源、自定义工具、MCP 启动时和各自增删改时同步进来(effect_system、params_schema、
|
||
source_hash、synced_at、missing);
|
||
- 人工治理:effect、approval、unattended_write、returns_schema、tabular、fields、masked、credential_mode、lookup、
|
||
endpoint_id。每改一次 version 加一,运行发起时把用到的能力的治理快照固定下来(Run.options["capabilities"])。
|
||
|
||
endpoints 是管理员登记的外部系统:按环境(test / prod)存 base_url 和认证头(值加密)。只有登记的端点能开内网访问;
|
||
模型给出的任意地址照旧走 tools/net.py 的完整 SSRF 检查。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from datetime import datetime
|
||
from typing import Any
|
||
|
||
from sqlalchemy import Integer, String, Text
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.db.base import Base, TimestampMixin, new_id
|
||
|
||
#: 能力对外部世界的效果。dynamic:同一个工具看这一次的参数定(可写数据源上的 db_query__:查询只读、DML 是写)
|
||
EFFECTS = ("read", "write", "dynamic")
|
||
#: 审批:inherit 跟三档信任;confirm 总要确认;none 只读能力在正式运行里免审批
|
||
APPROVALS = ("inherit", "confirm", "none")
|
||
#: 凭据:service 服务凭据;service_on_behalf 服务凭据 + AgentLab 签发的身份断言(不存用户自己的 token)
|
||
CREDENTIAL_MODES = ("service", "service_on_behalf")
|
||
|
||
|
||
class Capability(Base, TimestampMixin):
|
||
__tablename__ = "capabilities"
|
||
|
||
name: Mapped[str] = mapped_column(String(200), primary_key=True)
|
||
# 所属系统:数据源名、端点名、MCP 服务名、builtin、custom
|
||
system: Mapped[str] = mapped_column(String(100), default="")
|
||
title: Mapped[str] = mapped_column(String(200), default="")
|
||
description: Mapped[str] = mapped_column(Text, default="")
|
||
params_schema: Mapped[dict[str, Any]] = mapped_column(default=dict)
|
||
returns_schema: Mapped[dict[str, Any] | None] = mapped_column(default=None)
|
||
# 端点返回落成表格:{"rows": "/data/items", "columns": {"单号": "/id", "金额": "/amount"}}。声明了才能作证
|
||
tabular: Mapped[dict[str, Any] | None] = mapped_column(default=None)
|
||
# 同步时得出的效果(数据源可写为 dynamic,内置工具按 ToolSpec.dangerous,MCP 的 readOnlyHint 只当建议)
|
||
effect_system: Mapped[str] = mapped_column(String(20), default="dynamic")
|
||
# 治理后的效果;为空表示还没人确认过,按 effect_system 算
|
||
effect: Mapped[str | None] = mapped_column(String(20), default=None)
|
||
approval: Mapped[str] = mapped_column(String(20), default="inherit")
|
||
unattended_write: Mapped[bool] = mapped_column(default=False)
|
||
# 返回字段的语义,按 JSON 指针:{"/amount": {"label": 项, "unit": 项, ...}},「项」的形状同数据目录
|
||
# (data/catalog.py:{value, source, status, note, reason, updated_at})
|
||
fields: Mapped[dict[str, Any]] = mapped_column(default=dict)
|
||
# 遮罩字段(JSON 指针);查看、快照、视图都按它遮
|
||
masked: Mapped[list[Any]] = mapped_column(default=list)
|
||
credential_mode: Mapped[str] = mapped_column(String(30), default="service")
|
||
endpoint_id: Mapped[str | None] = mapped_column(String(32), default=None)
|
||
# 按幂等键查写入结果用的能力名(结果未知时自动核实)
|
||
lookup: Mapped[str | None] = mapped_column(String(200), default=None)
|
||
version: Mapped[int] = mapped_column(Integer, default=1)
|
||
source_hash: Mapped[str | None] = mapped_column(String(64), default=None)
|
||
synced_at: Mapped[datetime | None] = mapped_column(default=None)
|
||
# 来源已经删掉了(数据源、自定义工具、MCP 工具不在了)。不删行:运行和发布记录还引用它的版本
|
||
missing: Mapped[bool] = mapped_column(default=False)
|
||
updated_by: Mapped[str | None] = mapped_column(String(100), default=None)
|
||
|
||
|
||
class Endpoint(Base, TimestampMixin):
|
||
"""登记的外部系统。
|
||
|
||
environments = {"test": {...}, "prod": {...}},每个环境:
|
||
base_url、headers(值经 core/crypto 加密,接口只回掩码)、allow_intranet(只有管理员能开)、verify_tls。
|
||
正式运行走 prod;探索运行走 test,没有 test 时演练(不发送,记 simulated)。
|
||
"""
|
||
|
||
__tablename__ = "endpoints"
|
||
|
||
id: Mapped[str] = mapped_column(String(32), primary_key=True, default=new_id)
|
||
name: Mapped[str] = mapped_column(String(100), unique=True)
|
||
description: Mapped[str] = mapped_column(Text, default="")
|
||
environments: Mapped[dict[str, Any]] = mapped_column(default=dict)
|
||
idempotency_header: Mapped[str] = mapped_column(String(100), default="Idempotency-Key")
|
||
timeout_s: Mapped[int] = mapped_column(Integer, default=20)
|
||
version: Mapped[int] = mapped_column(Integer, default=1)
|
||
updated_by: Mapped[str | None] = mapped_column(String(100), default=None)
|