Add assert-eval init conversational config designer - #110
Merged
Conversation
Add p2m/init/ package with Click command definition exposing all CLI options (--output, --describe, --from, --model, --non-interactive, --max-turns, --force, --dry-run, etc.) and stub modules for the design agent loop and file emitter. Register the 'init' subcommand in p2m/cli.py.
Thin wrapper around litellm.completion for the init design agent. Provides chat_completion() for text and chat_completion_json() for structured JSON responses, reusing the existing _classify_llm_error pattern from model_client.py.
Structural validation of YAML proposals without requiring stage modules or filesystem context. Checks top-level keys, identifiers, behavior shape, pipeline stages, and reserved dimension names. Returns error list for LLM self-correction feedback.
Assembles the system message from the prompt template, CONFIG_REFERENCE schema, preset catalog, seed config, and CLI-provided hints. Applies token-budget trimming when the prompt exceeds model context thresholds.
Three-action protocol (ask/propose/done) with JSON parsing, markdown fence stripping, validation-driven self-correction, accept/refine/skip user flow, non-interactive single-shot path, KeyboardInterrupt draft preservation, and turn budget enforcement.
Normalizes YAML via roundtrip, writes to .tmp sibling file, then renames atomically. Preserves draft on failure. Respects --force flag.
- test_init_parse_action: action parsing, edge cases, error handling - test_init_validate: YAML validation, reserved names, identifiers - test_init_emit: atomic file writing, force overwrite, dry-run - test_init_context: system message assembly, token estimation - test_init_design_agent: design loop with mocked LLM - test_init_command: CLI integration via CliRunner 44 tests, all passing.
Combine dimensions from multiple judge preset groups. Accepts a single preset name (str) or a list of names. Dimensions are merged in order; later presets override earlier ones on dimension-name conflict. Inline dimensions under pipeline.judge.dimensions still take final priority. The new _parse_preset_names helper validates input (rejects non-string items, empty strings, and non-list/non-str types) and deduplicates repeated names (first occurrence wins) for deterministic merge order.
Add MultiPresetTest with 9 cases covering pipeline.judge.preset list syntax: single-element list equivalence, multi-preset dimension union, duplicate dedupe, inline override priority, empty list, and the four validation error paths (wrong type, non-string item, empty string item, unknown preset name).
Add p2m init usage examples, tips, and CLI reference to README, AGENTS.md, quickstart, writing-eval-specs, examples/README, and status-and-roadmap. Doc examples use --model azure/gpt-5.4.
Update default --model in _command.py and _context.py to use azure/gpt-5.4-mini. Add gpt-5.4/gpt-5.4-mini context window entries and fix _context_window_for() to strip azure/ prefix. Update all init tests to match.
There was a problem hiding this comment.
Pull request overview
Adds a new p2m init CLI workflow that uses an LLM-driven multi-turn dialogue to generate an eval config YAML, and extends config parsing to support combining multiple judge presets (merging/deduping dimensions with inline overrides taking precedence). The PR also includes extensive unit/integration tests and documentation updates describing the new command.
Changes:
- Introduce
p2m initimplementation (prompt/context builder, LLM caller, design loop, validation bridge, atomic emitter) and wire it into the CLI. - Extend
pipeline.judge.presetto accept a list of preset names and merge preset dimensions deterministically with inline overrides. - Add tests + docs covering
p2m initusage and multi-preset judge behavior.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_library_e2e.py | Adds integration coverage for multi-preset judge preset merging/dedup/overrides. |
| tests/test_init_validate.py | Adds unit tests for the p2m init validation bridge. |
| tests/test_init_parse_action.py | Adds tests for JSON action parsing and fence stripping in the design agent. |
| tests/test_init_emit.py | Adds tests for atomic YAML emission/overwrite behavior. |
| tests/test_init_design_agent.py | Adds tests for the design loop (done/parse-error recovery/validation retry/budget exhaustion/LLM errors). |
| tests/test_init_context.py | Adds tests for system prompt assembly and token budget helpers. |
| tests/test_init_command.py | Adds tests for the p2m init Click command behavior. |
| tests/conftest.py | Introduces a pytest hook for debugging caplog behavior in specific tests. |
| README.md | Documents p2m init at a high level and links to CLI reference. |
| prompts/init_system.md | Adds the system prompt defining the ask/propose/done protocol and config guidance. |
| p2m/init/_validate.py | Adds schema-ish structural validation for proposed YAML during the init conversation. |
| p2m/init/_llm.py | Adds a synchronous LiteLLM wrapper with error classification behavior. |
| p2m/init/_emit.py | Adds atomic .tmp write + rename output for generated configs. |
| p2m/init/_design_agent.py | Implements the multi-turn conversational design loop and action protocol handling. |
| p2m/init/_context.py | Builds the system message with optional injected context and token-budget trimming. |
| p2m/init/_command.py | Defines the Click command/options for p2m init. |
| p2m/init/init.py | Introduces the p2m.init package marker. |
| p2m/config.py | Adds list-valued judge preset parsing and merges dimensions across presets. |
| p2m/cli.py | Registers the new init command with the top-level CLI. |
| examples/README.md | Mentions p2m init as an alternative to hand-authoring YAML. |
| docs/writing-eval-specs.md | Adds a tip pointing users to p2m init as a faster starting path. |
| docs/status-and-roadmap.md | Adds p2m init to the “Stable enough to try” list. |
| docs/reference/cli.md | Adds a full CLI reference section for p2m init. |
| docs/quickstart.md | Adds a “next steps” pointer to p2m init. |
| AGENTS.md | Updates contributor guidance to include p2m init as the fast path. |
| .gitignore | Adjusts venv ignore pattern and adds .chainlit/. |
Drop the pytest_runtest_call hook and _spy machinery that was added during development debugging. Only the reusable _SpyHandler class is kept.
- Use str.replace() instead of re.sub() for plain-string replacement of the output filename placeholder. - Fix docstring to say 'Replace' instead of 'Emit' to match the method's actual behavior.
Reject configs with a missing behavior key rather than silently accepting them. The field is central to every eval spec.
Rename the default --output from eval.yaml to eval_config.yaml for consistency with the config reference and examples. Update the CLI docs and test assertions to match.
- Pass seed_path through _command.py → run_design_loop() → build_system_message() so the seed config participates in the system prompt's existing token-budget trimming logic. - Add a warning when the seed config in the user message exceeds 10% of the model's context window, without trimming it. - Export estimate_tokens and context_window_for as public aliases from _context.py for reuse by the design agent. - Improve LLM error handling: catch LLMAuthError, LLMInputError, and LLMProviderError with specific user-facing messages instead of a bare except.
# Conflicts: # AGENTS.md
tangym
enabled auto-merge (squash)
May 28, 2026 00:10
…ensions Update init_system.md to make clear that policy_violation and overrefusal are always included as built-in dimensions (not from the safety-core preset), and reframe the judge question to ask what additional dimensions the user wants on top.
p2m init conversational config designerassert-eval init conversational config designer
mmergawi
approved these changes
May 28, 2026
changliu2
added a commit
that referenced
this pull request
May 28, 2026
…esults - Restyle both incident_triage_simple and incident_triage_agent READMEs to match the PR #86 azure_doc_qa customer-facing format: top headline, what-this-demonstrates bullets, architecture diagram, quick-start, env-var table, judge-dimension list, expected-output file list. - Strip every reference to Agent Shield / ACS / agent_guarded.py / guardrails.yaml from both folders. Keep agent.py only. - Drop trade-off chart artifact + script reference. Drop all committed result snapshots (results are highly non-deterministic; the README now describes what artifacts to expect, not specific numbers). - Consolidate to a single eval_config.yaml per folder. Drop variant configs (baseline / naive_prompt / guarded / GEPA). Rebased onto current main (post #110 multi-preset judge dimensions). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AaronAspinwall123
added a commit
that referenced
this pull request
May 28, 2026
…t_eval rename Merges 19 commits from main into the rename branch and resolves conflicts in favor of the assert_eval naming. Continues the rename so that the legacy `p2m` name is gone everywhere outside of frozen historical artifact snapshots. Conflict resolution: - All Python module docstrings: keep MIT license header from main + the rename branch's docstring text (which uses `ASSERT` for the project brand and `assert_eval` for the Python module name). - assert_eval/config.py: take main's multi-preset judge logic and rename `from p2m.library.loader` -> `from assert_eval.library.loader`. New rename work brought in by the merge: - `p2m/init/` (PR #110 conversational config designer) renamed to `assert_eval/init/` and all internal `from p2m.*` imports updated. - assert_eval/cli.py: `from p2m.init._command` -> `from assert_eval.init._command`. - New tests/test_init_*.py: all `p2m.init.*` / `p2m.cli` / `p2m.core.*` references and `p2m init` docstrings updated. - README.md, docs/quickstart.md, docs/status-and-roadmap.md, docs/writing-eval-specs.md, examples/README.md: `p2m init` -> `assert-eval init`. - .github/workflows/regression.yml: path filter `p2m/**` -> `assert_eval/**`, env var `P2M_AZURE_DEPLOYMENT` -> `ASSERT_AZURE_DEPLOYMENT`, and header comments updated. - uv.lock: package name `p2m-policy` -> `assert-eval` (matches pyproject.toml). Guard test: - tests/test_no_p2m_references.py walks every git-tracked file and fails if the legacy `p2m` name reappears outside the small allowlist of historical artifact snapshots (examples/incident_triage_agent/artifacts/results/) and the test file itself. Excluded (intentional, per the original rename convention): - examples/incident_triage_agent/artifacts/results/**/config.yaml - these are frozen records of past runs and must not be rewritten. Validated: - import assert_eval.cli, assert_eval.init._command, ... all succeed. - assert-eval --help works. - New no-p2m guard test passes and correctly fails when a `p2m` reference is reintroduced. - pytest tests (excluding viewer tests that require `npm ci`): 832 passed, 16 skipped, 0 failed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
minthigpen
reviewed
May 28, 2026
minthigpen
approved these changes
May 28, 2026
tangym
added a commit
that referenced
this pull request
May 29, 2026
* Refine init system prompt conversation flow Replace flat bullet list with structured numbered sections (1-5) covering system context, target type, behavior definition, test set generation, and judge configuration per minthigpen's PR #110 review. * Add section-coverage pacing guardrails to init prompt Smaller models (e.g. gpt-5.4-mini) were jumping to propose after only 2 questions, skipping Behavior Definition, Test Set Generation, and Judge Configuration entirely. Add three guardrails without changing minthigpen's 5-section structure: - Tighten the 'fewer rounds' clause to require verification of each remaining section rather than blanket permission to skip. - Add pacing instruction: acknowledge info from verbose answers but continue asking about uncovered sections. - Add a pre-propose self-check: verify all 5 sections have concrete answers before switching to propose. * Move section checklist into propose action as prerequisite gate Smaller models ignored the standalone 'Before proposing' section. Merge the 5-point checklist into the propose action definition itself, with stronger language: 'do NOT emit propose until every check is yes' and 'you MUST use ask instead'. * Don't ask for system prompt when target is callable Callable targets own their own prompt. Only ask for a system prompt when the user selects the model target type. * Make judge presets explicitly optional in init prompt Rewrite Section 5 (Judge Configuration) to: - Separate presets and custom dimensions into two explicit questions - State clearly that presets are optional and if declined, omit the preset: key from the YAML entirely - Add a 'Critical' paragraph reinforcing literal respect for user answers - Update checklist item #5 to say 'whether to include' instead of 'which' Fixes the issue where mini models added all judge presets (safety-core, grounding, tool-use, robustness, operational) even when the user explicitly said 'none'. * Increase default --max-turns from 20 to 30 With 5 question sections, propose/refine cycles, and potential validation retries for malformed YAML, 20 turns is too tight. 30 provides comfortable headroom without being unlimited.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
assert-eval init— an AI-powered conversational config designer that interactively buildseval_config.yamlfiles through a multi-turn dialogue with the user. Also adds multi-preset judge support so generated configs can combine multiple judge presets.What's new
assert-eval initcommandA Click-based CLI command that launches a design agent to walk users through creating an evaluation config:
_design_agent.py) — Three-action protocol (ask/propose/done) with validation-driven self-correction and draft preservation_llm.py) — Synchronouslitellmwrapper withchat_completion()andchat_completion_json()_validate.py) — Structural YAML validation without filesystem context; feeds errors back to the agent for self-correction.behavioris a required field._context.py) — Assembles system messages with token-budget trimming from existing configs, eval specs, and examples. Threadsseed_pathfor relative-path resolution and emits a token-budget warning when context is trimmed._emit.py) — Writes YAML via.tmp+ atomicreplace()prompts/init_system.md) — Design agent behavior prompt. Clarifies thatpolicy_violationandoverrefusalare always-included built-in judge dimensions, and asks the user about additional dimensions on top.CLI options:
--output,--describe,--from,--model,--non-interactive,--max-turns,--force,--dry-runDefault output:
eval_config.yamlMulti-preset judge support
pipeline.judge.presetnow accepts a list of preset names. Dimensions from all presets are merged (with dedup), and inline overrides still take precedence.Test coverage
test_library_e2e.py) for multi-preset combining, dedup, inline overrides, empty list, and error casesCommits (oldest → newest)
init: add module skeleton and CLI registrationinit: add synchronous LLM caller moduleinit: add validation bridge for proposed configsinit: add context builder for design agent system promptinit: implement design agent conversation loopinit: implement atomic file writer for generated configsinit: add system prompt and polish design agent UXAdd unit tests for p2m init modulefeat(config): allow pipeline.judge.preset to accept a list of presetstest(config): cover multi-preset combining for judge dimensionsRemove leftover debug hook from conftest.pyFix _emit.py: use replace() and correct docstringMake behavior a required field in validationChange default output filename to eval_config.yamlThread seed_path to system prompt and add token-budget warningMerge remote-tracking branch origin/main into yemingtang/p2m-initRename p2m CLI references to assert-eval in init moduledocs: use assert-eval naming in cli.md init sectiondocs: clarify policy_violation and overrefusal are built-in judge dimensions