@rpamis/comet 0.4.0-beta.8 → 0.4.0-beta.9
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.
- package/README.md +1 -1
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills/comet/scripts/comet-entry-runtime.mjs +95 -4
- package/assets/skills/comet/scripts/comet-hook-router.mjs +224 -35
- package/assets/skills/comet/scripts/comet-runtime.mjs +218 -102
- package/assets/skills/comet-archive/SKILL.md +29 -20
- package/assets/skills/comet-native/SKILL.md +23 -15
- package/assets/skills/comet-native/reference/artifacts.md +19 -4
- package/assets/skills/comet-native/reference/commands.md +8 -2
- package/assets/skills/comet-native/reference/recovery.md +1 -1
- package/assets/skills/comet-native/scripts/comet-native-runtime.mjs +1052 -458
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills-zh/comet-archive/SKILL.md +29 -20
- package/assets/skills-zh/comet-native/SKILL.md +23 -15
- package/assets/skills-zh/comet-native/reference/artifacts.md +20 -5
- package/assets/skills-zh/comet-native/reference/commands.md +8 -2
- package/assets/skills-zh/comet-native/reference/recovery.md +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +3 -6
- package/dist/app/commands/init.js.map +1 -1
- package/dist/domains/comet-entry/current-selection.d.ts.map +1 -1
- package/dist/domains/comet-entry/current-selection.js +6 -8
- package/dist/domains/comet-entry/current-selection.js.map +1 -1
- package/dist/domains/comet-entry/project-status.d.ts.map +1 -1
- package/dist/domains/comet-entry/project-status.js +5 -1
- package/dist/domains/comet-entry/project-status.js.map +1 -1
- package/dist/domains/comet-native/native-build-evidence.js +2 -2
- package/dist/domains/comet-native/native-build-evidence.js.map +1 -1
- package/dist/domains/comet-native/native-change.d.ts +4 -2
- package/dist/domains/comet-native/native-change.d.ts.map +1 -1
- package/dist/domains/comet-native/native-change.js +18 -4
- package/dist/domains/comet-native/native-change.js.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.js +5 -3
- package/dist/domains/comet-native/native-check-receipt.js.map +1 -1
- package/dist/domains/comet-native/native-cli.d.ts.map +1 -1
- package/dist/domains/comet-native/native-cli.js +120 -16
- package/dist/domains/comet-native/native-cli.js.map +1 -1
- package/dist/domains/comet-native/native-config.d.ts +5 -1
- package/dist/domains/comet-native/native-config.d.ts.map +1 -1
- package/dist/domains/comet-native/native-config.js +78 -0
- package/dist/domains/comet-native/native-config.js.map +1 -1
- package/dist/domains/comet-native/native-continuation.d.ts +2 -1
- package/dist/domains/comet-native/native-continuation.d.ts.map +1 -1
- package/dist/domains/comet-native/native-continuation.js +13 -5
- package/dist/domains/comet-native/native-continuation.js.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.d.ts +7 -3
- package/dist/domains/comet-native/native-diagnostics.d.ts.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.js +19 -9
- package/dist/domains/comet-native/native-diagnostics.js.map +1 -1
- package/dist/domains/comet-native/native-file-identity.d.ts +2 -8
- package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -1
- package/dist/domains/comet-native/native-file-identity.js +1 -20
- package/dist/domains/comet-native/native-file-identity.js.map +1 -1
- package/dist/domains/comet-native/native-findings.d.ts.map +1 -1
- package/dist/domains/comet-native/native-findings.js +19 -1
- package/dist/domains/comet-native/native-findings.js.map +1 -1
- package/dist/domains/comet-native/native-guards.d.ts +2 -1
- package/dist/domains/comet-native/native-guards.d.ts.map +1 -1
- package/dist/domains/comet-native/native-guards.js +14 -0
- package/dist/domains/comet-native/native-guards.js.map +1 -1
- package/dist/domains/comet-native/native-lock.d.ts.map +1 -1
- package/dist/domains/comet-native/native-lock.js +24 -32
- package/dist/domains/comet-native/native-lock.js.map +1 -1
- package/dist/domains/comet-native/native-root-move.d.ts.map +1 -1
- package/dist/domains/comet-native/native-root-move.js +2 -0
- package/dist/domains/comet-native/native-root-move.js.map +1 -1
- package/dist/domains/comet-native/native-snapshot.d.ts +5 -1
- package/dist/domains/comet-native/native-snapshot.d.ts.map +1 -1
- package/dist/domains/comet-native/native-snapshot.js +218 -2
- package/dist/domains/comet-native/native-snapshot.js.map +1 -1
- package/dist/domains/comet-native/native-transitions.d.ts +2 -1
- package/dist/domains/comet-native/native-transitions.d.ts.map +1 -1
- package/dist/domains/comet-native/native-transitions.js +34 -11
- package/dist/domains/comet-native/native-transitions.js.map +1 -1
- package/dist/domains/comet-native/native-types.d.ts +16 -0
- package/dist/domains/comet-native/native-types.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.js +5 -3
- package/dist/domains/comet-native/native-verification-runtime.js.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts +2 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.js +6 -1
- package/dist/domains/comet-native/native-verification-scope.js.map +1 -1
- package/dist/domains/dashboard/native-collector.d.ts.map +1 -1
- package/dist/domains/dashboard/native-collector.js +4 -1
- package/dist/domains/dashboard/native-collector.js.map +1 -1
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +9 -0
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/project-instructions.d.ts.map +1 -1
- package/dist/domains/skill/project-instructions.js +4 -2
- package/dist/domains/skill/project-instructions.js.map +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts.map +1 -1
- package/dist/domains/workflow-contract/project-config.js +24 -2
- package/dist/domains/workflow-contract/project-config.js.map +1 -1
- package/dist/platform/fs/file-identity.d.ts +9 -0
- package/dist/platform/fs/file-identity.d.ts.map +1 -0
- package/dist/platform/fs/file-identity.js +21 -0
- package/dist/platform/fs/file-identity.js.map +1 -0
- package/dist/platform/fs/file-system.d.ts.map +1 -1
- package/dist/platform/fs/file-system.js +13 -9
- package/dist/platform/fs/file-system.js.map +1 -1
- package/dist/platform/fs/race-safe-read.d.ts +47 -0
- package/dist/platform/fs/race-safe-read.d.ts.map +1 -0
- package/dist/platform/fs/race-safe-read.js +132 -0
- package/dist/platform/fs/race-safe-read.js.map +1 -0
- package/eval/README.md +1 -1
- package/eval/local/tasks/comet-native-clarification-depth/environment/Dockerfile +27 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/test_wordcount.py +25 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/wordcount.py +36 -0
- package/eval/local/tasks/comet-native-clarification-depth/instruction.md +17 -0
- package/eval/local/tasks/comet-native-clarification-depth/task.toml +47 -0
- package/eval/local/tasks/comet-native-clarification-depth/validation/test_native_clarification_depth.py +618 -0
- package/eval/local/tasks/comet-native-clarification-modes/validation/test_native_clarification_modes.py +1 -1
- package/eval/local/tasks/index.yaml +6 -0
- package/eval/local/tests/conftest.py +146 -2
- package/eval/local/tests/scaffold/test_conftest_helpers.py +188 -1
- package/eval/local/tests/scaffold/test_tasks.py +440 -8
- package/eval/local/tests/scaffold/test_utils.py +114 -1
- package/eval/local/tests/tasks/test_tasks.py +2 -0
- package/eval/scaffold/python/aligned_comparison.py +1 -0
- package/eval/scaffold/python/tasks.py +2 -0
- package/eval/scaffold/shell/docker.sh +1 -1
- package/eval/scaffold/shell/run-claude-loop.sh +25 -2
- package/package.json +1 -1
|
@@ -67,6 +67,142 @@ def _extract_loop_interaction(stderr: str | None) -> dict[str, int | None]:
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
|
|
70
|
+
def _bounded_command_evidence(command: str, matches: list[re.Match[str]]) -> str:
|
|
71
|
+
chunks: list[str] = []
|
|
72
|
+
remaining = 4000
|
|
73
|
+
last_end = -1
|
|
74
|
+
for match in matches:
|
|
75
|
+
start = max(0, match.start() - 300)
|
|
76
|
+
end = min(len(command), match.end() + 300)
|
|
77
|
+
if start <= last_end and chunks:
|
|
78
|
+
overlap = max(0, last_end - start)
|
|
79
|
+
addition = command[start + overlap : end]
|
|
80
|
+
addition = addition[:remaining]
|
|
81
|
+
chunks[-1] += addition
|
|
82
|
+
remaining -= len(addition)
|
|
83
|
+
last_end = max(last_end, end)
|
|
84
|
+
else:
|
|
85
|
+
chunk = command[start:end][:remaining]
|
|
86
|
+
if chunks:
|
|
87
|
+
separator = "\n...[truncated]...\n"
|
|
88
|
+
if len(separator) > remaining:
|
|
89
|
+
break
|
|
90
|
+
chunks.append(separator)
|
|
91
|
+
remaining -= len(separator)
|
|
92
|
+
chunks.append(chunk)
|
|
93
|
+
remaining -= len(chunk)
|
|
94
|
+
last_end = end
|
|
95
|
+
if remaining <= 0:
|
|
96
|
+
break
|
|
97
|
+
excerpt = "".join(chunks)
|
|
98
|
+
return re.sub(
|
|
99
|
+
r"(?i)\b(api[_-]?key|auth[_-]?token|password|secret)\s*=\s*"
|
|
100
|
+
r"(?:\"[^\"]*\"|'[^']*'|[^\s;]+)",
|
|
101
|
+
r"\1=[REDACTED]",
|
|
102
|
+
excerpt,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _tool_result_succeeded(item: dict[str, Any]) -> bool:
|
|
107
|
+
is_error = item.get("is_error")
|
|
108
|
+
if is_error is True or str(is_error).strip().lower() == "true" or item.get("error"):
|
|
109
|
+
return False
|
|
110
|
+
status = str(item.get("status") or "").strip().lower()
|
|
111
|
+
if status in {"error", "failed", "failure", "cancelled", "canceled"}:
|
|
112
|
+
return False
|
|
113
|
+
content = item.get("content", "")
|
|
114
|
+
if isinstance(content, list):
|
|
115
|
+
content = " ".join(
|
|
116
|
+
str(block.get("text") or "") if isinstance(block, dict) else str(block)
|
|
117
|
+
for block in content
|
|
118
|
+
)
|
|
119
|
+
return not bool(
|
|
120
|
+
re.search(
|
|
121
|
+
r"(?i)^\s*(?:error|failed|failure|tool[_ -]?error)\b|"
|
|
122
|
+
r"\b(?:exit|exited with)(?:\s+code)?\s*[1-9]\d*\b",
|
|
123
|
+
str(content),
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _extract_subject_turn_evidence(stdout: str | None) -> list[dict[str, Any]]:
|
|
129
|
+
"""Group safe assistant result text and bounded tool evidence by subject turn."""
|
|
130
|
+
turns: list[dict[str, Any]] = []
|
|
131
|
+
tool_calls: list[dict[str, Any]] = []
|
|
132
|
+
tool_calls_by_id: dict[str, dict[str, Any]] = {}
|
|
133
|
+
last_assistant_text = ""
|
|
134
|
+
for line in (stdout or "").splitlines():
|
|
135
|
+
try:
|
|
136
|
+
event = json.loads(line)
|
|
137
|
+
except (json.JSONDecodeError, TypeError):
|
|
138
|
+
continue
|
|
139
|
+
if not isinstance(event, dict):
|
|
140
|
+
continue
|
|
141
|
+
if event.get("type") == "assistant":
|
|
142
|
+
content = (event.get("message") or {}).get("content") or []
|
|
143
|
+
assistant_text = " ".join(
|
|
144
|
+
str(block.get("text") or "")
|
|
145
|
+
for block in content
|
|
146
|
+
if isinstance(block, dict) and block.get("type") == "text"
|
|
147
|
+
).strip()
|
|
148
|
+
if assistant_text:
|
|
149
|
+
last_assistant_text = assistant_text
|
|
150
|
+
for block in content:
|
|
151
|
+
if isinstance(block, dict) and block.get("type") == "tool_use":
|
|
152
|
+
name = block.get("name")
|
|
153
|
+
if isinstance(name, str) and name:
|
|
154
|
+
evidence: dict[str, Any] = {"name": name, "success": False}
|
|
155
|
+
tool_input = block.get("input")
|
|
156
|
+
if isinstance(tool_input, dict):
|
|
157
|
+
for key in ("file_path", "path", "notebook_path"):
|
|
158
|
+
value = tool_input.get(key)
|
|
159
|
+
if isinstance(value, str) and value:
|
|
160
|
+
evidence["path"] = value[:500]
|
|
161
|
+
break
|
|
162
|
+
command = tool_input.get("command")
|
|
163
|
+
if isinstance(command, str) and command:
|
|
164
|
+
target_matches = list(
|
|
165
|
+
re.finditer(
|
|
166
|
+
r"(?i)(?:[a-z]:)?[./\\\w-]*\.py\b|"
|
|
167
|
+
r"\bbrief\.md\b|"
|
|
168
|
+
r"\bspec\.md\b",
|
|
169
|
+
command,
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
if target_matches:
|
|
173
|
+
evidence["command"] = _bounded_command_evidence(
|
|
174
|
+
command, target_matches
|
|
175
|
+
)
|
|
176
|
+
tool_calls.append(evidence)
|
|
177
|
+
tool_id = block.get("id")
|
|
178
|
+
if isinstance(tool_id, str) and tool_id:
|
|
179
|
+
tool_calls_by_id[tool_id] = evidence
|
|
180
|
+
continue
|
|
181
|
+
if event.get("type") == "user":
|
|
182
|
+
content = (event.get("message") or {}).get("content") or []
|
|
183
|
+
for block in content:
|
|
184
|
+
if not isinstance(block, dict) or block.get("type") != "tool_result":
|
|
185
|
+
continue
|
|
186
|
+
tool_use_id = block.get("tool_use_id")
|
|
187
|
+
if isinstance(tool_use_id, str) and tool_use_id in tool_calls_by_id:
|
|
188
|
+
tool_calls_by_id[tool_use_id]["success"] = _tool_result_succeeded(block)
|
|
189
|
+
continue
|
|
190
|
+
if event.get("type") != "result":
|
|
191
|
+
continue
|
|
192
|
+
result = event.get("result")
|
|
193
|
+
turns.append(
|
|
194
|
+
{
|
|
195
|
+
"turn": len(turns) + 1,
|
|
196
|
+
"result": result if isinstance(result, str) and result else last_assistant_text,
|
|
197
|
+
"tool_calls": tool_calls,
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
tool_calls = []
|
|
201
|
+
tool_calls_by_id = {}
|
|
202
|
+
last_assistant_text = ""
|
|
203
|
+
return turns
|
|
204
|
+
|
|
205
|
+
|
|
70
206
|
# =============================================================================
|
|
71
207
|
# CONSTANTS
|
|
72
208
|
# =============================================================================
|
|
@@ -695,6 +831,7 @@ def _resolve_interaction_config(task, profile_name: str, config):
|
|
|
695
831
|
task_interaction.decision_patterns or profile_default.decision_patterns
|
|
696
832
|
)
|
|
697
833
|
decision_reply = task_interaction.decision_reply or profile_default.decision_reply
|
|
834
|
+
decision_replies = list(task_interaction.decision_replies or profile_default.decision_replies)
|
|
698
835
|
continue_prompt = task_interaction.continue_prompt or profile_default.continue_prompt
|
|
699
836
|
fresh_resume_marker = task_interaction.fresh_resume_marker
|
|
700
837
|
|
|
@@ -712,7 +849,7 @@ def _resolve_interaction_config(task, profile_name: str, config):
|
|
|
712
849
|
prompt_path = Path(prompt_file) if prompt_file else (EVAL_ROOT / "simulator-instruction.md")
|
|
713
850
|
if not prompt_path.is_absolute():
|
|
714
851
|
prompt_path = EVAL_ROOT / prompt_path
|
|
715
|
-
if prompt_path.exists():
|
|
852
|
+
if prompt_path.exists() and (prompt_file or not task_interaction.simulator_prompt):
|
|
716
853
|
simulator_prompt = prompt_path.read_text(encoding="utf-8")
|
|
717
854
|
|
|
718
855
|
if simulator_prompt_override:
|
|
@@ -724,6 +861,7 @@ def _resolve_interaction_config(task, profile_name: str, config):
|
|
|
724
861
|
simulator_prompt=simulator_prompt,
|
|
725
862
|
decision_patterns=decision_patterns,
|
|
726
863
|
decision_reply=decision_reply,
|
|
864
|
+
decision_replies=decision_replies,
|
|
727
865
|
continue_prompt=continue_prompt,
|
|
728
866
|
fresh_resume_marker=fresh_resume_marker,
|
|
729
867
|
)
|
|
@@ -1137,12 +1275,18 @@ def run_claude(test_dir, experiment_logger, request):
|
|
|
1137
1275
|
loop_args += ["--decision-pattern", pattern]
|
|
1138
1276
|
if interaction.decision_reply:
|
|
1139
1277
|
loop_args += ["--decision-reply", interaction.decision_reply]
|
|
1278
|
+
for decision_reply_step in interaction.decision_replies:
|
|
1279
|
+
loop_args += ["--decision-reply-step", decision_reply_step]
|
|
1140
1280
|
if interaction.fresh_resume_marker:
|
|
1141
1281
|
loop_args += ["--fresh-resume-marker", interaction.fresh_resume_marker]
|
|
1142
1282
|
|
|
1143
1283
|
prompt_file = None
|
|
1144
1284
|
try:
|
|
1145
|
-
if
|
|
1285
|
+
if (
|
|
1286
|
+
interaction.simulator_prompt
|
|
1287
|
+
and not interaction.decision_reply
|
|
1288
|
+
and not interaction.decision_replies
|
|
1289
|
+
):
|
|
1146
1290
|
prompt_file = test_dir / ".eval-simulator-prompt.txt"
|
|
1147
1291
|
prompt_file.write_text(interaction.simulator_prompt, encoding="utf-8")
|
|
1148
1292
|
loop_args += [
|
|
@@ -101,6 +101,154 @@ def test_extract_loop_turns_reads_driver_completion_line():
|
|
|
101
101
|
assert conftest._extract_loop_turns("ordinary stderr") is None
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
def test_extract_subject_turn_evidence_groups_results_and_tool_calls():
|
|
105
|
+
stdout = "\n".join(
|
|
106
|
+
[
|
|
107
|
+
json.dumps(
|
|
108
|
+
{
|
|
109
|
+
"type": "assistant",
|
|
110
|
+
"message": {
|
|
111
|
+
"content": [
|
|
112
|
+
{"type": "text", "text": "Investigating."},
|
|
113
|
+
{
|
|
114
|
+
"type": "tool_use",
|
|
115
|
+
"id": "read-1",
|
|
116
|
+
"name": "Read",
|
|
117
|
+
"input": {"file_path": "x"},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"type": "tool_use",
|
|
121
|
+
"id": "bash-1",
|
|
122
|
+
"name": "Bash",
|
|
123
|
+
"input": {"command": "AUTH_TOKEN=topsecret cat > wordcount.py"},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"type": "tool_use",
|
|
127
|
+
"id": "edit-failed",
|
|
128
|
+
"name": "Edit",
|
|
129
|
+
"input": {"file_path": "sentence.py"},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"type": "tool_use",
|
|
133
|
+
"id": "bash-failed",
|
|
134
|
+
"name": "Bash",
|
|
135
|
+
"input": {"command": "cat > fallback.py"},
|
|
136
|
+
},
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
json.dumps(
|
|
142
|
+
{
|
|
143
|
+
"type": "user",
|
|
144
|
+
"message": {
|
|
145
|
+
"content": [
|
|
146
|
+
{
|
|
147
|
+
"type": "tool_result",
|
|
148
|
+
"tool_use_id": "read-1",
|
|
149
|
+
"content": "source",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"type": "tool_result",
|
|
153
|
+
"tool_use_id": "bash-1",
|
|
154
|
+
"content": "updated",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "tool_result",
|
|
158
|
+
"tool_use_id": "edit-failed",
|
|
159
|
+
"content": "permission denied",
|
|
160
|
+
"is_error": True,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"type": "tool_result",
|
|
164
|
+
"tool_use_id": "bash-failed",
|
|
165
|
+
"content": "Process exited with code 1",
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
json.dumps(
|
|
172
|
+
{
|
|
173
|
+
"type": "result",
|
|
174
|
+
"subtype": "success",
|
|
175
|
+
"result": "[blocking] QUESTION\nShould empty input return zero?",
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
json.dumps(
|
|
179
|
+
{
|
|
180
|
+
"type": "assistant",
|
|
181
|
+
"message": {
|
|
182
|
+
"content": [
|
|
183
|
+
{
|
|
184
|
+
"type": "tool_use",
|
|
185
|
+
"id": "write-1",
|
|
186
|
+
"name": "Write",
|
|
187
|
+
"input": {"file_path": "y"},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"type": "text",
|
|
191
|
+
"text": "Implementation completed through archive.",
|
|
192
|
+
},
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
json.dumps(
|
|
198
|
+
{
|
|
199
|
+
"type": "user",
|
|
200
|
+
"message": {
|
|
201
|
+
"content": [
|
|
202
|
+
{
|
|
203
|
+
"type": "tool_result",
|
|
204
|
+
"tool_use_id": "write-1",
|
|
205
|
+
"content": "created",
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
json.dumps(
|
|
212
|
+
{
|
|
213
|
+
"type": "result",
|
|
214
|
+
"subtype": "success",
|
|
215
|
+
"result": "",
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
assert conftest._extract_subject_turn_evidence(stdout) == [
|
|
222
|
+
{
|
|
223
|
+
"turn": 1,
|
|
224
|
+
"result": "[blocking] QUESTION\nShould empty input return zero?",
|
|
225
|
+
"tool_calls": [
|
|
226
|
+
{"name": "Read", "success": True, "path": "x"},
|
|
227
|
+
{
|
|
228
|
+
"name": "Bash",
|
|
229
|
+
"success": True,
|
|
230
|
+
"command": "AUTH_TOKEN=[REDACTED] cat > wordcount.py",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"name": "Edit",
|
|
234
|
+
"success": False,
|
|
235
|
+
"path": "sentence.py",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"name": "Bash",
|
|
239
|
+
"success": False,
|
|
240
|
+
"command": "cat > fallback.py",
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"turn": 2,
|
|
246
|
+
"result": "Implementation completed through archive.",
|
|
247
|
+
"tool_calls": [{"name": "Write", "success": True, "path": "y"}],
|
|
248
|
+
},
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
|
|
104
252
|
def test_capture_execution_identity_separates_runtime_image_from_safe_report(
|
|
105
253
|
tmp_path: Path, monkeypatch
|
|
106
254
|
):
|
|
@@ -201,7 +349,8 @@ def test_auto_user_prompt_paths_bypass_msys_path_conversion():
|
|
|
201
349
|
|
|
202
350
|
assert '"@//workspace/.eval-task-prompt.txt"' in source
|
|
203
351
|
assert '"//workspace/.eval-simulator-prompt.txt"' in source
|
|
204
|
-
assert "
|
|
352
|
+
assert "and not interaction.decision_reply" in source
|
|
353
|
+
assert "and not interaction.decision_replies" in source
|
|
205
354
|
|
|
206
355
|
|
|
207
356
|
def test_dynamic_treatment_config_from_skill_path(tmp_path: Path):
|
|
@@ -272,6 +421,44 @@ def test_resolve_interaction_config_uses_profile_default_prompt():
|
|
|
272
421
|
assert interaction.simulator_prompt is not None
|
|
273
422
|
|
|
274
423
|
|
|
424
|
+
def test_resolve_interaction_config_preserves_task_simulator_prompt(monkeypatch):
|
|
425
|
+
task = load_task("comet-native-clarification-modes")
|
|
426
|
+
monkeypatch.delenv("BENCH_SIMULATOR_PROMPT_FILE", raising=False)
|
|
427
|
+
|
|
428
|
+
class Config:
|
|
429
|
+
def getoption(self, name):
|
|
430
|
+
return {
|
|
431
|
+
"--interaction-mode": None,
|
|
432
|
+
"--max-turns": None,
|
|
433
|
+
"--simulator-prompt": None,
|
|
434
|
+
}.get(name)
|
|
435
|
+
|
|
436
|
+
interaction = conftest._resolve_interaction_config(task, "generic", Config())
|
|
437
|
+
|
|
438
|
+
assert interaction.simulator_prompt == task.config.interaction.simulator_prompt
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def test_resolve_interaction_config_allows_explicit_prompt_file_override(
|
|
442
|
+
tmp_path: Path, monkeypatch
|
|
443
|
+
):
|
|
444
|
+
task = load_task("comet-native-clarification-modes")
|
|
445
|
+
prompt_file = tmp_path / "simulator.md"
|
|
446
|
+
prompt_file.write_text("Use the explicit simulator.", encoding="utf-8")
|
|
447
|
+
monkeypatch.setenv("BENCH_SIMULATOR_PROMPT_FILE", str(prompt_file))
|
|
448
|
+
|
|
449
|
+
class Config:
|
|
450
|
+
def getoption(self, name):
|
|
451
|
+
return {
|
|
452
|
+
"--interaction-mode": None,
|
|
453
|
+
"--max-turns": None,
|
|
454
|
+
"--simulator-prompt": None,
|
|
455
|
+
}.get(name)
|
|
456
|
+
|
|
457
|
+
interaction = conftest._resolve_interaction_config(task, "generic", Config())
|
|
458
|
+
|
|
459
|
+
assert interaction.simulator_prompt == "Use the explicit simulator."
|
|
460
|
+
|
|
461
|
+
|
|
275
462
|
def test_build_eval_claude_md_injects_comet_workflow_contract():
|
|
276
463
|
claude_md = conftest._build_eval_claude_md("comet-workflow")
|
|
277
464
|
|