tf-rewardkit 1.6.3__tar.gz → 1.6.4.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/PKG-INFO +1 -1
  2. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/pyproject.toml +1 -1
  3. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/__init__.py +0 -1
  4. tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/_judge_args.py +198 -0
  5. tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/agentic.py +136 -0
  6. tf_rewardkit-1.6.4.dev0/src/rewardkit/workflow/component/llm_judge.py +145 -0
  7. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/executor.py +0 -4
  8. tf_rewardkit-1.6.3/src/rewardkit/workflow/component/_source.py +0 -188
  9. tf_rewardkit-1.6.3/src/rewardkit/workflow/component/agentic.py +0 -184
  10. tf_rewardkit-1.6.3/src/rewardkit/workflow/component/llm_judge.py +0 -233
  11. tf_rewardkit-1.6.3/src/rewardkit/workflow/converter/__init__.py +0 -19
  12. tf_rewardkit-1.6.3/src/rewardkit/workflow/converter/_convert.py +0 -467
  13. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/LICENSE +0 -0
  14. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/README.md +0 -0
  15. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/__init__.py +0 -0
  16. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/__main__.py +0 -0
  17. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/agents.py +0 -0
  18. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/compare.py +0 -0
  19. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/__init__.py +0 -0
  20. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/_command.py +0 -0
  21. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/_trajectory.py +0 -0
  22. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_contains.py +0 -0
  23. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_matches.py +0 -0
  24. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_output_matches_regex.py +0 -0
  25. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/command_succeeds.py +0 -0
  26. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/csv_cell_equals.py +0 -0
  27. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/diff_ratio.py +0 -0
  28. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_contains.py +0 -0
  29. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_contains_regex.py +0 -0
  30. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_exists.py +0 -0
  31. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_matches.py +0 -0
  32. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/file_not_exists.py +0 -0
  33. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/files_equal.py +0 -0
  34. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/http_response_contains.py +0 -0
  35. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/http_status_equals.py +0 -0
  36. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/image_similarity.py +0 -0
  37. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/image_size_equals.py +0 -0
  38. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/json_key_equals.py +0 -0
  39. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/json_path_equals.py +0 -0
  40. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/sqlite_query_equals.py +0 -0
  41. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_tool_not_used.py +0 -0
  42. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_tool_used.py +0 -0
  43. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/trajectory_turn_count.py +0 -0
  44. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/criteria/xlsx_cell_equals.py +0 -0
  45. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/isolation.py +0 -0
  46. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/judges.py +0 -0
  47. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/models.py +0 -0
  48. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/agent.md +0 -0
  49. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/llm.md +0 -0
  50. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/prompts/llm_trajectory.md +0 -0
  51. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/reward.py +0 -0
  52. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/runner.py +0 -0
  53. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/session.py +0 -0
  54. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/trajectory.py +0 -0
  55. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/attribution.py +0 -0
  56. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/cli.py +0 -0
  57. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/README.md +0 -0
  58. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/__init__.py +0 -0
  59. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/__init__.py +0 -0
  60. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/budget.py +0 -0
  61. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/rubric.py +0 -0
  62. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/salvage.py +0 -0
  63. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/_internal/scoring.py +0 -0
  64. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/code.py +0 -0
  65. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/consume_upstream.py +0 -0
  66. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/contracts.py +0 -0
  67. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/criterion.py +0 -0
  68. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/do_nothing.py +0 -0
  69. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/fail.py +0 -0
  70. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/llm_stub.py +0 -0
  71. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/__init__.py +0 -0
  72. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_code_methods.py +0 -0
  73. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_compute.py +0 -0
  74. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_content.py +0 -0
  75. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_contract.py +0 -0
  76. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_ctx.py +0 -0
  77. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_faults.py +0 -0
  78. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_html_render.py +0 -0
  79. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_pptx_render.py +0 -0
  80. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_render_common.py +0 -0
  81. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_tagging.py +0 -0
  82. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_visual.py +0 -0
  83. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/_vlm.py +0 -0
  84. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/aggregate.py +0 -0
  85. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/content.py +0 -0
  86. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/gate.py +0 -0
  87. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/render.py +0 -0
  88. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/tag.py +0 -0
  89. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/ppt_judge/visual.py +0 -0
  90. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/produce_value.py +0 -0
  91. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/component/registry.py +0 -0
  92. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/context.py +0 -0
  93. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/diagram.py +0 -0
  94. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/errors.py +0 -0
  95. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/loader.py +0 -0
  96. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/model_service.py +0 -0
  97. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/plan.py +0 -0
  98. {tf_rewardkit-1.6.3 → tf_rewardkit-1.6.4.dev0}/src/rewardkit/workflow/scoring.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tf-rewardkit
