feat(ack): add structured worker model routing
This commit is contained in:
@@ -31,6 +31,7 @@ from yaml_subset import (
|
||||
load_yaml_subset,
|
||||
make_unique_pyyaml_loader,
|
||||
)
|
||||
from worker_profiles import validate_routing_document
|
||||
|
||||
STATUS_ENUM = {
|
||||
"open",
|
||||
@@ -46,7 +47,16 @@ MAX_ROUNDS = 3
|
||||
KNOWLEDGE_KINDS = {"guardrail", "pitfall", "verification"}
|
||||
KNOWLEDGE_CHECK_RESULTS = {"passed", "failed", "not_applicable"}
|
||||
KNOWLEDGE_REF_RE = re.compile(r"^K-[A-Z0-9][A-Z0-9-]*@[1-9][0-9]*$")
|
||||
TASK_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
||||
ATTEMPT_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*-A[1-9][0-9]*$")
|
||||
SEMVER_RE = re.compile(
|
||||
r"^(0|[1-9][0-9]*)\."
|
||||
r"(0|[1-9][0-9]*)\."
|
||||
r"(0|[1-9][0-9]*)"
|
||||
r"(?:-(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)"
|
||||
r"(?:\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?"
|
||||
r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$"
|
||||
)
|
||||
KNOWLEDGE_SCOPE_FIELDS = {
|
||||
"components",
|
||||
"paths",
|
||||
@@ -76,6 +86,14 @@ KNOWLEDGE_CHECK_FIELDS = {
|
||||
"checkedBy",
|
||||
"checkedAt",
|
||||
}
|
||||
DISPATCH_FIELDS = {
|
||||
"taskId",
|
||||
"dispatchId",
|
||||
"worker",
|
||||
"developer",
|
||||
"test",
|
||||
"rounds",
|
||||
}
|
||||
KNOWLEDGE_CANDIDATE_REQUIRED_FIELDS = {
|
||||
"kind",
|
||||
"title",
|
||||
@@ -461,6 +479,22 @@ def validate_builtin(data: dict) -> list[str]:
|
||||
"project.knowledgeFile 必须固定为 docs/ack/knowledge.yaml"
|
||||
)
|
||||
|
||||
ack_version = data.get("ackVersion")
|
||||
version_match = SEMVER_RE.fullmatch(ack_version) if isinstance(ack_version, str) else None
|
||||
if "ackVersion" in data and version_match is None:
|
||||
errors.append("ackVersion 必须是合法 SemVer(例如 0.10.0)")
|
||||
routing_required = (
|
||||
(isinstance(project, dict) and "orchestration" in project)
|
||||
or "workerReceipts" in data
|
||||
or (
|
||||
version_match is not None
|
||||
and (int(version_match.group(1)), int(version_match.group(2)))
|
||||
>= (0, 10)
|
||||
)
|
||||
)
|
||||
if routing_required:
|
||||
errors.extend(validate_routing_document(data))
|
||||
|
||||
if "summary" in data:
|
||||
summary = data["summary"]
|
||||
if not isinstance(summary, dict):
|
||||
@@ -494,6 +528,10 @@ def validate_builtin(data: dict) -> list[str]:
|
||||
errors.append(f"{where}: id 必须是非空字符串")
|
||||
else:
|
||||
where = f"tasks[{i}] {tid}"
|
||||
if routing_required and TASK_ID_RE.fullmatch(tid) is None:
|
||||
errors.append(
|
||||
f"{where}: v0.10 自动路由 id 只允许字母、数字、点、下划线和连字符"
|
||||
)
|
||||
if tid in seen_ids:
|
||||
errors.append(f"{where}: id 重复")
|
||||
seen_ids.add(tid)
|
||||
@@ -533,6 +571,12 @@ def validate_builtin(data: dict) -> list[str]:
|
||||
dispatch = {}
|
||||
else:
|
||||
dispatch = task["dispatch"]
|
||||
reject_unknown_fields(
|
||||
dispatch,
|
||||
DISPATCH_FIELDS,
|
||||
f"{where}.dispatch",
|
||||
errors,
|
||||
)
|
||||
validate_string_fields(
|
||||
dispatch,
|
||||
{"taskId", "dispatchId", "worker"},
|
||||
|
||||
Reference in New Issue
Block a user