落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Schema / 字段合同包。
|
||||
|
||||
校验规则读 contracts JSON;本包不做自然语言抽取。
|
||||
"""
|
||||
|
||||
from agent.schema.contracts_loader import (
|
||||
contracts_dir,
|
||||
load_contract,
|
||||
require_formal_contract,
|
||||
resolve_contract_path,
|
||||
)
|
||||
from agent.schema.field_validate import validate_required_fields_shell
|
||||
|
||||
__all__ = [
|
||||
"contracts_dir",
|
||||
"load_contract",
|
||||
"require_formal_contract",
|
||||
"resolve_contract_path",
|
||||
"validate_required_fields_shell",
|
||||
]
|
||||
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
字段 / 字典合同加载。
|
||||
|
||||
本文件职责:从仓库 contracts/ 读 JSON;优先正式文件名,其次 PLACEHOLDER。
|
||||
没读到真合同前,业务校验代码不得假装已激活字段规则(prompt/05)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def contracts_dir() -> Path:
|
||||
"""
|
||||
定位仓库 contracts 目录。
|
||||
|
||||
查找顺序:inquiry-agent 上一级 / 再上一级(兼容拷贝到 C:\\ytd)。
|
||||
"""
|
||||
here = Path(__file__).resolve()
|
||||
for parent in here.parents:
|
||||
candidate = parent / "contracts"
|
||||
if candidate.is_dir():
|
||||
return candidate
|
||||
# 回退:与 agent 包同级仓库根的常见布局
|
||||
return here.parents[3] / "contracts"
|
||||
|
||||
|
||||
def _load_json_file(path: Path) -> dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def resolve_contract_path(stem: str) -> Optional[Path]:
|
||||
"""
|
||||
解析合同文件路径。
|
||||
|
||||
stem 例:inquiry-required-fields-v1 / tms-dictionary-projection-v2
|
||||
优先 `{stem}.json`,否则 `{stem}.PLACEHOLDER.json`。
|
||||
"""
|
||||
root = contracts_dir()
|
||||
formal = root / f"{stem}.json"
|
||||
if formal.is_file():
|
||||
return formal
|
||||
placeholder = root / f"{stem}.PLACEHOLDER.json"
|
||||
if placeholder.is_file():
|
||||
return placeholder
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def load_contract(stem: str) -> dict[str, Any]:
|
||||
"""
|
||||
加载合同 JSON。
|
||||
|
||||
返回:dict;文件缺失抛 FileNotFoundError。
|
||||
is_placeholder:由 meta 或文件名推断,供调用方拒绝「用占位做生产校验」。
|
||||
"""
|
||||
path = resolve_contract_path(stem)
|
||||
if path is None:
|
||||
raise FileNotFoundError(f"合同文件不存在: {stem}(目录 {contracts_dir()})")
|
||||
data = _load_json_file(path)
|
||||
is_ph = "PLACEHOLDER" in path.name or str(data.get("schemaVersion", "")).endswith(
|
||||
"placeholder"
|
||||
)
|
||||
data = dict(data)
|
||||
data["_meta"] = {
|
||||
"path": str(path),
|
||||
"is_placeholder": is_ph,
|
||||
"stem": stem,
|
||||
}
|
||||
logger.info(
|
||||
"已加载合同 stem=%s placeholder=%s path=%s",
|
||||
stem,
|
||||
is_ph,
|
||||
path.name,
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
def require_formal_contract(stem: str) -> dict[str, Any]:
|
||||
"""
|
||||
加载且必须为正式文件(非 PLACEHOLDER)。
|
||||
|
||||
骨架联调请用 load_contract;写字段校验业务前必须走本函数。
|
||||
"""
|
||||
data = load_contract(stem)
|
||||
if data.get("_meta", {}).get("is_placeholder"):
|
||||
raise RuntimeError(
|
||||
f"合同仍为占位,禁止做业务校验: {stem}。"
|
||||
"请将正式 JSON 放到 contracts/(见 _ref/prod-pull 对照)"
|
||||
)
|
||||
return data
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
字段合同校验入口壳。
|
||||
|
||||
本文件职责:暴露 validate_required_fields_shell;正式规则读 contracts JSON 后再实现。
|
||||
禁止:在未 require_formal_contract 时假装已激活字段;禁止用正则替代模型语义。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from agent.schema.contracts_loader import load_contract, require_formal_contract
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def validate_required_fields_shell(
|
||||
*,
|
||||
facts: dict[str, Any],
|
||||
business_line: str = "",
|
||||
require_formal: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
字段校验空壳。
|
||||
|
||||
返回结构固定:ok / implemented / missing / errors。
|
||||
implemented=False 表示规则引擎尚未接入(框架阶段预期)。
|
||||
"""
|
||||
stem = "inquiry-required-fields-v1"
|
||||
try:
|
||||
contract = (
|
||||
require_formal_contract(stem) if require_formal else load_contract(stem)
|
||||
)
|
||||
except (FileNotFoundError, RuntimeError) as exc:
|
||||
return {
|
||||
"ok": False,
|
||||
"implemented": False,
|
||||
"missing": [],
|
||||
"errors": [str(exc)],
|
||||
"business_line": business_line,
|
||||
}
|
||||
|
||||
is_ph = bool(contract.get("_meta", {}).get("is_placeholder"))
|
||||
logger.info(
|
||||
"schema.validate_shell line=%s placeholder=%s facts_keys=%s(未跑激活规则)",
|
||||
business_line or "-",
|
||||
is_ph,
|
||||
sorted(facts.keys()),
|
||||
)
|
||||
return {
|
||||
"ok": False,
|
||||
"implemented": False,
|
||||
"missing": [],
|
||||
"errors": ["field_activation_rules_not_implemented"],
|
||||
"business_line": business_line,
|
||||
"contract_placeholder": is_ph,
|
||||
}
|
||||
Reference in New Issue
Block a user