@lnilluv/pi-ralph-loop 0.1.4-dev.0 → 0.1.4-dev.1
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 +63 -12
- package/package.json +1 -1
- package/src/index.ts +1034 -168
- package/src/ralph-draft-llm.ts +35 -7
- package/src/ralph-draft.ts +1 -1
- package/src/ralph.ts +708 -51
- package/src/runner-rpc.ts +434 -0
- package/src/runner-state.ts +822 -0
- package/src/runner.ts +957 -0
- package/tests/fixtures/parity/migrate/OPEN_QUESTIONS.md +3 -0
- package/tests/fixtures/parity/migrate/RALPH.md +27 -0
- package/tests/fixtures/parity/migrate/golden/MIGRATED.md +15 -0
- package/tests/fixtures/parity/migrate/legacy/source.md +6 -0
- package/tests/fixtures/parity/migrate/legacy/source.yaml +3 -0
- package/tests/fixtures/parity/migrate/scripts/show-legacy.sh +10 -0
- package/tests/fixtures/parity/migrate/scripts/verify.sh +15 -0
- package/tests/fixtures/parity/research/OPEN_QUESTIONS.md +3 -0
- package/tests/fixtures/parity/research/RALPH.md +45 -0
- package/tests/fixtures/parity/research/claim-evidence-checklist.md +15 -0
- package/tests/fixtures/parity/research/expected-outputs.md +22 -0
- package/tests/fixtures/parity/research/scripts/show-snapshots.sh +13 -0
- package/tests/fixtures/parity/research/scripts/verify.sh +55 -0
- package/tests/fixtures/parity/research/snapshots/app-factory-ai-cli.md +11 -0
- package/tests/fixtures/parity/research/snapshots/docs-factory-ai-cli-features-missions.md +11 -0
- package/tests/fixtures/parity/research/snapshots/factory-ai-news-missions.md +11 -0
- package/tests/fixtures/parity/research/source-manifest.md +20 -0
- package/tests/index.test.ts +3169 -104
- package/tests/parity/README.md +9 -0
- package/tests/parity/harness.py +526 -0
- package/tests/parity-harness.test.ts +42 -0
- package/tests/parity-research-fixture.test.ts +34 -0
- package/tests/ralph-draft-llm.test.ts +82 -9
- package/tests/ralph-draft.test.ts +1 -1
- package/tests/ralph.test.ts +1265 -36
- package/tests/runner-event-contract.test.ts +235 -0
- package/tests/runner-rpc.test.ts +358 -0
- package/tests/runner-state.test.ts +553 -0
- package/tests/runner.test.ts +1347 -0
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
parseRalphMarkdown,
|
|
13
13
|
type DraftRequest,
|
|
14
14
|
} from "../src/ralph.ts";
|
|
15
|
+
import { SECRET_PATH_POLICY_TOKEN } from "../src/secret-paths.ts";
|
|
15
16
|
import {
|
|
16
17
|
buildStrengtheningPrompt,
|
|
17
18
|
strengthenDraftWithLlm,
|
|
@@ -138,6 +139,23 @@ test("buildStrengtheningPrompt includes the full prompt contract and repo signal
|
|
|
138
139
|
assert.match(text, /return only a complete RALPH\.md/i);
|
|
139
140
|
});
|
|
140
141
|
|
|
142
|
+
test("buildStrengtheningPrompt states the body-and-commands compatibility contract", () => {
|
|
143
|
+
const request = makeRequest();
|
|
144
|
+
const prompt = buildStrengtheningPrompt(request, "body-and-commands");
|
|
145
|
+
const text = promptText(prompt);
|
|
146
|
+
|
|
147
|
+
assert.match(text, /strengthening scope: body-and-commands/i);
|
|
148
|
+
assert.match(text, /body-and-commands scope/i);
|
|
149
|
+
assert.match(text, /command names and run strings must match the deterministic baseline exactly/i);
|
|
150
|
+
assert.match(text, /max_iterations may stay the same or decrease from the deterministic baseline, never increase/i);
|
|
151
|
+
assert.match(text, /top-level timeout may stay the same or decrease from the deterministic baseline, never increase/i);
|
|
152
|
+
assert.match(text, /per-command timeout may stay the same or decrease from that command's baseline timeout, and must still be <= timeout/i);
|
|
153
|
+
assert.match(text, /completion_promise must remain unchanged, including remaining absent when absent from the baseline/i);
|
|
154
|
+
assert.match(text, /every \{\{\s*commands\.<name>\s*\}\} must refer to an accepted command/i);
|
|
155
|
+
assert.match(text, /baseline guardrails remain fixed in this phase/i);
|
|
156
|
+
assert.match(text, /unsupported frontmatter changes are rejected and fall back automatically/i);
|
|
157
|
+
});
|
|
158
|
+
|
|
141
159
|
test("buildStrengtheningPrompt omits secret-bearing top-level repo names", (t) => {
|
|
142
160
|
const cwd = createTempRepo();
|
|
143
161
|
t.after(() => rmSync(cwd, { recursive: true, force: true }));
|
|
@@ -319,11 +337,31 @@ test("strengthenDraftWithLlm normalizes a stronger full draft while preserving d
|
|
|
319
337
|
});
|
|
320
338
|
});
|
|
321
339
|
|
|
322
|
-
test("strengthenDraftWithLlm accepts
|
|
340
|
+
test("strengthenDraftWithLlm accepts only compatible body-and-commands changes", async () => {
|
|
323
341
|
const request = makeRequest();
|
|
324
342
|
const runtime = makeRuntime();
|
|
325
343
|
const baseline = parseRalphMarkdown(request.baselineDraft);
|
|
326
|
-
const
|
|
344
|
+
const [testsCommand, , gitLogCommand] = baseline.frontmatter.commands;
|
|
345
|
+
const rawDraft = `---
|
|
346
|
+
commands:
|
|
347
|
+
- name: ${gitLogCommand.name}
|
|
348
|
+
run: ${gitLogCommand.run}
|
|
349
|
+
timeout: ${Math.max(1, gitLogCommand.timeout - 5)}
|
|
350
|
+
- name: ${testsCommand.name}
|
|
351
|
+
run: ${testsCommand.run}
|
|
352
|
+
timeout: ${Math.max(1, testsCommand.timeout - 15)}
|
|
353
|
+
max_iterations: ${Math.max(1, baseline.frontmatter.maxIterations - 5)}
|
|
354
|
+
timeout: ${Math.max(1, Math.min(baseline.frontmatter.timeout, 120))}
|
|
355
|
+
guardrails:
|
|
356
|
+
block_commands:
|
|
357
|
+
- 'git\\s+push'
|
|
358
|
+
protected_files:
|
|
359
|
+
- '${SECRET_PATH_POLICY_TOKEN}'
|
|
360
|
+
---
|
|
361
|
+
${baseline.body.replace(/\{\{ commands\.lint \}\}/g, "")}
|
|
362
|
+
|
|
363
|
+
Use {{ commands.${testsCommand.name} }} and {{ commands.${gitLogCommand.name} }}.
|
|
364
|
+
`;
|
|
327
365
|
|
|
328
366
|
const result = await strengthenDraftWithLlm(request, runtime, {
|
|
329
367
|
scope: "body-and-commands",
|
|
@@ -334,13 +372,14 @@ test("strengthenDraftWithLlm accepts improved frontmatter and commands in body-a
|
|
|
334
372
|
const parsed = parseRalphMarkdown(result.draft.content);
|
|
335
373
|
|
|
336
374
|
assert.deepEqual(result.draft.target, request.target);
|
|
337
|
-
assert.deepEqual(parsed.frontmatter.commands, [
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
assert.
|
|
375
|
+
assert.deepEqual(parsed.frontmatter.commands, [
|
|
376
|
+
{ name: gitLogCommand.name, run: gitLogCommand.run, timeout: Math.max(1, gitLogCommand.timeout - 5) },
|
|
377
|
+
{ name: testsCommand.name, run: testsCommand.run, timeout: Math.max(1, testsCommand.timeout - 15) },
|
|
378
|
+
]);
|
|
379
|
+
assert.equal(parsed.frontmatter.maxIterations, Math.max(1, baseline.frontmatter.maxIterations - 5));
|
|
380
|
+
assert.equal(parsed.frontmatter.timeout, Math.max(1, Math.min(baseline.frontmatter.timeout, 120)));
|
|
381
|
+
assert.deepEqual(parsed.frontmatter.guardrails, baseline.frontmatter.guardrails);
|
|
382
|
+
assert.equal(parsed.body.trim(), `${baseline.body.replace(/\{\{ commands\.lint \}\}/g, "").trim()}\n\nUse {{ commands.${testsCommand.name} }} and {{ commands.${gitLogCommand.name} }}.`.trim());
|
|
344
383
|
assert.deepEqual(extractDraftMetadata(result.draft.content), {
|
|
345
384
|
generator: "pi-ralph-loop",
|
|
346
385
|
version: 2,
|
|
@@ -350,6 +389,40 @@ test("strengthenDraftWithLlm accepts improved frontmatter and commands in body-a
|
|
|
350
389
|
});
|
|
351
390
|
});
|
|
352
391
|
|
|
392
|
+
test("strengthenDraftWithLlm falls back when unsupported frontmatter changes are requested in body-and-commands scope", async () => {
|
|
393
|
+
const request = makeRequest();
|
|
394
|
+
const runtime = makeRuntime();
|
|
395
|
+
const baseline = parseRalphMarkdown(request.baselineDraft);
|
|
396
|
+
const [testsCommand, , gitLogCommand] = baseline.frontmatter.commands;
|
|
397
|
+
const rawDraft = `---
|
|
398
|
+
commands:
|
|
399
|
+
- name: ${gitLogCommand.name}
|
|
400
|
+
run: ${gitLogCommand.run}
|
|
401
|
+
timeout: ${gitLogCommand.timeout}
|
|
402
|
+
- name: ${testsCommand.name}
|
|
403
|
+
run: ${testsCommand.run}
|
|
404
|
+
timeout: ${testsCommand.timeout}
|
|
405
|
+
max_iterations: ${baseline.frontmatter.maxIterations}
|
|
406
|
+
timeout: ${baseline.frontmatter.timeout}
|
|
407
|
+
guardrails:
|
|
408
|
+
block_commands:
|
|
409
|
+
- 'git\\s+push'
|
|
410
|
+
- 'rm\\s+-rf'
|
|
411
|
+
protected_files: []
|
|
412
|
+
---
|
|
413
|
+
${baseline.body}
|
|
414
|
+
|
|
415
|
+
Use {{ commands.${testsCommand.name} }} and {{ commands.${gitLogCommand.name} }}.
|
|
416
|
+
`;
|
|
417
|
+
|
|
418
|
+
const result = await strengthenDraftWithLlm(request, runtime, {
|
|
419
|
+
scope: "body-and-commands",
|
|
420
|
+
completeImpl: async () => makeAssistantMessage([{ type: "text", text: rawDraft }]),
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
assert.deepEqual(result, { kind: "fallback" });
|
|
424
|
+
});
|
|
425
|
+
|
|
353
426
|
test("strengthenDraftWithLlm falls back on invalid model output", async () => {
|
|
354
427
|
const request = makeRequest();
|
|
355
428
|
const runtime = makeRuntime();
|
|
@@ -134,7 +134,7 @@ test("createDraftPlan strengthens with an injected active model runtime", async
|
|
|
134
134
|
strengthenCalls += 1;
|
|
135
135
|
assert.equal(runtimeArg.model?.id, activeModel.id);
|
|
136
136
|
assert.equal(runtimeArg.modelRegistry, runtime.modelRegistry);
|
|
137
|
-
assert.equal(options?.scope, "body-
|
|
137
|
+
assert.equal(options?.scope, "body-and-commands");
|
|
138
138
|
assert.match(request.baselineDraft, /reverse engineer this app/);
|
|
139
139
|
return { kind: "llm-strengthened", draft: makeDraftPlan(task, target, "llm-strengthened", cwd) };
|
|
140
140
|
},
|