@rpamis/comet 0.4.0-beta.7 → 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/LICENSE +21 -21
- package/README.md +3 -3
- 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 +118 -6
- package/assets/skills/comet/scripts/comet-hook-router.mjs +244 -26
- package/assets/skills/comet/scripts/comet-runtime.mjs +221 -104
- 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 +1136 -471
- 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/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +1 -1
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +3 -2
- package/dist/domains/comet-classic/classic-guard.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-archive-transaction.d.ts.map +1 -1
- package/dist/domains/comet-native/native-archive-transaction.js +5 -6
- package/dist/domains/comet-native/native-archive-transaction.js.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.js +11 -7
- package/dist/domains/comet-native/native-atomic-file.js.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.js +11 -7
- package/dist/domains/comet-native/native-bounded-file.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-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt-storage.js +11 -7
- package/dist/domains/comet-native/native-check-receipt-storage.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 +16 -11
- 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-evidence-retention.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-retention.js +5 -3
- package/dist/domains/comet-native/native-evidence-retention.js.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.js +11 -7
- package/dist/domains/comet-native/native-evidence-storage.js.map +1 -1
- package/dist/domains/comet-native/native-file-identity.d.ts +3 -0
- package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -0
- package/dist/domains/comet-native/native-file-identity.js +2 -0
- package/dist/domains/comet-native/native-file-identity.js.map +1 -0
- 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 +30 -35
- package/dist/domains/comet-native/native-lock.js.map +1 -1
- package/dist/domains/comet-native/native-protected-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-protected-file.js +9 -8
- package/dist/domains/comet-native/native-protected-file.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-run-store.d.ts.map +1 -1
- package/dist/domains/comet-native/native-run-store.js +9 -8
- package/dist/domains/comet-native/native-run-store.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 +225 -5
- 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/dashboard/web/index.html +14 -14
- 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/pyproject.toml +4 -4
- 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 +8 -1
|
@@ -88,6 +88,7 @@ max_turns = 7
|
|
|
88
88
|
simulator_prompt = "Answer as a concise developer user."
|
|
89
89
|
decision_patterns = ["confirm", "choose"]
|
|
90
90
|
decision_reply = "Use the recommended option."
|
|
91
|
+
decision_replies = ["First reply.", "Second reply."]
|
|
91
92
|
continue_prompt = "Please continue."
|
|
92
93
|
fresh_resume_marker = "COLD_RESUME_READY"
|
|
93
94
|
"""
|
|
@@ -105,6 +106,7 @@ fresh_resume_marker = "COLD_RESUME_READY"
|
|
|
105
106
|
assert task.config.interaction.simulator_prompt == "Answer as a concise developer user."
|
|
106
107
|
assert task.config.interaction.decision_patterns == ["confirm", "choose"]
|
|
107
108
|
assert task.config.interaction.decision_reply == "Use the recommended option."
|
|
109
|
+
assert task.config.interaction.decision_replies == ["First reply.", "Second reply."]
|
|
108
110
|
assert task.config.interaction.continue_prompt == "Please continue."
|
|
109
111
|
assert task.config.interaction.fresh_resume_marker == "COLD_RESUME_READY"
|
|
110
112
|
|
|
@@ -153,7 +155,7 @@ def test_comet_task_index_lists_real_tasks():
|
|
|
153
155
|
index = yaml.safe_load(index_path.read_text(encoding="utf-8"))
|
|
154
156
|
names = [task["name"] for task in index["tasks"]]
|
|
155
157
|
assert sorted(names) == sorted(list_tasks())
|
|
156
|
-
assert len(names) ==
|
|
158
|
+
assert len(names) == 31
|
|
157
159
|
assert set(names) == {
|
|
158
160
|
"authoring-skill-smoke",
|
|
159
161
|
"comet-agent-memory-routing",
|
|
@@ -173,6 +175,7 @@ def test_comet_task_index_lists_real_tasks():
|
|
|
173
175
|
"comet-noise-distractor",
|
|
174
176
|
"comet-native-workflow",
|
|
175
177
|
"comet-native-clarification",
|
|
178
|
+
"comet-native-clarification-depth",
|
|
176
179
|
"comet-native-clarification-modes",
|
|
177
180
|
"comet-native-repository-fact",
|
|
178
181
|
"comet-native-interrupted-transition",
|
|
@@ -237,10 +240,429 @@ def test_native_clarification_modes_task_compares_batch_and_sequential():
|
|
|
237
240
|
assert "Do not choose the clarification mode" in prompt
|
|
238
241
|
|
|
239
242
|
|
|
243
|
+
def test_native_clarification_depth_task_keeps_answers_private_and_sequential():
|
|
244
|
+
task = load_task("comet-native-clarification-depth")
|
|
245
|
+
|
|
246
|
+
assert task.default_treatments == ["COMET_NATIVE_SEQUENTIAL"]
|
|
247
|
+
assert task.config.evaluation.profile == "generic"
|
|
248
|
+
assert task.config.evaluation.required_skills == ["comet-native"]
|
|
249
|
+
assert task.config.interaction.mode == "auto_user"
|
|
250
|
+
assert task.config.interaction.max_turns == 8
|
|
251
|
+
assert task.config.timeout_sec == 2400
|
|
252
|
+
assert task.config.interaction.decision_reply is None
|
|
253
|
+
assert task.config.interaction.simulator_prompt is None
|
|
254
|
+
assert task.config.interaction.decision_replies == [
|
|
255
|
+
"It prints Sentences: 0.",
|
|
256
|
+
"They count as one sentence boundary.",
|
|
257
|
+
(
|
|
258
|
+
"Recognized abbreviations such as e.g. and Dr. always suppress their periods, "
|
|
259
|
+
"including at end-of-input; every other occurrence of ., !, or ? remains a "
|
|
260
|
+
"sentence boundary, and the non-empty fallback still makes an "
|
|
261
|
+
"abbreviation-only input one sentence."
|
|
262
|
+
),
|
|
263
|
+
"Use a small explicit list. Ask me for the exact entries separately.",
|
|
264
|
+
(
|
|
265
|
+
"Use exactly Dr., Mr., Mrs., Ms., Prof., Sr., Jr., e.g., i.e., etc., "
|
|
266
|
+
"vs., Inc., Ltd., Corp., St., and Ave., matched case-sensitively exactly "
|
|
267
|
+
"as written."
|
|
268
|
+
),
|
|
269
|
+
"confirmed",
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
prompt = task.render_prompt().lower()
|
|
273
|
+
assert "sentences: 0" not in prompt
|
|
274
|
+
assert "small explicit list" not in prompt
|
|
275
|
+
assert "e.g." not in prompt
|
|
276
|
+
assert "follow the already configured native sequential clarification protocol" in prompt
|
|
277
|
+
assert "resolve every undefined user-visible behavior" in prompt
|
|
278
|
+
for leaked_protocol_step in (
|
|
279
|
+
"one decision per turn",
|
|
280
|
+
"recommendation",
|
|
281
|
+
"rescan",
|
|
282
|
+
"shared-understanding",
|
|
283
|
+
"explicit confirmation",
|
|
284
|
+
):
|
|
285
|
+
assert leaked_protocol_step not in prompt
|
|
286
|
+
|
|
287
|
+
task_root = get_tasks_dir() / "comet-native-clarification-depth"
|
|
288
|
+
forbidden = "gr" + "ill"
|
|
289
|
+
for path in task_root.rglob("*"):
|
|
290
|
+
assert forbidden not in path.name.lower()
|
|
291
|
+
if path.is_file() and path.suffix in {".md", ".toml", ".py", ".txt", ".yaml", ".yml"}:
|
|
292
|
+
assert forbidden not in path.read_text(encoding="utf-8").lower()
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def test_native_clarification_depth_validator_requires_five_questions_then_confirmation(
|
|
296
|
+
tmp_path: Path,
|
|
297
|
+
):
|
|
298
|
+
validator_path = (
|
|
299
|
+
get_tasks_dir()
|
|
300
|
+
/ "comet-native-clarification-depth"
|
|
301
|
+
/ "validation"
|
|
302
|
+
/ "test_native_clarification_depth.py"
|
|
303
|
+
)
|
|
304
|
+
spec = importlib.util.spec_from_file_location(
|
|
305
|
+
"native_clarification_depth_validator", validator_path
|
|
306
|
+
)
|
|
307
|
+
assert spec and spec.loader
|
|
308
|
+
validator = importlib.util.module_from_spec(spec)
|
|
309
|
+
spec.loader.exec_module(validator)
|
|
310
|
+
validator.WORKSPACE = tmp_path
|
|
311
|
+
brief_path = "/workspace/docs/comet/changes/add-sentence-counting/brief.md"
|
|
312
|
+
spec_path = (
|
|
313
|
+
"/workspace/docs/comet/changes/add-sentence-counting/specs/sentence-counting/spec.md"
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
config = tmp_path / ".comet" / "config.yaml"
|
|
317
|
+
config.parent.mkdir(parents=True)
|
|
318
|
+
config.write_text(
|
|
319
|
+
"schema: comet.project.v1\nnative:\n clarification_mode: sequential\n",
|
|
320
|
+
encoding="utf-8",
|
|
321
|
+
)
|
|
322
|
+
(tmp_path / "_test_context.json").write_text(
|
|
323
|
+
json.dumps(
|
|
324
|
+
{
|
|
325
|
+
"treatment_name": "COMET_NATIVE_SEQUENTIAL",
|
|
326
|
+
"interaction": {
|
|
327
|
+
"mode": "auto_user",
|
|
328
|
+
"actual_turns": 7,
|
|
329
|
+
"decision_points": 6,
|
|
330
|
+
"deterministic_replies": 6,
|
|
331
|
+
"subject_turns": [
|
|
332
|
+
{
|
|
333
|
+
"turn": 1,
|
|
334
|
+
"result": (
|
|
335
|
+
"Question: What should empty input print?\n"
|
|
336
|
+
"Recommendation: print zero. Impact: keeps output numeric."
|
|
337
|
+
),
|
|
338
|
+
"tool_calls": [
|
|
339
|
+
{
|
|
340
|
+
"name": "Read",
|
|
341
|
+
"success": True,
|
|
342
|
+
"path": "/workspace/wordcount.py",
|
|
343
|
+
}
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"turn": 2,
|
|
348
|
+
"result": (
|
|
349
|
+
"Question: Should consecutive terminators such as ?! "
|
|
350
|
+
"form one boundary?\nRecommendation: count one boundary. "
|
|
351
|
+
"Impact: avoids double counting."
|
|
352
|
+
),
|
|
353
|
+
"tool_calls": [
|
|
354
|
+
{
|
|
355
|
+
"name": "Edit",
|
|
356
|
+
"success": True,
|
|
357
|
+
"path": brief_path,
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"name": "Edit",
|
|
361
|
+
"success": True,
|
|
362
|
+
"path": spec_path,
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"turn": 3,
|
|
368
|
+
"result": (
|
|
369
|
+
"**Question:** Should abbreviations such as Dr. end a "
|
|
370
|
+
"sentence?\n**Recommendation:** do not treat recognized "
|
|
371
|
+
"abbreviations as boundaries. **Impact:** avoids false boundaries."
|
|
372
|
+
),
|
|
373
|
+
"tool_calls": [
|
|
374
|
+
{
|
|
375
|
+
"name": "Edit",
|
|
376
|
+
"success": True,
|
|
377
|
+
"path": brief_path,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"name": "Edit",
|
|
381
|
+
"success": True,
|
|
382
|
+
"path": spec_path,
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"turn": 4,
|
|
388
|
+
"result": (
|
|
389
|
+
"Question: How should the recognized abbreviation collection "
|
|
390
|
+
"be maintained?\nRecommendation: use a small explicit list. "
|
|
391
|
+
"Impact: keeps exceptions reviewable."
|
|
392
|
+
),
|
|
393
|
+
"tool_calls": [
|
|
394
|
+
{
|
|
395
|
+
"name": "Edit",
|
|
396
|
+
"success": True,
|
|
397
|
+
"path": brief_path,
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"name": "Edit",
|
|
401
|
+
"success": True,
|
|
402
|
+
"path": spec_path,
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"turn": 5,
|
|
408
|
+
"result": (
|
|
409
|
+
"Question: Which exact abbreviation entries should the list "
|
|
410
|
+
"contain?\nRecommendation: include common titles and prose "
|
|
411
|
+
"short forms. Impact: fixes the compatibility boundary."
|
|
412
|
+
),
|
|
413
|
+
"tool_calls": [
|
|
414
|
+
{
|
|
415
|
+
"name": "Edit",
|
|
416
|
+
"success": True,
|
|
417
|
+
"path": brief_path,
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"name": "Edit",
|
|
421
|
+
"success": True,
|
|
422
|
+
"path": spec_path,
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"turn": 6,
|
|
428
|
+
"result": (
|
|
429
|
+
"My understanding:\nGoal / outcome: add reliable sentence counting."
|
|
430
|
+
"\nScope: the --sentences CLI flag and focused tests."
|
|
431
|
+
"\nExplicit non-goals: changing existing word or line counts."
|
|
432
|
+
"\nAcceptance criteria: common CLI inputs return the agreed counts."
|
|
433
|
+
"\nDecisions: abbreviations do not end sentences; use a small "
|
|
434
|
+
"explicit abbreviation list containing Dr., Mr., Mrs., Ms., Prof., "
|
|
435
|
+
"Sr., Jr., e.g., i.e., etc., vs., Inc., Ltd., Corp., St., and Ave.; "
|
|
436
|
+
"empty input "
|
|
437
|
+
"prints Sentences: 0; consecutive terminators form one boundary. "
|
|
438
|
+
"Please confirm."
|
|
439
|
+
),
|
|
440
|
+
"tool_calls": [
|
|
441
|
+
{
|
|
442
|
+
"name": "Edit",
|
|
443
|
+
"success": True,
|
|
444
|
+
"path": brief_path,
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "Edit",
|
|
448
|
+
"success": True,
|
|
449
|
+
"path": spec_path,
|
|
450
|
+
},
|
|
451
|
+
],
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"turn": 7,
|
|
455
|
+
"result": "Completed through all phases and archived.",
|
|
456
|
+
"tool_calls": [
|
|
457
|
+
{
|
|
458
|
+
"name": "Edit",
|
|
459
|
+
"success": True,
|
|
460
|
+
"path": "/workspace/wordcount.py",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"name": "Bash",
|
|
464
|
+
"success": True,
|
|
465
|
+
"command": "python wordcount.py --sentences",
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
},
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
encoding="utf-8",
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
protocol = validator.check_clarification_protocol()
|
|
477
|
+
assert protocol["status"] == "passed", protocol
|
|
478
|
+
assert validator.contradictory_decisions(
|
|
479
|
+
"Abbreviations do not end sentences. Abbreviations are ordinary prose "
|
|
480
|
+
"tokens with no special-casing."
|
|
481
|
+
) == ["abbreviation behavior"]
|
|
482
|
+
assert (
|
|
483
|
+
validator.contradictory_decisions(
|
|
484
|
+
"Abbreviations do not end sentences and use a fixed explicit list."
|
|
485
|
+
)
|
|
486
|
+
== []
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
context = json.loads((tmp_path / "_test_context.json").read_text(encoding="utf-8"))
|
|
490
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].append(
|
|
491
|
+
{
|
|
492
|
+
"name": "Edit",
|
|
493
|
+
"success": False,
|
|
494
|
+
"path": "/workspace/sentence.py",
|
|
495
|
+
}
|
|
496
|
+
)
|
|
497
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
498
|
+
|
|
499
|
+
protocol = validator.check_clarification_protocol()
|
|
500
|
+
assert protocol["status"] == "passed", protocol
|
|
501
|
+
|
|
502
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].pop()
|
|
503
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].append(
|
|
504
|
+
{
|
|
505
|
+
"name": "Write",
|
|
506
|
+
"success": True,
|
|
507
|
+
"path": "/tmp/evidence.py",
|
|
508
|
+
}
|
|
509
|
+
)
|
|
510
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
511
|
+
|
|
512
|
+
protocol = validator.check_clarification_protocol()
|
|
513
|
+
assert protocol["status"] == "passed", protocol
|
|
514
|
+
|
|
515
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].pop()
|
|
516
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].append(
|
|
517
|
+
{
|
|
518
|
+
"name": "Write",
|
|
519
|
+
"success": True,
|
|
520
|
+
"path": ("/workspace/docs/comet/changes/add-sentence-counting/runtime/evidence.py"),
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
524
|
+
|
|
525
|
+
result = validator.check_clarification_protocol()
|
|
526
|
+
assert result["status"] == "failed"
|
|
527
|
+
assert "before explicit confirmation" in result["reason"].lower()
|
|
528
|
+
|
|
529
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].pop()
|
|
530
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].append(
|
|
531
|
+
{
|
|
532
|
+
"name": "Edit",
|
|
533
|
+
"success": True,
|
|
534
|
+
"path": "/workspace/sentence.py",
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
538
|
+
|
|
539
|
+
result = validator.check_clarification_protocol()
|
|
540
|
+
assert result["status"] == "failed"
|
|
541
|
+
assert "before explicit confirmation" in result["reason"].lower()
|
|
542
|
+
|
|
543
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].pop()
|
|
544
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].append(
|
|
545
|
+
{
|
|
546
|
+
"name": "Bash",
|
|
547
|
+
"success": True,
|
|
548
|
+
"command": "cat > test_wordcount.py",
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
552
|
+
|
|
553
|
+
result = validator.check_clarification_protocol()
|
|
554
|
+
assert result["status"] == "failed"
|
|
555
|
+
assert "before explicit confirmation" in result["reason"].lower()
|
|
556
|
+
|
|
557
|
+
context["interaction"]["subject_turns"][0]["tool_calls"].pop()
|
|
558
|
+
investigation = context["interaction"]["subject_turns"][0]["tool_calls"]
|
|
559
|
+
context["interaction"]["subject_turns"][0]["tool_calls"] = [
|
|
560
|
+
{
|
|
561
|
+
**investigation[0],
|
|
562
|
+
"success": False,
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
566
|
+
|
|
567
|
+
result = validator.check_clarification_protocol()
|
|
568
|
+
assert result["status"] == "failed"
|
|
569
|
+
assert "not investigated" in result["reason"].lower()
|
|
570
|
+
|
|
571
|
+
context["interaction"]["subject_turns"][0]["tool_calls"] = investigation
|
|
572
|
+
persistence = context["interaction"]["subject_turns"][1]["tool_calls"]
|
|
573
|
+
context["interaction"]["subject_turns"][1]["tool_calls"] = [
|
|
574
|
+
{
|
|
575
|
+
**persistence[0],
|
|
576
|
+
"success": False,
|
|
577
|
+
},
|
|
578
|
+
persistence[1],
|
|
579
|
+
]
|
|
580
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
581
|
+
|
|
582
|
+
result = validator.check_clarification_protocol()
|
|
583
|
+
assert result["status"] == "failed"
|
|
584
|
+
assert "persistence evidence" in result["reason"].lower()
|
|
585
|
+
assert "brief" in result["reason"].lower()
|
|
586
|
+
|
|
587
|
+
context["interaction"]["subject_turns"][1]["tool_calls"] = [
|
|
588
|
+
{
|
|
589
|
+
**persistence[0],
|
|
590
|
+
"path": "/workspace/brief.md",
|
|
591
|
+
},
|
|
592
|
+
persistence[1],
|
|
593
|
+
]
|
|
594
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
595
|
+
|
|
596
|
+
result = validator.check_clarification_protocol()
|
|
597
|
+
assert result["status"] == "failed"
|
|
598
|
+
assert "brief" in result["reason"].lower()
|
|
599
|
+
|
|
600
|
+
context["interaction"]["subject_turns"][1]["tool_calls"] = persistence
|
|
601
|
+
implementation = context["interaction"]["subject_turns"][6]["tool_calls"]
|
|
602
|
+
context["interaction"]["subject_turns"][6]["tool_calls"] = [
|
|
603
|
+
{
|
|
604
|
+
"name": "Bash",
|
|
605
|
+
"success": True,
|
|
606
|
+
"command": "python wordcount.py --sentences",
|
|
607
|
+
}
|
|
608
|
+
]
|
|
609
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
610
|
+
|
|
611
|
+
result = validator.check_clarification_protocol()
|
|
612
|
+
assert result["status"] == "failed"
|
|
613
|
+
assert "after explicit confirmation" in result["reason"].lower()
|
|
614
|
+
|
|
615
|
+
context["interaction"]["subject_turns"][6]["tool_calls"] = implementation
|
|
616
|
+
confirmation = context["interaction"]["subject_turns"][5]["result"]
|
|
617
|
+
context["interaction"]["subject_turns"][5]["result"] = (
|
|
618
|
+
"Our understanding summary:\nGoal: add sentence counting.\nScope: the CLI."
|
|
619
|
+
"\nNon-goals: existing counters.\nAcceptance criteria: agreed counts are printed."
|
|
620
|
+
"\nDecisions: abbreviation behavior, empty input, and terminator runs. Please confirm."
|
|
621
|
+
)
|
|
622
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
623
|
+
|
|
624
|
+
result = validator.check_clarification_protocol()
|
|
625
|
+
assert result["status"] == "failed"
|
|
626
|
+
assert "confirmation summary is incomplete" in result["reason"].lower()
|
|
627
|
+
|
|
628
|
+
context["interaction"]["subject_turns"][5]["result"] = (
|
|
629
|
+
"Our understanding: abbreviations do not end sentences; use a small explicit "
|
|
630
|
+
"abbreviation list including e.g. and Dr.; empty input prints Sentences: 0; "
|
|
631
|
+
"consecutive terminators form one boundary. Please confirm."
|
|
632
|
+
)
|
|
633
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
634
|
+
|
|
635
|
+
result = validator.check_clarification_protocol()
|
|
636
|
+
assert result["status"] == "failed"
|
|
637
|
+
assert "goal/outcome" in result["reason"].lower()
|
|
638
|
+
|
|
639
|
+
context["interaction"]["subject_turns"][5]["result"] = confirmation
|
|
640
|
+
upstream = context["interaction"]["subject_turns"][3]["result"]
|
|
641
|
+
downstream = context["interaction"]["subject_turns"][4]["result"]
|
|
642
|
+
context["interaction"]["subject_turns"][3]["result"] = downstream
|
|
643
|
+
context["interaction"]["subject_turns"][4]["result"] = upstream
|
|
644
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
645
|
+
|
|
646
|
+
result = validator.check_clarification_protocol()
|
|
647
|
+
assert result["status"] == "failed"
|
|
648
|
+
assert "hidden and dependent decisions in order" in result["reason"].lower()
|
|
649
|
+
|
|
650
|
+
context["interaction"]["subject_turns"][3]["result"] = upstream
|
|
651
|
+
context["interaction"]["subject_turns"][4]["result"] = downstream
|
|
652
|
+
context["interaction"]["subject_turns"][0]["result"] += (
|
|
653
|
+
"\nQuestion: What should empty input print?"
|
|
654
|
+
)
|
|
655
|
+
(tmp_path / "_test_context.json").write_text(json.dumps(context), encoding="utf-8")
|
|
656
|
+
|
|
657
|
+
result = validator.check_clarification_protocol()
|
|
658
|
+
assert result["status"] == "failed"
|
|
659
|
+
assert "exactly one" in result["reason"].lower()
|
|
660
|
+
|
|
661
|
+
|
|
240
662
|
@pytest.mark.parametrize(
|
|
241
663
|
("treatment", "mode", "decision_points"),
|
|
242
664
|
[
|
|
243
|
-
("COMET_NATIVE_SEQUENTIAL", "sequential",
|
|
665
|
+
("COMET_NATIVE_SEQUENTIAL", "sequential", 4),
|
|
244
666
|
("COMET_NATIVE_BATCH", "batch", 2),
|
|
245
667
|
],
|
|
246
668
|
)
|
|
@@ -320,7 +742,10 @@ A contiguous run of terminal punctuation (`.`, `!`, `?`) counts as exactly one b
|
|
|
320
742
|
|
|
321
743
|
def test_native_clarification_validator_rejects_multiple_archives(tmp_path: Path):
|
|
322
744
|
validator_path = (
|
|
323
|
-
get_tasks_dir()
|
|
745
|
+
get_tasks_dir()
|
|
746
|
+
/ "comet-native-clarification"
|
|
747
|
+
/ "validation"
|
|
748
|
+
/ "test_native_clarification.py"
|
|
324
749
|
)
|
|
325
750
|
spec = importlib.util.spec_from_file_location("native_clarification_validator", validator_path)
|
|
326
751
|
assert spec and spec.loader
|
|
@@ -346,7 +771,10 @@ def test_native_clarification_validator_rejects_multiple_archives(tmp_path: Path
|
|
|
346
771
|
|
|
347
772
|
def test_native_clarification_validator_accepts_one_semantic_canonical_spec(tmp_path: Path):
|
|
348
773
|
validator_path = (
|
|
349
|
-
get_tasks_dir()
|
|
774
|
+
get_tasks_dir()
|
|
775
|
+
/ "comet-native-clarification"
|
|
776
|
+
/ "validation"
|
|
777
|
+
/ "test_native_clarification.py"
|
|
350
778
|
)
|
|
351
779
|
spec = importlib.util.spec_from_file_location("native_clarification_validator", validator_path)
|
|
352
780
|
assert spec and spec.loader
|
|
@@ -431,7 +859,10 @@ archived: true
|
|
|
431
859
|
|
|
432
860
|
def test_native_clarification_validator_rejects_leftover_active_change(tmp_path: Path):
|
|
433
861
|
validator_path = (
|
|
434
|
-
get_tasks_dir()
|
|
862
|
+
get_tasks_dir()
|
|
863
|
+
/ "comet-native-clarification"
|
|
864
|
+
/ "validation"
|
|
865
|
+
/ "test_native_clarification.py"
|
|
435
866
|
)
|
|
436
867
|
spec = importlib.util.spec_from_file_location("native_clarification_validator", validator_path)
|
|
437
868
|
assert spec and spec.loader
|
|
@@ -474,7 +905,9 @@ def test_native_interrupted_transition_fixture_is_recovered_by_current_runtime(t
|
|
|
474
905
|
task = load_task("comet-native-interrupted-transition")
|
|
475
906
|
workspace = tmp_path / "workspace"
|
|
476
907
|
shutil.copytree(task.environment_dir, workspace)
|
|
477
|
-
runtime =
|
|
908
|
+
runtime = (
|
|
909
|
+
get_tasks_dir().parents[2] / "assets/skills/comet-native/scripts/comet-native-runtime.mjs"
|
|
910
|
+
)
|
|
478
911
|
change = workspace / "docs/comet/changes/add-character-counting"
|
|
479
912
|
|
|
480
913
|
def run_native(*args: str, expected_exit: int = 0) -> dict:
|
|
@@ -538,7 +971,6 @@ def test_native_interrupted_transition_fixture_is_recovered_by_current_runtime(t
|
|
|
538
971
|
event
|
|
539
972
|
for event in events
|
|
540
973
|
if event.get("type") == "state_transitioned"
|
|
541
|
-
and event.get("data", {}).get("transitionId")
|
|
542
|
-
== "11111111-2222-4333-8444-555555555555"
|
|
974
|
+
and event.get("data", {}).get("transitionId") == "11111111-2222-4333-8444-555555555555"
|
|
543
975
|
]
|
|
544
976
|
assert len(recovered) == 1
|
|
@@ -232,6 +232,10 @@ def test_claude_loop_applies_plugin_args_to_subject_turns_only():
|
|
|
232
232
|
assert 'claude -p "$USER_REPLY" "${PLUGIN_ARGS[@]}"' in loop_sh
|
|
233
233
|
assert "fresh resume boundary detected" in loop_sh
|
|
234
234
|
assert 'claude -p "$sim_prompt" "${PLUGIN_ARGS[@]}"' not in loop_sh
|
|
235
|
+
assert 'if ! rm -f -- "$SIMULATOR_PROMPT_FILE"; then' in loop_sh
|
|
236
|
+
assert loop_sh.index('rm -f -- "$SIMULATOR_PROMPT_FILE"') < loop_sh.index(
|
|
237
|
+
'RAW=$(claude -p "$SUBJECT_PROMPT"'
|
|
238
|
+
)
|
|
235
239
|
|
|
236
240
|
|
|
237
241
|
def test_claude_loop_surfaces_subject_resume_failure(tmp_path: Path):
|
|
@@ -284,6 +288,113 @@ printf '%s\n' '{"type":"result","subtype":"success","session_id":"session-1","re
|
|
|
284
288
|
assert "subject turn 2 failed" in result.stderr
|
|
285
289
|
|
|
286
290
|
|
|
291
|
+
def test_claude_loop_consumes_deterministic_reply_steps_in_order(tmp_path: Path):
|
|
292
|
+
fake_bin = tmp_path / "bin"
|
|
293
|
+
fake_bin.mkdir()
|
|
294
|
+
fake_claude = fake_bin / "claude"
|
|
295
|
+
fake_claude.write_text(
|
|
296
|
+
"""#!/usr/bin/env bash
|
|
297
|
+
prompt=""
|
|
298
|
+
while [[ $# -gt 0 ]]; do
|
|
299
|
+
if [[ "$1" == "-p" ]]; then
|
|
300
|
+
prompt="$2"
|
|
301
|
+
break
|
|
302
|
+
fi
|
|
303
|
+
shift
|
|
304
|
+
done
|
|
305
|
+
printf '%s\n' '{"type":"system","session_id":"session-1"}'
|
|
306
|
+
case "$prompt" in
|
|
307
|
+
"First reply.")
|
|
308
|
+
printf '%s\n' '{"type":"result","subtype":"success","session_id":"session-1","result":"Question: Which second choice should be used? Recommendation: B. Impact: changes output."}'
|
|
309
|
+
;;
|
|
310
|
+
"Second reply.")
|
|
311
|
+
printf '%s\n' '{"type":"result","subtype":"success","session_id":"session-1","result":"Workflow completed through all phases and archived."}'
|
|
312
|
+
;;
|
|
313
|
+
*)
|
|
314
|
+
printf '%s\n' '{"type":"result","subtype":"success","session_id":"session-1","result":"Question: Which first choice should be used? Recommendation: A. Impact: changes output."}'
|
|
315
|
+
;;
|
|
316
|
+
esac
|
|
317
|
+
""",
|
|
318
|
+
encoding="utf-8",
|
|
319
|
+
newline="\n",
|
|
320
|
+
)
|
|
321
|
+
fake_claude.chmod(0o755)
|
|
322
|
+
|
|
323
|
+
env = os.environ.copy()
|
|
324
|
+
env["PATH"] = f"{utils._to_bash_path(fake_bin)}:{env.get('PATH', '')}"
|
|
325
|
+
result = subprocess.run(
|
|
326
|
+
[
|
|
327
|
+
utils.BASH_EXEC,
|
|
328
|
+
utils._to_bash_path(utils.SHELL_DIR / "run-claude-loop.sh"),
|
|
329
|
+
"Implement the requested change.",
|
|
330
|
+
"--max-turns",
|
|
331
|
+
"3",
|
|
332
|
+
"--decision-reply-step",
|
|
333
|
+
"First reply.",
|
|
334
|
+
"--decision-reply-step",
|
|
335
|
+
"Second reply.",
|
|
336
|
+
],
|
|
337
|
+
capture_output=True,
|
|
338
|
+
text=True,
|
|
339
|
+
encoding="utf-8",
|
|
340
|
+
errors="replace",
|
|
341
|
+
timeout=10,
|
|
342
|
+
check=False,
|
|
343
|
+
env=env,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
assert result.returncode == 0, result.stderr
|
|
347
|
+
assert result.stderr.count("deterministic decision reply applied") == 2
|
|
348
|
+
assert "workflow completion detected" in result.stderr
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def test_claude_loop_removes_private_simulator_prompt_before_subject_run(tmp_path: Path):
|
|
352
|
+
fake_bin = tmp_path / "bin"
|
|
353
|
+
fake_bin.mkdir()
|
|
354
|
+
fake_claude = fake_bin / "claude"
|
|
355
|
+
fake_claude.write_text(
|
|
356
|
+
"""#!/usr/bin/env bash
|
|
357
|
+
if [[ -e "$SIMULATOR_LEAK_PATH" ]]; then
|
|
358
|
+
echo "private simulator prompt leaked to subject" >&2
|
|
359
|
+
exit 43
|
|
360
|
+
fi
|
|
361
|
+
printf '%s\n' '{"type":"system","session_id":"session-1"}'
|
|
362
|
+
printf '%s\n' '{"type":"result","subtype":"success","session_id":"session-1","result":"Workflow completed through all phases and archived."}'
|
|
363
|
+
""",
|
|
364
|
+
encoding="utf-8",
|
|
365
|
+
newline="\n",
|
|
366
|
+
)
|
|
367
|
+
fake_claude.chmod(0o755)
|
|
368
|
+
simulator_prompt = tmp_path / ".eval-simulator-prompt.txt"
|
|
369
|
+
simulator_prompt.write_text("private fixed decisions", encoding="utf-8")
|
|
370
|
+
|
|
371
|
+
env = os.environ.copy()
|
|
372
|
+
env["PATH"] = f"{utils._to_bash_path(fake_bin)}:{env.get('PATH', '')}"
|
|
373
|
+
env["SIMULATOR_LEAK_PATH"] = utils._to_bash_path(simulator_prompt)
|
|
374
|
+
result = subprocess.run(
|
|
375
|
+
[
|
|
376
|
+
utils.BASH_EXEC,
|
|
377
|
+
utils._to_bash_path(utils.SHELL_DIR / "run-claude-loop.sh"),
|
|
378
|
+
"Implement the requested change.",
|
|
379
|
+
"--max-turns",
|
|
380
|
+
"1",
|
|
381
|
+
"--simulator-prompt-file",
|
|
382
|
+
utils._to_bash_path(simulator_prompt),
|
|
383
|
+
],
|
|
384
|
+
capture_output=True,
|
|
385
|
+
text=True,
|
|
386
|
+
encoding="utf-8",
|
|
387
|
+
errors="replace",
|
|
388
|
+
timeout=10,
|
|
389
|
+
check=False,
|
|
390
|
+
env=env,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
assert result.returncode == 0, result.stderr
|
|
394
|
+
assert "private simulator prompt leaked" not in result.stderr
|
|
395
|
+
assert not simulator_prompt.exists()
|
|
396
|
+
|
|
397
|
+
|
|
287
398
|
def test_decision_point_detector_rejects_completion_statements():
|
|
288
399
|
statement = "Implementation is complete and the artifacts provide the requested evidence."
|
|
289
400
|
punctuation_summary = "Done. The counter recognizes ., !, and ? terminators."
|
|
@@ -373,7 +484,9 @@ def test_completion_point_detector_requires_explicit_non_negated_workflow_comple
|
|
|
373
484
|
"completion-point.sh", "Change add-counting completed through Archive.", check=False
|
|
374
485
|
)
|
|
375
486
|
archived_to = utils.run_shell(
|
|
376
|
-
"completion-point.sh",
|
|
487
|
+
"completion-point.sh",
|
|
488
|
+
"- **Archived to**: docs/comet/archive/2026-07-19-add-counting/",
|
|
489
|
+
check=False,
|
|
377
490
|
)
|
|
378
491
|
completed_all_phases = utils.run_shell(
|
|
379
492
|
"completion-point.sh",
|
|
@@ -388,6 +388,7 @@ def test_task_treatment(task_name, treatment_name):
|
|
|
388
388
|
|
|
389
389
|
events = extract_events(parse_output(result.stdout))
|
|
390
390
|
loop_interaction = conftest._extract_loop_interaction(result.stderr)
|
|
391
|
+
subject_turns = conftest._extract_subject_turn_evidence(result.stdout)
|
|
391
392
|
outputs = {
|
|
392
393
|
"run_id": run_id,
|
|
393
394
|
"treatment_name": treatment_name,
|
|
@@ -418,6 +419,7 @@ def test_task_treatment(task_name, treatment_name):
|
|
|
418
419
|
"mode": interaction.mode,
|
|
419
420
|
"max_turns": interaction.max_turns,
|
|
420
421
|
**loop_interaction,
|
|
422
|
+
"subject_turns": subject_turns,
|
|
421
423
|
},
|
|
422
424
|
"case_manifest": case_manifest,
|
|
423
425
|
}
|