3
- Version: 1.6.3
3
+ Version: 1.6.4.dev0
4
4
  Summary: Lightweight grading toolkit for environment-based tasks.
5
5
  Keywords: grading,evaluation,rewards,llm,agents,benchmarks
6
6
  Author: benediktstroebl
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tf-rewardkit"
3
- version = "1.6.3"
3
+ version = "1.6.4.dev0"
4
4
  description = "Lightweight grading toolkit for environment-based tasks."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -11,7 +11,6 @@ Prefect 3 调度执行。
11
11
  - ``errors`` 框架级 Failure 类型:错误形状的载体
12
12
  - ``context`` 共享运行时服务
13
13
  - ``component`` 组件注册表与随框架组件
14
- - ``converter`` 转换工具:rubric.json → workflow.toml
15
14
 
16
15
  完整契约见 docs/judging-graph-protocol.md。
17
16
  """
@@ -0,0 +1,198 @@
1
+ """args 传参判分组件(``llm_judge@1`` / ``agentic@1``)的共享私有helper。
2
+
3
+ 两个组件不经任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个
4
+ node 对应一次 ``arun_llm`` / ``arun_agent`` 调用。本模块承载三块共享逻辑:
5
+
6
+ - ``criteria`` 槽解析:TOML inline table 的数组,元素字段对齐存量 judge
7
+ TOML 的 ``[[criterion]]`` 表(``description`` 必填,其余选填、缺省值同
8
+ 存量配置);元素形状校验失败返回原因串由调用方按 unjudged 处置——评分
9
+ 项配置问题是清单问题,不是节点运行失败;
10
+ - 覆盖链解析:model 链 ``context.model_name``(CLI)> ``REWARDKIT_MODEL``
11
+ > 额外 env(如 ``REWARDKIT_JUDGE``)> args 槽 > 组件缺省;agent 链
12
+ ``context.judge``(CLI)> agent 专用 env > ``REWARDKIT_JUDGE``(仅当值
13
+ 在 known_agents 注册表内才采用——部署里该变量常被设成 LLM 模型名)>
14
+ args 槽 > 组件缺省;
15
+ - ``files`` 槽锚定:相对路径一律按 workspace 根解析(判分调用直读路径
16
+ 相对进程 CWD,而 workspace 是独立注入的)。
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import os
22
+ from pathlib import Path
23
+ from typing import Any
24
+
25
+ from rewardkit.models import Binary, Criterion, Likert, Numeric, Rubric
26
+
27
+ JUDGE_NAME_ENV = "REWARDKIT_JUDGE"
28
+ """通用 judge 名覆盖变量(LLM 侧作模型名通道,agent 侧须过注册表门槛)。"""
29
+
30
+ MODEL_NAME_ENV = "REWARDKIT_MODEL"
31
+ """模型名覆盖变量(两个组件的 model 链共用)。"""
32
+
33
+ _CRITERION_ENTRY_KEYS = frozenset(
34
+ {
35
+ "description",
36
+ "type",
37
+ "name",
38
+ "id",
39
+ "points",
40
+ "levels",
41
+ "min",
42
+ "max",
43
+ "weight",
44
+ "files",
45
+ "negate",
46
+ "optional",
47
+ }
48
+ )
49
+
50
+
51
+ def _output_format_for_entry(entry: dict[str, Any]) -> Any:
52
+ """元素 type/points/levels/min/max → OutputFormat(映射对齐存量
53
+ ``runner._build_criteria_from_toml``:likert → ``Likert(points)``、
54
+ numeric → ``Numeric(min, max)``、rubric → ``Rubric(levels)``、其余 →
55
+ ``Binary()``)。"""
56
+ ctype = entry.get("type", "binary")
57
+ if ctype == "likert":
58
+ return Likert(points=entry.get("points", 5))
59
+ if ctype == "numeric":
60
+ return Numeric(min=entry.get("min", 0.0), max=entry.get("max", 1.0))
61
+ if ctype == "rubric":
62
+ return Rubric(levels=tuple(entry.get("levels", ())))
63
+ return Binary()
64
+
65
+
66
+ def _validate_entry(entry: dict[str, Any], index: int) -> str | None:
67
+ """单元素字段级校验;返回原因串或 None(合法)。"""
68
+ unknown = set(entry) - _CRITERION_ENTRY_KEYS
69
+ if unknown:
70
+ return f"criteria 元素 {index} 含未知字段:{sorted(unknown)}"
71
+ description = entry.get("description")
72
+ if not isinstance(description, str) or not description.strip():
73
+ return f"criteria 元素 {index} 缺少非空 description 字段"
74
+ ctype = entry.get("type", "binary")
75
+ if ctype not in ("binary", "likert", "numeric", "rubric"):
76
+ return f"criteria 元素 {index} 的 type 非法:{ctype!r}"
77
+ if "points" in entry and not isinstance(entry["points"], int):
78
+ return f"criteria 元素 {index} 的 points 必须是整数"
79
+ if "levels" in entry and not (
80
+ isinstance(entry["levels"], (list, tuple))
81
+ and all(isinstance(level, str) for level in entry["levels"])
82
+ ):
83
+ return f"criteria 元素 {index} 的 levels 必须是字符串数组"
84
+ for field in ("min", "max", "weight"):
85
+ if field in entry and not isinstance(entry[field], (int, float)):
86
+ return f"criteria 元素 {index} 的 {field} 必须是数值"
87
+ for field in ("negate", "optional"):
88
+ if field in entry and not isinstance(entry[field], bool):
89
+ return f"criteria 元素 {index} 的 {field} 必须是布尔"
90
+ if "files" in entry and not (
91
+ isinstance(entry["files"], (list, tuple))
92
+ and all(isinstance(item, str) for item in entry["files"])
93
+ ):
94
+ return f"criteria 元素 {index} 的 files 必须是字符串数组"
95
+ for field in ("name", "id"):
96
+ if field in entry and entry[field] is not None and not isinstance(entry[field], str):
97
+ return f"criteria 元素 {index} 的 {field} 必须是字符串"
98
+ return None
99
+
100
+
101
+ def parse_criteria_entries(
102
+ entries: Any, workspace_root: Any
103
+ ) -> tuple[list[Criterion], list[float], str | None]:
104
+ """解析 ``criteria`` 槽,返回 ``(criteria, weights, 原因串)``。
105
+
106
+ 原因串非 None 表示槽非法(调用方按 unjudged 处置);合法时原因串为
107
+ None,weights 与 criteria 按下标一一对应(元素 ``weight`` 缺省 1.0)。
108
+ """
109
+ if isinstance(entries, (str, dict)) or not isinstance(entries, (list, tuple)):
110
+ return [], [], "criteria 必须是评分项表的数组(args 的 array 槽)"
111
+ if not entries:
112
+ return [], [], "criteria 不能为空数组"
113
+
114
+ criteria: list[Criterion] = []
115
+ weights: list[float] = []
116
+ for index, entry in enumerate(entries):
117
+ if not isinstance(entry, dict):
118
+ return [], [], f"criteria 元素 {index} 必须是表,收到 {type(entry).__name__}"
119
+ reason = _validate_entry(entry, index)
120
+ if reason:
121
+ return [], [], reason
122
+ try:
123
+ output_format = _output_format_for_entry(entry)
124
+ criterion = Criterion(
125
+ description=entry["description"],
126
+ output_format=output_format,
127
+ name=entry.get("name") or None,
128
+ id=entry.get("id"),
129
+ files=abs_files(entry.get("files", ()), workspace_root),
130
+ negate=entry.get("negate", False),
131
+ optional=entry.get("optional", False),
132
+ )
133
+ except Exception as exc: # noqa: BLE001 - name/output_format 非法属清单问题
134
+ return [], [], f"criteria 元素 {index} 构造失败(name 或 output_format 非法):{exc}"
135
+ criteria.append(criterion)
136
+ weights.append(float(entry.get("weight", 1.0)))
137
+ return criteria, weights, None
138
+
139
+
140
+ def abs_files(entries: Any, workspace_root: Any) -> tuple[str, ...]:
141
+ """路径列表按 workspace 根锚定;绝对路径原样。"""
142
+ resolved = []
143
+ for entry in entries:
144
+ path = Path(str(entry))
145
+ resolved.append(str(path if path.is_absolute() else Path(workspace_root) / path))
146
+ return tuple(resolved)
147
+
148
+
149
+ def resolve_arg_files(files: Any, workspace_root: Any) -> tuple[str, ...]:
150
+ """``files`` 槽:单路径字符串或路径列表 → 按 workspace 根锚定;
151
+ 空值与不认识的形状落空元组。"""
152
+ if isinstance(files, str) and files:
153
+ return abs_files([files], workspace_root)
154
+ if isinstance(files, (list, tuple)) and files:
155
+ return abs_files(files, workspace_root)
156
+ return ()
157
+
158
+
159
+ def resolve_model(
160
+ context: Any,
161
+ slot: str | None,
162
+ *,
163
+ extra_envs: tuple[str, ...] = (),
164
+ default: str | None = None,
165
+ ) -> str | None:
166
+ """model 覆盖链:``context.model_name``(CLI)> ``REWARDKIT_MODEL`` >
167
+ ``extra_envs`` 逐个 > args 槽 > ``default``。"""
168
+ candidates = [getattr(context, "model_name", None), os.environ.get(MODEL_NAME_ENV)]
169
+ candidates += [os.environ.get(name) for name in extra_envs]
170
+ candidates += [slot, default]
171
+ for value in candidates:
172
+ if value:
173
+ return str(value)
174
+ return default
175
+
176
+
177
+ def resolve_agent(
178
+ context: Any,
179
+ slot: str | None,
180
+ *,
181
+ agent_env: str,
182
+ default: str,
183
+ ) -> str:
184
+ """agent 覆盖链:``context.judge``(CLI)> ``agent_env`` >
185
+ ``REWARDKIT_JUDGE``(仅当值在 known_agents 内才采用)> args 槽 >
186
+ ``default``。"""
187
+ from rewardkit.agents import known_agents
188
+
189
+ cli_judge = getattr(context, "judge", None)
190
+ if cli_judge:
191
+ return str(cli_judge)
192
+ env_agent = os.environ.get(agent_env)
193
+ if env_agent:
194
+ return env_agent
195
+ env_judge = os.environ.get(JUDGE_NAME_ENV)
196
+ if env_judge in known_agents():
197
+ return env_judge
198
+ return slot or default
@@ -0,0 +1,136 @@
1
+ """agentic 判分组件 ``agentic@1``:编码智能体 judge 的图内入口(args 传参薄封装)。
2
+
3
+ 不读任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个 node
4
+ 一次 ``arun_agent`` 调用。
5
+
6
+ - ``criteria`` 必填槽为评分项表的数组(元素字段与权重语义同
7
+ ``llm_judge@1``);
8
+ - 其余选填槽与 ``AgentJudge`` 字段逐字同名(``agent`` / ``model`` /
9
+ ``version`` / ``timeout`` / ``cwd`` / ``isolated`` / ``atif_trajectory``
10
+ / ``mode`` / ``mcp_servers``),另加 ``system_prompt``;槽不写即不传
11
+ 该字段,落 ``AgentJudge`` 自身缺省(``isolated`` 缺省 False 与宿主
12
+ 对齐,组件层不自造缺省);槽值非法(如 agent 不在注册表内)按
13
+ unjudged 处置;
14
+ - agent 覆盖链:``context.judge``(CLI --judge)> ``REWARDKIT_AGENT``
15
+ 环境变量 > ``REWARDKIT_JUDGE``(**仅当值在 known_agents 注册表内才
16
+ 采用**——该变量常被设成 LLM 模型名)> args ``agent`` > 组件缺省
17
+ ``codex``;agent 名的注册表校验由 AgentJudge 的 validator 兜底(非法
18
+ 名显式报错,错误消息含已知 agent 列表);
19
+ - model 覆盖链:``context.model_name`` > ``REWARDKIT_MODEL`` 环境变量 >
20
+ args ``model`` > None(AgentJudge 自身缺省);
21
+ - ``cwd`` 槽缺省时由 workspace 根兜底(``arun_agent`` 自身语义:
22
+ ``judge.cwd or workspace``);
23
+ - 产出 ``{"scores": [{"id", "score", "reasoning", "warnings", "weight",
24
+ "optional"}, ...], "output", "warnings", "judge_logs"}``(信封语义同
25
+ ``llm_judge@1``)。agentic 没有门控职责,判 0 分也是有效判定,**调用
26
+ 异常不由组件转 Failure**(冒泡为任务失败,由归因层收集);
27
+ ``criteria`` 槽非法 → unjudged。
28
+
29
+ 真实 Codex 执行的验证在 AP 题包与原生格式端到端验证中走过;仓库内
30
+ 测试用假 backend 打桩。
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ from typing import Any
36
+
37
+ from rewardkit.judges import arun_agent
38
+ from rewardkit.models import AgentJudge
39
+ from rewardkit.workflow.component._judge_args import (
40
+ parse_criteria_entries,
41
+ resolve_agent,
42
+ resolve_model,
43
+ )
44
+ from rewardkit.workflow.component.registry import InputSlot, component
45
+
46
+ AGENT_NAME_ENV = "REWARDKIT_AGENT"
47
+ DEFAULT_AGENT = "codex"
48
+
49
+
50
+ @component(
51
+ name="agentic",
52
+ version=1,
53
+ outputs=["verdict"],
54
+ inputs=[
55
+ InputSlot(
56
+ name="criteria",
57
+ accepted_types=("array",),
58
+ description="评分项表的数组,元素字段对齐存量 [[criterion]] 表",
59
+ ),
60
+ InputSlot(name="agent", required=False, accepted_types=("string",)),
61
+ InputSlot(name="model", required=False, accepted_types=("string",)),
62
+ InputSlot(name="version", required=False, accepted_types=("string",)),
63
+ InputSlot(name="timeout", required=False, accepted_types=("int",)),
64
+ InputSlot(name="cwd", required=False, accepted_types=("string",)),
65
+ InputSlot(name="isolated", required=False, accepted_types=("bool",)),
66
+ InputSlot(name="atif_trajectory", required=False, accepted_types=("string",)),
67
+ InputSlot(name="mode", required=False, accepted_types=("string",)),
68
+ InputSlot(name="mcp_servers", required=False, accepted_types=("array",)),
69
+ InputSlot(name="system_prompt", required=False, accepted_types=("string",)),
70
+ ],
71
+ )
72
+ async def agentic(
73
+ context,
74
+ criteria,
75
+ agent=None,
76
+ model=None,
77
+ version=None,
78
+ timeout=None,
79
+ cwd=None,
80
+ isolated=None,
81
+ atif_trajectory=None,
82
+ mode=None,
83
+ mcp_servers=None,
84
+ system_prompt=None,
85
+ ) -> dict[str, Any]:
86
+ """``arun_agent`` 的薄封装:评分项与调用配置全来自 args(见模块 docstring)。"""
87
+ root = context.workspace.root
88
+ criteria_objs, weights, reason = parse_criteria_entries(criteria, root)
89
+ if reason:
90
+ return {"unjudged": True, "reason": reason}
91
+
92
+ judge_kwargs: dict[str, Any] = {}
93
+ for key, value in (
94
+ ("version", version),
95
+ ("timeout", timeout),
96
+ ("cwd", cwd),
97
+ ("isolated", None if isolated is None else bool(isolated)),
98
+ ("atif_trajectory", atif_trajectory),
99
+ ("mode", mode),
100
+ ("mcp_servers", tuple(mcp_servers) if mcp_servers else None),
101
+ ):
102
+ if value is not None:
103
+ judge_kwargs[key] = value
104
+ try:
105
+ judge = AgentJudge(
106
+ agent=resolve_agent(context, agent, agent_env=AGENT_NAME_ENV, default=DEFAULT_AGENT),
107
+ model=resolve_model(context, model),
108
+ **judge_kwargs,
109
+ )
110
+ except Exception as exc: # noqa: BLE001 - 槽值非法属配置问题,按 unjudged
111
+ return {"unjudged": True, "reason": f"agentic 槽值非法:{exc}"}
112
+
113
+ result = await arun_agent(
114
+ judge,
115
+ criteria_objs,
116
+ weights,
117
+ workspace=str(root),
118
+ system_prompt=system_prompt,
119
+ )
120
+ all_scores = [
121
+ {
122
+ "id": c.id or score.name or f"criterion_{index}",
123
+ "score": score.value,
124
+ "reasoning": score.reasoning,
125
+ "warnings": list(result.warnings),
126
+ "weight": weights[index],
127
+ "optional": c.optional,
128
+ }
129
+ for index, (c, score) in enumerate(zip(criteria_objs, result.scores))
130
+ ]
131
+ return {
132
+ "scores": all_scores,
133
+ "output": result.output,
134
+ "warnings": list(result.warnings),
135
+ "judge_logs": list(result.judge_logs),
136
+ }
@@ -0,0 +1,145 @@
1
+ """判分组件 ``llm_judge@1``:LLM judge 的图内入口(args 传参薄封装)。
2
+
3
+ 不读任何清单文件:评分项与调用配置全部由图 ``args`` 传入,一个 node
4
+ 一次 ``arun_llm`` 调用。
5
+
6
+ - ``criteria`` 必填槽为评分项表的数组(元素字段对齐存量 judge TOML 的
7
+ ``[[criterion]]`` 表:``description`` 必填,``type`` / ``points`` /
8
+ ``levels`` / ``min`` / ``max`` / ``files`` / ``negate`` / ``optional`` /
9
+ ``name`` / ``id`` / ``weight`` 选填、缺省同存量配置);条目 ``weight``
10
+ 透传为 ``arun_llm`` 的 weights 入参与分数信封的 ``weight`` 键;
11
+ - 其余选填槽与 ``LLMJudge`` 字段逐字同名(``model`` / ``files`` /
12
+ ``mode`` / ``timeout`` / ``reasoning_effort`` / ``reference`` /
13
+ ``atif_trajectory``),另加 ``system_prompt``;槽不写即不传该字段,
14
+ 落 ``LLMJudge`` 自身缺省(mode=batched、timeout=300 等);槽值非法
15
+ (如 mode 不在枚举内)按 unjudged 处置;
16
+ - model 覆盖链:``context.model_name``(CLI --model)> ``REWARDKIT_MODEL``
17
+ 环境变量 > ``REWARDKIT_JUDGE`` > args ``model`` > 组件缺省;
18
+ - ``files`` 槽为组级共享(单路径字符串或路径列表),相对路径一律按
19
+ workspace 根解析(``arun_llm`` 直读路径相对进程 CWD,而 workspace 是
20
+ 独立注入的);条目级 ``files`` 仅 individual 模式生效(存量 arun_llm
21
+ 语义);batched 下被忽略——组件在该条目的 warnings 里记录提示,不
22
+ 静默丢失;
23
+ - 产出 ``{"scores": [{"id", "score", "reasoning", "warnings", "weight",
24
+ "optional"}, ...], "output", "warnings"}``(``score`` 键是交分信封
25
+ ``value`` 的别名,可直接标记 ``is_score_node``;``optional`` 进图级
26
+ 聚合);任一次调用异常 → Failure(error_kind 为 llm-error);
27
+ ``criteria`` 槽非法 → unjudged。
28
+
29
+ 模型调用经 ``context.model``(ModelService)的 ``acompletion`` 注入
30
+ arun_llm——占 ``max_concurrent_workflow`` 名额;注入的替身无
31
+ acompletion 时回退 litellm 直调。
32
+
33
+ 本组件不 import prefect(分层约束)。
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ from typing import Any
39
+
40
+ from rewardkit.judges import arun_llm
41
+ from rewardkit.models import LLMJudge
42
+ from rewardkit.workflow.component._judge_args import (
43
+ JUDGE_NAME_ENV,
44
+ parse_criteria_entries,
45
+ resolve_arg_files,
46
+ resolve_model,
47
+ )
48
+ from rewardkit.workflow.component.registry import InputSlot, component
49
+ from rewardkit.workflow.errors import Failure
50
+
51
+ DEFAULT_JUDGE_MODEL = "anthropic/claude-sonnet-5"
52
+ """judge 模型缺省(与 JudgeConfig.judge 的缺省一致,作文档锚点)。"""
53
+
54
+
55
+ @component(
56
+ name="llm_judge",
57
+ version=1,
58
+ outputs=["verdict"],
59
+ inputs=[
60
+ InputSlot(
61
+ name="criteria",
62
+ accepted_types=("array",),
63
+ description="评分项表的数组,元素字段对齐存量 [[criterion]] 表",
64
+ ),
65
+ InputSlot(name="model", required=False, accepted_types=("string",)),
66
+ InputSlot(name="files", required=False, accepted_types=("string", "array")),
67
+ InputSlot(name="mode", required=False, accepted_types=("string",)),
68
+ InputSlot(name="timeout", required=False, accepted_types=("int",)),
69
+ InputSlot(name="reasoning_effort", required=False, accepted_types=("string",)),
70
+ InputSlot(name="reference", required=False, accepted_types=("string",)),
71
+ InputSlot(name="atif_trajectory", required=False, accepted_types=("string",)),
72
+ InputSlot(name="system_prompt", required=False, accepted_types=("string",)),
73
+ ],
74
+ )
75
+ async def llm_judge(
76
+ context,
77
+ criteria,
78
+ model=None,
79
+ files=None,
80
+ mode=None,
81
+ timeout=None,
82
+ reasoning_effort=None,
83
+ reference=None,
84
+ atif_trajectory=None,
85
+ system_prompt=None,
86
+ ) -> Any:
87
+ """``arun_llm`` 的薄封装:评分项与调用配置全来自 args(见模块 docstring)。"""
88
+ root = context.workspace.root
89
+ criteria_objs, weights, reason = parse_criteria_entries(criteria, root)
90
+ if reason:
91
+ return {"unjudged": True, "reason": reason}
92
+
93
+ judge_kwargs: dict[str, Any] = {}
94
+ for key, value in (
95
+ ("mode", mode),
96
+ ("timeout", timeout),
97
+ ("reasoning_effort", reasoning_effort),
98
+ ("reference", reference),
99
+ ("atif_trajectory", atif_trajectory),
100
+ ):
101
+ if value is not None:
102
+ judge_kwargs[key] = value
103
+ try:
104
+ judge = LLMJudge(
105
+ model=resolve_model(context, model, extra_envs=(JUDGE_NAME_ENV,), default=DEFAULT_JUDGE_MODEL),
106
+ files=resolve_arg_files(files, root),
107
+ **judge_kwargs,
108
+ )
109
+ except Exception as exc: # noqa: BLE001 - 槽值非法属配置问题,按 unjudged
110
+ return {"unjudged": True, "reason": f"llm_judge 槽值非法:{exc}"}
111
+
112
+ per_item_warns: list[list[str]] = []
113
+ for c in criteria_objs:
114
+ warns_for_item: list[str] = []
115
+ if judge.mode == "batched" and c.files:
116
+ warns_for_item.append(
117
+ f"mode=batched:条目 {c.id or c.name} 的 files 被忽略"
118
+ "(组级 files 生效;条目级 files 需 mode=individual)"
119
+ )
120
+ per_item_warns.append(warns_for_item)
121
+
122
+ completion = getattr(context.model, "acompletion", None)
123
+ try:
124
+ scores, output, warns = await arun_llm(
125
+ judge, criteria_objs, weights, system_prompt, completion=completion
126
+ )
127
+ except Exception as exc: # noqa: BLE001 - 判分调用失败 = 节点失败
128
+ return Failure(
129
+ root_cause_node_id=context.node_id,
130
+ message=f"llm_judge 调用失败:{exc}",
131
+ error_kind="llm-error",
132
+ chain=(context.node_id,),
133
+ )
134
+ all_scores = [
135
+ {
136
+ "id": c.id or score.name or f"criterion_{index}",
137
+ "score": score.value,
138
+ "reasoning": score.reasoning,
139
+ "warnings": list(warns) + per_item_warns[index],
140
+ "weight": weights[index],
141
+ "optional": c.optional,
142
+ }
143
+ for index, (c, score) in enumerate(zip(criteria_objs, scores))
144
+ ]
145
+ return {"scores": all_scores, "output": output, "warnings": list(warns)}
@@ -56,7 +56,6 @@ from rewardkit.workflow.attribution import (
56
56
  is_unjudged,
57
57
  make_unjudged,
58
58
  )
59
- from rewardkit.workflow.component._source import clear_source_cache
60
59
  from rewardkit.workflow.component.registry import (
61
60
  ComponentSpec,
62
61
  ensure_builtin_components,
@@ -503,9 +502,6 @@ def run(
503
502
  并参与并发上限的优先级合并。
504
503
  """
505
504
  ensure_builtin_components()
506
- # 每次 run() 取数据源的新鲜快照:清空判分组件共享的 tests/*.toml
507
- # 解析缓存,使进程内缓存不跨运行泄漏。
508
- clear_source_cache()
509
505
  rc = dict(run_context or {})
510
506
  workflow_limit, tag_limits = _effective_concurrency(plan, rc)
511
507
  if model is None: