ai-consultants 2.22.0 → 2.23.0
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/.env.example +0 -4
- package/CLAUDE.md +13 -11
- package/README.md +25 -9
- package/SKILL.md +2 -2
- package/docs/COST_RATES.md +1 -9
- package/docs/RECIPES.md +0 -2
- package/docs/cost_rates.json +1 -1
- package/docs/releases/v2.23.0.md +75 -0
- package/package.json +1 -1
- package/references/configuration.md +0 -2
- package/scripts/config.sh +5 -17
- package/scripts/consult_all.sh +1 -1
- package/scripts/lib/common.sh +15 -1
- package/scripts/lib/reflection.sh +0 -452
package/.env.example
CHANGED
|
@@ -207,10 +207,6 @@ SYNTH_MAX=10
|
|
|
207
207
|
ENABLE_DEBATE=false
|
|
208
208
|
DEBATE_ROUNDS=1 # 1 = no debate, 2-3 = with cross-critique
|
|
209
209
|
|
|
210
|
-
# Self-Reflection (experimental): generate-critique-refine loop
|
|
211
|
-
ENABLE_REFLECTION=false
|
|
212
|
-
REFLECTION_CYCLES=1
|
|
213
|
-
|
|
214
210
|
# Peer Review: anonymous evaluation
|
|
215
211
|
ENABLE_PEER_REVIEW=false
|
|
216
212
|
PEER_REVIEW_MIN_RESPONSES=3
|
package/CLAUDE.md
CHANGED
|
@@ -6,7 +6,7 @@ AI Consultants is a multi-model AI deliberation system that queries up to 11 AI
|
|
|
6
6
|
|
|
7
7
|
**Self-Exclusion**: The invoking agent is automatically excluded from the panel to prevent self-consultation. Claude Code won't query Claude, Codex CLI won't query Codex, etc.
|
|
8
8
|
|
|
9
|
-
**Version**: 2.
|
|
9
|
+
**Version**: 2.23.0
|
|
10
10
|
|
|
11
11
|
## Distribution
|
|
12
12
|
|
|
@@ -64,8 +64,7 @@ ai-consultants/
|
|
|
64
64
|
│ ├── costs.sh # Cost tracking + response limits
|
|
65
65
|
│ ├── cache.sh # Semantic caching (v2.3)
|
|
66
66
|
│ ├── api_query.sh # API mode query execution (v2.6)
|
|
67
|
-
│
|
|
68
|
-
│ └── reflection.sh # Self-reflection + judge step
|
|
67
|
+
│ └── progress.sh # Progress bars
|
|
69
68
|
├── references/
|
|
70
69
|
│ ├── configuration.md # Full configuration reference
|
|
71
70
|
│ └── details.md # Presets, strategies, best practices
|
|
@@ -194,7 +193,7 @@ Functions in `lib/common.sh`:
|
|
|
194
193
|
### Configuration Presets
|
|
195
194
|
```bash
|
|
196
195
|
# Quality Tier Presets (v2.5)
|
|
197
|
-
./scripts/consult_all.sh --preset max_quality "question" #
|
|
196
|
+
./scripts/consult_all.sh --preset max_quality "question" # 8 of 11 consultants + premium models + peer review
|
|
198
197
|
./scripts/consult_all.sh --preset medium "question" # 4 consultants + standard models
|
|
199
198
|
./scripts/consult_all.sh --preset fast "question" # 2 consultants + economy models
|
|
200
199
|
|
|
@@ -252,12 +251,6 @@ Process:
|
|
|
252
251
|
3. Aggregate peer scores to identify strongest arguments
|
|
253
252
|
4. De-anonymize in final report
|
|
254
253
|
|
|
255
|
-
### Judge Step (Overconfidence Detection)
|
|
256
|
-
Functions in `lib/reflection.sh`:
|
|
257
|
-
- `judge_response()` - Evaluates single response for overconfidence
|
|
258
|
-
- `heuristic_overconfidence_check()` - Fast fallback without LLM
|
|
259
|
-
- `judge_all_responses()` - Batch evaluation
|
|
260
|
-
|
|
261
254
|
## v2.9 Features
|
|
262
255
|
|
|
263
256
|
### Kimi CLI Support
|
|
@@ -410,7 +403,7 @@ get_model_for_tier "claude" "economy" # → claude-haiku-4-5
|
|
|
410
403
|
Three new presets leverage the model tiers:
|
|
411
404
|
|
|
412
405
|
```bash
|
|
413
|
-
# Maximum quality - all premium models + debate +
|
|
406
|
+
# Maximum quality - all premium models + debate + peer review
|
|
414
407
|
./scripts/consult_all.sh --preset max_quality "critical architecture decision"
|
|
415
408
|
|
|
416
409
|
# Balanced quality - standard models, 4 consultants, light debate
|
|
@@ -802,6 +795,15 @@ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/s
|
|
|
802
795
|
|
|
803
796
|
## Changelog
|
|
804
797
|
|
|
798
|
+
### v2.23.0
|
|
799
|
+
- **`lib/reflection.sh` deleted (452 lines) and `ENABLE_REFLECTION` / `REFLECTION_CYCLES` removed.** The module was never sourced — `grep -rn 'reflection\.sh' scripts/` matched only the file's own header — so the generate-critique-refine loop had never executed. The two flags were declared at `config.sh` and exported by four presets (`high-stakes`, `max_quality`, `fast`, `_disable_all_consultants`) with no consumer anywhere. It had also aged past the codebase: `_exec_consultant` hardcoded a Gemini/Codex/Mistral case (3 of 11 consultants; the rest hit `*) return 1`) and its Gemini branch still used the pre-`agy` CLI syntax retired in v2.15.0 — so wiring it up as written would have produced partial reflection with a broken Gemini path. Removed rather than implemented because v2.16's `converge`/`adversarial` shapes already run critique-refine off measured consensus rather than a fixed cycle count. Worth noting for archaeology: the module was *maintained* in at least three review passes (v2.15.1 de-fencing, the `--model` parity change, the v2.10.9 `((var++))` sweep) — effort spent on code that never ran.
|
|
800
|
+
- **The release gate had been red since 2.22.0 and nobody could see it.** `scripts/release.sh:26` sources `lib/common.sh` → `config.sh` → `load_user_config` *before* `npm test` at line 194, so `_apply_env_file`'s `export "$key=$value"` put the maintainer's entire `~/.config/ai-consultants/.env` into the test environment. Two suites were not hermetic against that, and the first aborted the run before the second could surface:
|
|
801
|
+
- **`test_user_config.sh`** — `test_xdg_fallback` (Test 6) unsets `AI_CONSULTANTS_CONFIG_DIR` in the suite's own shell (required, to assert the XDG branch) and `_reset_state` never restored it, so the unset leaked into all 22 later tests, which then read the *real* user config. Fixed by re-exporting an empty temp dir in `_reset_state`, making isolation order-independent; tests that legitimately override the dir per-invocation are unaffected. Plus the whole `*_USE_API` set unset at suite top (the guard `test_configure.sh` already carried), and `ENABLE_KIMI`/`GROK_API_URL` (Test 27) and `GEMINI_MODEL`/`PANIC_KEYWORDS` (Test 28) unset inside their subshells — those assert on *real* var names and `load_user_config` lets the environment win over the file by design, so with `config.sh` pre-sourced the file under test was never consulted.
|
|
802
|
+
- **`test_configure.sh`** — `run_clean_configure` scrubbed the nine API keys but no settings, while `configure`'s `has_explicit_value` reads any ambient value as a deliberate pin. An exported `DEFAULT_PRESET` therefore overrode the value Tests 6 and 10 had just written into the file they assert on. The scrub set is now derived from `configure --show-parameters` — configure's own contract — with a hard failure if that list comes back empty, so the scrub can never silently degrade to a no-op. **Verified pre-existing**: the same two assertions fail at `2ac18d4` (the v2.22.0 release commit) under the same conditions, via a throwaway worktree.
|
|
803
|
+
- **`test_functions.sh` was under-reporting failures across the whole file.** `run_tests` scores a test by its exit status — that of its LAST command — so a failing assertion followed by a passing one printed `FAIL`, incremented nothing, and let the suite exit 0. 8 of the 13 test functions run more than one assertion and none accumulated a result. The five `assert_*` helpers now set `_ASSERT_FAILED` on every failure path and `run_tests` fails a test when either that flag or the exit status is non-zero. **Caught by trying to make the new pin fail**: the first version of `test_known_feature_flags_in_sync` printed `FAIL: ... Actual: PHANTOM_FEATURE` while the suite still reported "All tests passed". Verified against a pre-existing test by breaking the first of three assertions in `test_case_conversion` — previously green, now correctly red.
|
|
804
|
+
- **`KNOWN_FEATURE_FLAGS` synced (9 → 27) and pinned.** `_discover_custom_api_agents` (`consult_all.sh:48`) walks `env` and enrolls any `ENABLE_X=true` as a consultant when `X_API_URL` is set and `X` is absent from the registry, so the 18 missing flags — `PEER_REVIEW`, `HEALTH_GATE`, `SEMANTIC_CACHE`, … — were latent phantom consultants. Measured drift: 18 missing, 0 stale. `test_known_feature_flags_in_sync` derives the expected set from `config.sh`'s top-level `ENABLE_*` declarations minus `KNOWN_CLI_AGENTS`/`KNOWN_API_AGENTS` and asserts both directions, so the next added flag fails the build. (Checked that the `^ENABLE_` grep misses nothing declared only inside functions — the sole extra hit was `AGENTNAME`, from the convention's doc comment.)
|
|
805
|
+
- **Preset tables were documenting a mode that stopped being the default in v2.16.** Found by the `/code-review max` pass on the removal branch: renaming the README column from "Reflection" to "Peer Review" turned a code-enforced "No" into a false claim, because `_disable_all_consultants` exported `ENABLE_REFLECTION=false` — the line this release deletes — whereas nothing ever clears `ENABLE_PEER_REVIEW`. Combined with `consult_all.sh:285` force-enabling peer review for the adversarial shape, `--preset medium` on a SECURITY question runs a full billed peer-review round the table promised it would not. The Debate column was stale for the same reason (`DEBATE_ROUNDS` is only read under `ORCHESTRATION_MODE=fixed`). Both tables now state only what the preset pins, with the planner's role called out. Also corrected `max_quality`'s "All consultants" → 8 of 11, which contradicted the README table in the same commit.
|
|
806
|
+
|
|
805
807
|
### v2.22.0
|
|
806
808
|
- Added the public `ai-consultants configure` / `config` subcommand. Automatic mode detects every current consultant, uses CLI-first transport selection with API fallback when credentials are available, persists to the XDG user config directory, preserves custom values and secrets while refreshing availability-derived `ENABLE_*` flags, backs up rewrites, and keeps files at mode 600.
|
|
807
809
|
- Replaced the stale 1,092-line v2.0 configurator with a compact implementation whose accepted parameter surface is derived from `.env.example`. `--set KEY=VALUE` supports repeatable automation and participates in detection, `--interactive` reviews credentials/transports/panel selection, `--advanced` reviews every parameter, `--show-parameters` exposes the contract, and side-effect-free `--dry-run` redacts secrets.
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# AI Consultants v2.
|
|
1
|
+
# AI Consultants v2.23.0
|
|
2
2
|
|
|
3
3
|
> **A harness for every question.** A panel of up to 11 frontier models that writes its own playbook per question — fan out, debate to convergence, cross-examine under adversarial review, or run a tournament — and checks its work before it reaches you.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/matteoscurati/ai-consultants)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://docs.anthropic.com/en/docs/claude-code/skills)
|
|
8
8
|
[](https://github.com/matteoscurati/ai-consultants)
|
|
@@ -428,11 +428,19 @@ Choose the right balance of quality, speed, and cost with model quality tiers.
|
|
|
428
428
|
|
|
429
429
|
### Tier Presets
|
|
430
430
|
|
|
431
|
-
| Preset | Tier | Agents |
|
|
432
|
-
|
|
433
|
-
| `max_quality` | Premium | 8
|
|
434
|
-
| `medium` | Standard | 4 |
|
|
435
|
-
| `fast` | Economy | 2 |
|
|
431
|
+
| Preset | Tier | Agents | Use Case |
|
|
432
|
+
|--------|------|--------|----------|
|
|
433
|
+
| `max_quality` | Premium | 8 of 11 | Critical decisions |
|
|
434
|
+
| `medium` | Standard | 4 | General questions |
|
|
435
|
+
| `fast` | Economy | 2 | Quick checks |
|
|
436
|
+
|
|
437
|
+
**Deliberation depth is not fixed by the preset.** Under the default
|
|
438
|
+
`ORCHESTRATION_MODE=auto` the planner picks the shape per question, so the
|
|
439
|
+
`DEBATE_ROUNDS` a preset pins applies only under `ORCHESTRATION_MODE=fixed`,
|
|
440
|
+
and a `SECURITY`-classified question runs the adversarial shape — including a
|
|
441
|
+
peer-review round — whatever preset you chose. `max_quality` additionally
|
|
442
|
+
enables peer review outright; `medium` and `fast` do not *clear* it, so an
|
|
443
|
+
enabled peer review carries into them.
|
|
436
444
|
|
|
437
445
|
### Models by Tier
|
|
438
446
|
|
|
@@ -479,8 +487,8 @@ Choose how many consultants to use:
|
|
|
479
487
|
|
|
480
488
|
| Preset | Consultants | Tier | Use Case |
|
|
481
489
|
|--------|-------------|------|----------|
|
|
482
|
-
| `max_quality` | 8
|
|
483
|
-
| `medium` | 4
|
|
490
|
+
| `max_quality` | 8 of 11 (+ peer review) | Premium | Critical decisions |
|
|
491
|
+
| `medium` | 4 | Standard | General questions |
|
|
484
492
|
| `fast` | 2 | Economy | Quick checks |
|
|
485
493
|
| `minimal` | 2 (Gemini + Codex) | Default | Quick questions, low cost |
|
|
486
494
|
| `balanced` | 4 (+ Mistral + Cursor) | Default | Standard consultations |
|
|
@@ -717,6 +725,14 @@ Each consultation generates:
|
|
|
717
725
|
|
|
718
726
|
## Changelog
|
|
719
727
|
|
|
728
|
+
### v2.23.0
|
|
729
|
+
|
|
730
|
+
- **`ENABLE_REFLECTION` and `REFLECTION_CYCLES` removed.** The self-reflection module they controlled was never called by anything, so the settings had never affected a consultation — v2.16's `converge` and `adversarial` shapes already run critique-refine off measured consensus. **If you set either key**, remove it: `configure --set ENABLE_REFLECTION=...` now exits non-zero, and both keys are dropped when an existing `.env` is rewritten.
|
|
731
|
+
- **The release gate works again.** Two test suites failed deterministically against any real user configuration, so no release since 2.22.0 could pass its own `npm test`.
|
|
732
|
+
- **`npm test` no longer swallows failures.** A failing assertion followed by a passing one inside the same test function was counted as a pass, across 8 of 13 test functions.
|
|
733
|
+
- **Feature flags can no longer be enrolled as consultants.** A registry that told feature flags apart from custom API agents was 18 entries out of date; it is now complete and pinned by a test.
|
|
734
|
+
- **Preset tables corrected** — they described a debate and peer-review depth the code has not enforced since v2.16, and called `high-stakes`/`max_quality` "all consultants" when they enable 5 and 8 of 11. See the [v2.23.0 release note](docs/releases/v2.23.0.md).
|
|
735
|
+
|
|
720
736
|
### v2.22.0
|
|
721
737
|
|
|
722
738
|
- **`ai-consultants configure`**: a public automatic configurator. It detects your installed CLIs and API keys, picks CLI-first transports, and writes a private XDG config while preserving your existing settings and secrets. Drive it with repeatable `--set KEY=VALUE`, review it with `--interactive` / `--advanced`, or preview it with `--dry-run`. See the [v2.22.0 release note](docs/releases/v2.22.0.md).
|
package/SKILL.md
CHANGED
|
@@ -5,10 +5,10 @@ license: MIT
|
|
|
5
5
|
compatibility: Requires bash, jq, and at least 2 AI CLI tools (agy, codex, vibe, etc.). macOS and Linux.
|
|
6
6
|
metadata:
|
|
7
7
|
author: matteoscurati
|
|
8
|
-
version: 2.
|
|
8
|
+
version: 2.23.0
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# AI Consultants v2.
|
|
11
|
+
# AI Consultants v2.23.0 - AI Expert Panel
|
|
12
12
|
|
|
13
13
|
**A harness for every question.** Convene a panel of AI "consultants" for coding questions — and let the engine pick *how* they deliberate: a quick read, a convergence loop, an adversarial refutation gate, a tournament, or an exhaustive sweep. Each consultant has a **configurable persona** that shapes its analysis.
|
|
14
14
|
|
package/docs/COST_RATES.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Cost Rates - AI Consultants v2.
|
|
1
|
+
# Cost Rates - AI Consultants v2.23.0
|
|
2
2
|
|
|
3
3
|
This page documents the per-token rates used by the cost tracking system.
|
|
4
4
|
|
|
@@ -102,14 +102,6 @@ Since v2.5, models are organized into three tiers. Use `apply_model_tier()` or `
|
|
|
102
102
|
|
|
103
103
|
**Estimated cost:** $0.08 - $0.15
|
|
104
104
|
|
|
105
|
-
### With Self-Reflection
|
|
106
|
-
|
|
107
|
-
**Additional parameters:**
|
|
108
|
-
- Critique + refinement cycle per consultant
|
|
109
|
-
- ~500 additional tokens per cycle
|
|
110
|
-
|
|
111
|
-
**Estimated cost:** $0.10 - $0.20
|
|
112
|
-
|
|
113
105
|
## Budget Management
|
|
114
106
|
|
|
115
107
|
### Configuration Variables
|
package/docs/RECIPES.md
CHANGED
package/docs/cost_rates.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.23.0",
|
|
3
3
|
"updated": "2026-07-16",
|
|
4
4
|
"models": {
|
|
5
5
|
"_comment_units": "All rates are USD per 1,000 tokens (per-1K). lib/costs.sh computes cost as (token_count / 1000) * rate, so every value here MUST be a per-1K rate = (provider $/1M price) / 1000. Do NOT paste $/MTok figures directly.",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Release v2.23.0
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-20
|
|
4
|
+
**Type:** Minor — removes a dead feature flag and repairs the release gate
|
|
5
|
+
**Previous:** v2.22.0
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- **`ENABLE_REFLECTION` / `REFLECTION_CYCLES` removed.** The self-reflection module they controlled was never called by anything, so the settings had never affected a consultation.
|
|
10
|
+
- **The release gate works again.** `scripts/release.sh` could not pass its own `npm test` since 2.22.0; two test suites failed deterministically against any real user configuration.
|
|
11
|
+
- **`npm test` now reports failures it used to swallow.** A failing assertion followed by a passing one inside the same test function was counted as a pass.
|
|
12
|
+
- **A registry that could enroll feature flags as consultants is fixed**, and pinned by a test so it cannot drift again.
|
|
13
|
+
- **Preset documentation corrected** — the tables described a deliberation depth the code has not enforced since v2.16.
|
|
14
|
+
|
|
15
|
+
## What's New
|
|
16
|
+
|
|
17
|
+
### Self-reflection is gone
|
|
18
|
+
|
|
19
|
+
`lib/reflection.sh` implemented a generate-critique-refine loop across 452 lines. Nothing ever sourced it. `ENABLE_REFLECTION` and `REFLECTION_CYCLES` were declared in `config.sh` and set by four presets, but no consumer read them — the flags were configuration that promised behavior the tool never performed.
|
|
20
|
+
|
|
21
|
+
The module had also aged past the codebase. Its `_exec_consultant` hardcoded a three-branch dispatch (Gemini/Codex/Mistral) predating both the 11-consultant roster and the CLI/API transport layer, and its Gemini branch still used the CLI syntax retired in v2.15.0 by the `agy` migration. Wiring it up as written would have produced reflection for 3 of 11 consultants with a broken Gemini path.
|
|
22
|
+
|
|
23
|
+
It was removed rather than implemented because v2.16 already covers the ground: the `converge` and `adversarial` orchestration shapes run critique-refine driven by measured consensus instead of a fixed cycle count.
|
|
24
|
+
|
|
25
|
+
### The release gate
|
|
26
|
+
|
|
27
|
+
`scripts/release.sh` sources `lib/common.sh` — and so `config.sh`, and so `load_user_config` — before running `npm test`. Every setting in the maintainer's own `~/.config/ai-consultants/.env` was therefore exported into the test process, and two suites were not isolated against it:
|
|
28
|
+
|
|
29
|
+
- **`test_user_config.sh`** — `test_xdg_fallback` unsets `AI_CONSULTANTS_CONFIG_DIR` in the suite's own shell, which it must in order to assert the XDG branch, but nothing restored it. The unset leaked into all 22 following tests, which then read the real user config. Two further tests asserted on real configuration variable names that an ambient export silently replaced.
|
|
30
|
+
- **`test_configure.sh`** — its `run_clean_configure` helper scrubbed the nine API keys but no settings, while `configure`'s `has_explicit_value` reads *any* ambient value as a deliberate user pin. An exported `DEFAULT_PRESET` overrode the value the preservation tests had just written into the file they were asserting on.
|
|
31
|
+
|
|
32
|
+
Both suites now derive their isolation from the contract they test rather than from a hand-listed subset: `test_user_config.sh` re-establishes an empty config directory before every test, and `test_configure.sh` builds its scrub set from `configure --show-parameters`.
|
|
33
|
+
|
|
34
|
+
This is why the failure was invisible: `configure` shipped in 2.22.0, so only a maintainer who had actually run it hit the condition, and the first failing suite aborted the run before the second could be seen.
|
|
35
|
+
|
|
36
|
+
### Test failures that were being swallowed
|
|
37
|
+
|
|
38
|
+
`test_functions.sh` scores a test function by its exit status, which in bash is that of its last command. A failing assertion followed by a passing one printed `FAIL`, counted as a pass, left the failure total at zero and exited 0. Eight of the thirteen test functions run more than one assertion and were exposed.
|
|
39
|
+
|
|
40
|
+
The `assert_*` helpers now record failures in a flag the runner consults, so a test fails if either its status or any assertion inside it did.
|
|
41
|
+
|
|
42
|
+
### Phantom consultants from feature flags
|
|
43
|
+
|
|
44
|
+
`_discover_custom_api_agents` walks the environment and enrolls any `ENABLE_X=true` as a consultant when an `X_API_URL` is also present and `X` is absent from `KNOWN_FEATURE_FLAGS`. That registry listed 9 entries against 27 live non-consultant flags, so 18 — `ENABLE_PEER_REVIEW` and `ENABLE_HEALTH_GATE` among them — were latent phantom consultants. All 27 are registered, and a test derives the expected set from `config.sh` so the next added flag fails the build instead of drifting silently.
|
|
45
|
+
|
|
46
|
+
### Preset documentation
|
|
47
|
+
|
|
48
|
+
The tier-preset tables stated a per-preset debate and peer-review depth that the code does not enforce. Under the default `ORCHESTRATION_MODE=auto` the planner chooses the shape per question: a `DEBATE_ROUNDS` value a preset pins applies only under `ORCHESTRATION_MODE=fixed`, and a `SECURITY`-classified question runs the adversarial shape — peer review included — whatever preset was chosen. `max_quality` was also described as "all consultants" while enabling 8 of the 11-consultant roster.
|
|
49
|
+
|
|
50
|
+
## Breaking Changes
|
|
51
|
+
|
|
52
|
+
**`ENABLE_REFLECTION` and `REFLECTION_CYCLES` are no longer accepted parameters.**
|
|
53
|
+
|
|
54
|
+
No runtime behavior changes — the flags controlled nothing. What changes is the configuration surface:
|
|
55
|
+
|
|
56
|
+
- `ai-consultants configure --set ENABLE_REFLECTION=...` now exits non-zero instead of accepting the value. A provisioning script that pins either key will abort after upgrading.
|
|
57
|
+
- Both keys are dropped, without warning, the next time `configure` rewrites an existing user `.env`.
|
|
58
|
+
|
|
59
|
+
## Upgrade Guide
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# If installed via git clone
|
|
63
|
+
cd ~/.claude/skills/ai-consultants && git pull
|
|
64
|
+
|
|
65
|
+
# If installed via curl | bash
|
|
66
|
+
curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/scripts/install.sh | bash
|
|
67
|
+
|
|
68
|
+
# If installed via npx — nothing to do, npx resolves the published version
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Remove `ENABLE_REFLECTION` and `REFLECTION_CYCLES` from any `.env` file or provisioning script that sets them. No other configuration changes are required.
|
|
72
|
+
|
|
73
|
+
## Contributors
|
|
74
|
+
|
|
75
|
+
- matteoscurati
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-consultants",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.23.0",
|
|
4
4
|
"description": "A harness for every question - a panel of up to 11 AI models that picks its own deliberation strategy per question (convergence, adversarial verification, tournament) and checks its work before answering",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-consultants": "bin/ai-consultants"
|
|
@@ -164,8 +164,6 @@ ENABLE_DEBATE=false # Multi-agent debate
|
|
|
164
164
|
DEBATE_ROUNDS=1 # Used by ORCHESTRATION_MODE=fixed
|
|
165
165
|
ENABLE_PEER_REVIEW=false # Anonymous peer review
|
|
166
166
|
PEER_REVIEW_MIN_RESPONSES=3 # Minimum panel size for peer review
|
|
167
|
-
ENABLE_REFLECTION=false # Generate -> critique -> refine
|
|
168
|
-
REFLECTION_CYCLES=1
|
|
169
167
|
ENABLE_PANIC_MODE=auto # auto | always | never
|
|
170
168
|
ENABLE_SMART_ROUTING=false # Category-based consultant selection
|
|
171
169
|
ENABLE_COST_TRACKING=true # Track API usage costs
|
package/scripts/config.sh
CHANGED
|
@@ -374,16 +374,6 @@ PANIC_EXTRA_DEBATE_ROUNDS="${PANIC_EXTRA_DEBATE_ROUNDS:-1}"
|
|
|
374
374
|
# Keywords that trigger panic mode when found in responses
|
|
375
375
|
PANIC_KEYWORDS="${PANIC_KEYWORDS:-uncertain|maybe|not sure|possibly|unclear|depends|hard to say|difficult to determine}"
|
|
376
376
|
|
|
377
|
-
# =============================================================================
|
|
378
|
-
# SELF-REFLECTION (v2.0)
|
|
379
|
-
# =============================================================================
|
|
380
|
-
|
|
381
|
-
# Enable auto-reflection (generate-critique-refine)
|
|
382
|
-
ENABLE_REFLECTION="${ENABLE_REFLECTION:-false}"
|
|
383
|
-
|
|
384
|
-
# Number of reflection cycles per response
|
|
385
|
-
REFLECTION_CYCLES="${REFLECTION_CYCLES:-1}"
|
|
386
|
-
|
|
387
377
|
# =============================================================================
|
|
388
378
|
# SMART ROUTING (v2.0)
|
|
389
379
|
# =============================================================================
|
|
@@ -761,7 +751,7 @@ apply_model_tier() {
|
|
|
761
751
|
# high-stakes - Broad premium panel + debate (maximum rigor)
|
|
762
752
|
#
|
|
763
753
|
# Quality Tiers (v2.5):
|
|
764
|
-
# max_quality -
|
|
754
|
+
# max_quality - 8 of 11 consultants + premium models + peer review
|
|
765
755
|
# medium - 4 consultants + standard models + light debate
|
|
766
756
|
# fast - 2 consultants + economy models, no debate
|
|
767
757
|
#
|
|
@@ -773,7 +763,7 @@ _disable_all_consultants() {
|
|
|
773
763
|
export ENABLE_CURSOR=false ENABLE_KIMI=false ENABLE_CLAUDE=false
|
|
774
764
|
export ENABLE_QWEN3=false ENABLE_GLM=false ENABLE_GROK=false
|
|
775
765
|
export ENABLE_DEEPSEEK=false ENABLE_MINIMAX=false
|
|
776
|
-
export ENABLE_DEBATE=false
|
|
766
|
+
export ENABLE_DEBATE=false
|
|
777
767
|
}
|
|
778
768
|
|
|
779
769
|
# Apply a preset configuration
|
|
@@ -800,7 +790,6 @@ apply_preset() {
|
|
|
800
790
|
export ENABLE_GEMINI=true ENABLE_CODEX=true ENABLE_MISTRAL=true
|
|
801
791
|
export ENABLE_CURSOR=true ENABLE_CLAUDE=true
|
|
802
792
|
export ENABLE_DEBATE=true DEBATE_ROUNDS=2
|
|
803
|
-
export ENABLE_REFLECTION=true REFLECTION_CYCLES=1
|
|
804
793
|
;;
|
|
805
794
|
security)
|
|
806
795
|
export ENABLE_GEMINI=true ENABLE_CODEX=true
|
|
@@ -820,7 +809,6 @@ apply_preset() {
|
|
|
820
809
|
export ENABLE_CURSOR=true ENABLE_KIMI=true
|
|
821
810
|
export ENABLE_CLAUDE=true ENABLE_QWEN3=true ENABLE_MINIMAX=true
|
|
822
811
|
export ENABLE_DEBATE=true DEBATE_ROUNDS=3
|
|
823
|
-
export ENABLE_REFLECTION=true REFLECTION_CYCLES=2
|
|
824
812
|
export ENABLE_PEER_REVIEW=true
|
|
825
813
|
;;
|
|
826
814
|
medium)
|
|
@@ -834,7 +822,7 @@ apply_preset() {
|
|
|
834
822
|
# Super fast - economy models, minimal consultants
|
|
835
823
|
apply_model_tier "economy"
|
|
836
824
|
export ENABLE_GEMINI=true ENABLE_CODEX=true
|
|
837
|
-
export ENABLE_DEBATE=false
|
|
825
|
+
export ENABLE_DEBATE=false
|
|
838
826
|
export ENABLE_COMPACT_REPORT=true
|
|
839
827
|
;;
|
|
840
828
|
*)
|
|
@@ -853,7 +841,7 @@ list_presets() {
|
|
|
853
841
|
Available presets:
|
|
854
842
|
|
|
855
843
|
Quality Tiers (v2.5):
|
|
856
|
-
max_quality
|
|
844
|
+
max_quality 8 of 11 consultants + premium models + peer review
|
|
857
845
|
medium 4 consultants + standard models + light debate
|
|
858
846
|
fast 2 consultants + economy models, no debate
|
|
859
847
|
|
|
@@ -873,4 +861,4 @@ EOF
|
|
|
873
861
|
# VERSION
|
|
874
862
|
# =============================================================================
|
|
875
863
|
|
|
876
|
-
AI_CONSULTANTS_VERSION="2.
|
|
864
|
+
AI_CONSULTANTS_VERSION="2.23.0"
|
package/scripts/consult_all.sh
CHANGED
|
@@ -82,7 +82,7 @@ Options:
|
|
|
82
82
|
balanced - 4 models, good coverage
|
|
83
83
|
thorough - 5 models, comprehensive
|
|
84
84
|
high-stakes - All models + debate
|
|
85
|
-
max_quality -
|
|
85
|
+
max_quality - 8 of 11 consultants + premium models + peer review
|
|
86
86
|
medium - 4 models + standard models + light debate
|
|
87
87
|
fast - 2 models + economy models, no debate
|
|
88
88
|
security - Security-focused + debate
|
package/scripts/lib/common.sh
CHANGED
|
@@ -276,7 +276,21 @@ to_title() {
|
|
|
276
276
|
# This list is used by discovery functions to identify custom agents
|
|
277
277
|
KNOWN_CLI_AGENTS="GEMINI CODEX MISTRAL CURSOR KIMI CLAUDE QWEN3 MINIMAX"
|
|
278
278
|
KNOWN_API_AGENTS="GLM GROK DEEPSEEK"
|
|
279
|
-
|
|
279
|
+
|
|
280
|
+
# Every non-consultant ENABLE_* flag declared in config.sh. This is a denylist
|
|
281
|
+
# guarding _discover_custom_api_agents (consult_all.sh): that function walks
|
|
282
|
+
# `env`, and any ENABLE_X=true whose X is absent here is enrolled as a custom
|
|
283
|
+
# consultant once an X_API_URL is also present. A flag missing from this list is
|
|
284
|
+
# therefore a latent phantom-consultant bug, not a cosmetic omission -- it had
|
|
285
|
+
# drifted 18 flags out of date before the pin below existed.
|
|
286
|
+
# KEEP IN SYNC with the top-level ENABLE_* declarations in config.sh;
|
|
287
|
+
# test_functions.sh::test_known_feature_flags_in_sync fails the build otherwise.
|
|
288
|
+
KNOWN_FEATURE_FLAGS="PERSONA SYNTHESIS DEBATE CLASSIFICATION SMART_ROUTING \
|
|
289
|
+
COST_TRACKING PROGRESS_BARS EARLY_TERMINATION PREFLIGHT ADVERSARIAL_VERIFY \
|
|
290
|
+
AST_EXTRACTION BUDGET_LIMIT CAPABILITY_ROUTING CAPABILITY_WEIGHTING \
|
|
291
|
+
COMPACT_REPORT COST_AWARE_ROUTING DEBATE_OPTIMIZATION HEALTH_GATE PANIC_MODE \
|
|
292
|
+
PEER_REVIEW RELIABILITY_TRACKING RESPONSE_LIMITS SELECTIVE_CONTEXT \
|
|
293
|
+
SEMANTIC_CACHE SEMANTIC_CHUNKING STANCE_CONSENSUS SYMBOL_COMPRESSION"
|
|
280
294
|
|
|
281
295
|
# Check if an agent name is a known predefined agent
|
|
282
296
|
# Usage: is_known_agent "AGENTNAME"
|
|
@@ -1,452 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# reflection.sh - Self-reflection (Reflexion pattern) for AI Consultants
|
|
3
|
-
#
|
|
4
|
-
# Implements the generate-critique-refine pattern to improve
|
|
5
|
-
# response quality through self-criticism.
|
|
6
|
-
|
|
7
|
-
# =============================================================================
|
|
8
|
-
# REFLECTION PROMPTS
|
|
9
|
-
# =============================================================================
|
|
10
|
-
|
|
11
|
-
# Prompt for self-critique
|
|
12
|
-
CRITIQUE_PROMPT_TEMPLATE='You provided this response to a programming question:
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
%RESPONSE%
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
Now critique your response. Consider:
|
|
19
|
-
1. **Correctness**: Are there logical or technical errors?
|
|
20
|
-
2. **Completeness**: Is anything important missing?
|
|
21
|
-
3. **Clarity**: Is it well explained?
|
|
22
|
-
4. **Edge cases**: Have you considered all edge cases?
|
|
23
|
-
5. **Alternatives**: Are there better approaches not mentioned?
|
|
24
|
-
6. **Risks**: Are there hidden potential problems?
|
|
25
|
-
|
|
26
|
-
Respond in JSON:
|
|
27
|
-
{
|
|
28
|
-
"critique": {
|
|
29
|
-
"strengths": ["<strengths of the response>"],
|
|
30
|
-
"weaknesses": ["<weak points>"],
|
|
31
|
-
"missing_aspects": ["<what is missing>"],
|
|
32
|
-
"errors_found": ["<identified errors>"],
|
|
33
|
-
"improvement_suggestions": ["<how to improve>"]
|
|
34
|
-
},
|
|
35
|
-
"overall_quality": <1-10>,
|
|
36
|
-
"needs_refinement": <true if significant improvement is needed>
|
|
37
|
-
}'
|
|
38
|
-
|
|
39
|
-
# Prompt for refinement
|
|
40
|
-
REFINE_PROMPT_TEMPLATE='Your original response was:
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
%ORIGINAL%
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
Your self-critique identified:
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
%CRITIQUE%
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
Now produce an IMPROVED response that:
|
|
53
|
-
1. Corrects the identified errors
|
|
54
|
-
2. Adds the missing aspects
|
|
55
|
-
3. Strengthens the weak points
|
|
56
|
-
4. Maintains the strengths
|
|
57
|
-
|
|
58
|
-
Respond with the same JSON schema as the original response, but improved.'
|
|
59
|
-
|
|
60
|
-
# =============================================================================
|
|
61
|
-
# REFLECTION FUNCTIONS
|
|
62
|
-
# =============================================================================
|
|
63
|
-
|
|
64
|
-
# Helper: Execute prompt with a specific consultant
|
|
65
|
-
# Usage: _exec_consultant <consultant> <prompt>
|
|
66
|
-
_exec_consultant() {
|
|
67
|
-
local consultant="$1"
|
|
68
|
-
local prompt="$2"
|
|
69
|
-
|
|
70
|
-
case "$consultant" in
|
|
71
|
-
Gemini) echo "$prompt" | "$GEMINI_CMD" -p - --model "$GEMINI_MODEL" 2>/dev/null ;;
|
|
72
|
-
Codex) "$CODEX_CMD" exec --skip-git-repo-check "$prompt" 2>/dev/null ;;
|
|
73
|
-
Mistral) "$MISTRAL_CMD" --prompt "$prompt" --auto-approve 2>/dev/null ;;
|
|
74
|
-
*) return 1 ;;
|
|
75
|
-
esac
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
# Generate critique of a response
|
|
79
|
-
# Usage: generate_critique <consultant> <response_content>
|
|
80
|
-
# Output: JSON with the critique
|
|
81
|
-
generate_critique() {
|
|
82
|
-
local consultant="$1"
|
|
83
|
-
local response="$2"
|
|
84
|
-
local prompt="${CRITIQUE_PROMPT_TEMPLATE//%RESPONSE%/$response}"
|
|
85
|
-
|
|
86
|
-
_exec_consultant "$consultant" "$prompt" || \
|
|
87
|
-
echo '{"critique": {"error": "Unknown consultant"}, "needs_refinement": false}'
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# Refine a response based on critique
|
|
91
|
-
# Usage: refine_response <consultant> <original_response> <critique>
|
|
92
|
-
# Output: refined response
|
|
93
|
-
refine_response() {
|
|
94
|
-
local consultant="$1"
|
|
95
|
-
local original="$2"
|
|
96
|
-
local critique="$3"
|
|
97
|
-
|
|
98
|
-
local prompt="${REFINE_PROMPT_TEMPLATE//%ORIGINAL%/$original}"
|
|
99
|
-
prompt="${prompt//%CRITIQUE%/$critique}"
|
|
100
|
-
|
|
101
|
-
_exec_consultant "$consultant" "$prompt"
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# Execute complete reflection cycle
|
|
105
|
-
# Usage: run_reflection_cycle <consultant> <query> <output_file> [cycles]
|
|
106
|
-
run_reflection_cycle() {
|
|
107
|
-
local consultant="$1"
|
|
108
|
-
local query="$2"
|
|
109
|
-
local output_file="$3"
|
|
110
|
-
local cycles="${4:-1}"
|
|
111
|
-
|
|
112
|
-
local current_response=""
|
|
113
|
-
local reflection_history=()
|
|
114
|
-
|
|
115
|
-
# Step 1: Get initial response (already done externally)
|
|
116
|
-
if [[ -f "$output_file" && -s "$output_file" ]]; then
|
|
117
|
-
current_response=$(cat "$output_file")
|
|
118
|
-
else
|
|
119
|
-
log_warn "No initial response found for reflection"
|
|
120
|
-
return 1
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
# Reflection cycles
|
|
124
|
-
for ((cycle=1; cycle<=cycles; cycle++)); do
|
|
125
|
-
log_debug "[$consultant] Reflection cycle $cycle/$cycles"
|
|
126
|
-
|
|
127
|
-
# Step 2: Self-critique
|
|
128
|
-
local critique=$(generate_critique "$consultant" "$current_response")
|
|
129
|
-
# CLIs like agy wrap JSON in a ```json fence; strip it so the jq reads
|
|
130
|
-
# below (and the final response write) see valid JSON.
|
|
131
|
-
critique=$(strip_json_fence "$critique")
|
|
132
|
-
|
|
133
|
-
# Check if refinement is needed
|
|
134
|
-
local needs_refinement=$(echo "$critique" | jq -r '.needs_refinement // false' 2>/dev/null)
|
|
135
|
-
|
|
136
|
-
if [[ "$needs_refinement" == "false" && $cycle -gt 1 ]]; then
|
|
137
|
-
log_debug "[$consultant] No refinement needed, stopping at cycle $cycle"
|
|
138
|
-
break
|
|
139
|
-
fi
|
|
140
|
-
|
|
141
|
-
# Save to history
|
|
142
|
-
reflection_history+=("$critique")
|
|
143
|
-
|
|
144
|
-
# Step 3: Refine
|
|
145
|
-
local refined=$(refine_response "$consultant" "$current_response" "$critique")
|
|
146
|
-
|
|
147
|
-
if [[ -n "$refined" ]]; then
|
|
148
|
-
current_response=$(strip_json_fence "$refined")
|
|
149
|
-
else
|
|
150
|
-
log_warn "[$consultant] Refinement failed, keeping previous response"
|
|
151
|
-
break
|
|
152
|
-
fi
|
|
153
|
-
done
|
|
154
|
-
|
|
155
|
-
# Add reflection metadata to final result
|
|
156
|
-
if echo "$current_response" | jq -e '.' > /dev/null 2>&1; then
|
|
157
|
-
echo "$current_response" | jq \
|
|
158
|
-
--argjson cycles "$cycles" \
|
|
159
|
-
--argjson history "$(printf '%s\n' ${reflection_history[@]+"${reflection_history[@]}"} | jq -s '.')" \
|
|
160
|
-
'. + {reflection: {cycles_completed: $cycles, history: $history}}' \
|
|
161
|
-
> "$output_file"
|
|
162
|
-
else
|
|
163
|
-
echo "$current_response" > "$output_file"
|
|
164
|
-
fi
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
# =============================================================================
|
|
168
|
-
# QUALITY ASSESSMENT
|
|
169
|
-
# =============================================================================
|
|
170
|
-
|
|
171
|
-
# Evaluate if a response would benefit from reflection
|
|
172
|
-
# Usage: should_reflect <response_json>
|
|
173
|
-
# Returns: 0 if yes, 1 if no
|
|
174
|
-
should_reflect() {
|
|
175
|
-
local response="$1"
|
|
176
|
-
|
|
177
|
-
# Check confidence score
|
|
178
|
-
local confidence=$(echo "$response" | jq -r '.confidence.score // 5' 2>/dev/null)
|
|
179
|
-
|
|
180
|
-
# If confidence is low, reflect
|
|
181
|
-
if [[ $confidence -lt 6 ]]; then
|
|
182
|
-
return 0
|
|
183
|
-
fi
|
|
184
|
-
|
|
185
|
-
# Check if there are many caveats
|
|
186
|
-
local caveats_count=$(echo "$response" | jq -r '.response.caveats | length // 0' 2>/dev/null)
|
|
187
|
-
if [[ $caveats_count -gt 3 ]]; then
|
|
188
|
-
return 0
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
# Check uncertainty factors
|
|
192
|
-
local uncertainty_count=$(echo "$response" | jq -r '.confidence.uncertainty_factors | length // 0' 2>/dev/null)
|
|
193
|
-
if [[ $uncertainty_count -gt 2 ]]; then
|
|
194
|
-
return 0
|
|
195
|
-
fi
|
|
196
|
-
|
|
197
|
-
return 1
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
# Calculate quality score of a response
|
|
201
|
-
# Usage: calculate_quality_score <response_json>
|
|
202
|
-
calculate_quality_score() {
|
|
203
|
-
local response="$1"
|
|
204
|
-
|
|
205
|
-
local confidence=$(echo "$response" | jq -r '.confidence.score // 5' 2>/dev/null)
|
|
206
|
-
local has_code=$(echo "$response" | jq -r '.response.code_snippets | length > 0' 2>/dev/null)
|
|
207
|
-
local has_pros=$(echo "$response" | jq -r '.response.pros | length > 0' 2>/dev/null)
|
|
208
|
-
local has_cons=$(echo "$response" | jq -r '.response.cons | length > 0' 2>/dev/null)
|
|
209
|
-
|
|
210
|
-
local score=$confidence
|
|
211
|
-
|
|
212
|
-
# Bonus for completeness
|
|
213
|
-
[[ "$has_code" == "true" ]] && score=$((score + 1))
|
|
214
|
-
[[ "$has_pros" == "true" ]] && score=$((score + 1))
|
|
215
|
-
[[ "$has_cons" == "true" ]] && score=$((score + 1))
|
|
216
|
-
|
|
217
|
-
# Cap at 10
|
|
218
|
-
if [[ $score -gt 10 ]]; then
|
|
219
|
-
score=10
|
|
220
|
-
fi
|
|
221
|
-
|
|
222
|
-
echo $score
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
# =============================================================================
|
|
226
|
-
# JUDGE STEP - OVERCONFIDENCE DETECTION (v2.2)
|
|
227
|
-
# =============================================================================
|
|
228
|
-
|
|
229
|
-
# Prompt template for the judge evaluation
|
|
230
|
-
JUDGE_PROMPT_TEMPLATE='You are an expert meta-evaluator. Your job is to detect OVERCONFIDENCE in AI responses.
|
|
231
|
-
|
|
232
|
-
Analyze this response for overconfidence signals:
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
CONSULTANT: %CONSULTANT%
|
|
236
|
-
CONFIDENCE SCORE: %CONFIDENCE%/10
|
|
237
|
-
|
|
238
|
-
SUMMARY:
|
|
239
|
-
%SUMMARY%
|
|
240
|
-
|
|
241
|
-
DETAILED RESPONSE:
|
|
242
|
-
%DETAILED%
|
|
243
|
-
|
|
244
|
-
REASONING FOR CONFIDENCE:
|
|
245
|
-
%REASONING%
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
Evaluate for overconfidence by checking:
|
|
249
|
-
|
|
250
|
-
1. **Hedging vs Certainty Mismatch**: Does the text use hedging language ("might", "could", "possibly") but claim high confidence?
|
|
251
|
-
2. **Evidence Quality**: Is the confidence score justified by the evidence/reasoning provided?
|
|
252
|
-
3. **Complexity Acknowledgment**: Does a high confidence score acknowledge the complexity of the problem?
|
|
253
|
-
4. **Edge Cases**: Are edge cases mentioned? High confidence without edge case consideration is suspicious.
|
|
254
|
-
5. **Alternative Awareness**: Does the response acknowledge alternative approaches exist?
|
|
255
|
-
|
|
256
|
-
Respond ONLY with valid JSON:
|
|
257
|
-
{
|
|
258
|
-
"consultant": "%CONSULTANT%",
|
|
259
|
-
"original_confidence": %CONFIDENCE%,
|
|
260
|
-
"overconfidence_detected": <true/false>,
|
|
261
|
-
"adjusted_confidence": <1-10>,
|
|
262
|
-
"analysis": {
|
|
263
|
-
"hedging_language_count": <number of hedging phrases found>,
|
|
264
|
-
"certainty_claims_count": <number of certainty claims>,
|
|
265
|
-
"evidence_quality": "<weak|moderate|strong>",
|
|
266
|
-
"complexity_acknowledged": <true/false>,
|
|
267
|
-
"edge_cases_mentioned": <true/false>,
|
|
268
|
-
"alternatives_acknowledged": <true/false>
|
|
269
|
-
},
|
|
270
|
-
"red_flags": ["<specific overconfidence indicators found>"],
|
|
271
|
-
"recommendation": "<keep|adjust_down|flag_for_review>"
|
|
272
|
-
}'
|
|
273
|
-
|
|
274
|
-
# Run judge evaluation on a single response
|
|
275
|
-
# Usage: judge_response <response_file>
|
|
276
|
-
# Output: JSON with judge evaluation
|
|
277
|
-
judge_response() {
|
|
278
|
-
local response_file="$1"
|
|
279
|
-
|
|
280
|
-
if [[ ! -f "$response_file" || ! -s "$response_file" ]]; then
|
|
281
|
-
echo '{"error": "Invalid response file"}'
|
|
282
|
-
return 1
|
|
283
|
-
fi
|
|
284
|
-
|
|
285
|
-
local consultant confidence summary detailed reasoning
|
|
286
|
-
consultant=$(jq -r '.consultant // "unknown"' "$response_file" 2>/dev/null)
|
|
287
|
-
confidence=$(jq -r '.confidence.score // 5' "$response_file" 2>/dev/null)
|
|
288
|
-
summary=$(jq -r '.response.summary // "No summary"' "$response_file" 2>/dev/null)
|
|
289
|
-
detailed=$(jq -r '.response.detailed // "No details"' "$response_file" 2>/dev/null | head -c 2000)
|
|
290
|
-
reasoning=$(jq -r '.confidence.reasoning // "No reasoning provided"' "$response_file" 2>/dev/null)
|
|
291
|
-
|
|
292
|
-
local prompt="${JUDGE_PROMPT_TEMPLATE}"
|
|
293
|
-
prompt="${prompt//%CONSULTANT%/$consultant}"
|
|
294
|
-
prompt="${prompt//%CONFIDENCE%/$confidence}"
|
|
295
|
-
prompt="${prompt//%SUMMARY%/$summary}"
|
|
296
|
-
prompt="${prompt//%DETAILED%/$detailed}"
|
|
297
|
-
prompt="${prompt//%REASONING%/$reasoning}"
|
|
298
|
-
|
|
299
|
-
# Use Claude for judging (most reliable for meta-analysis)
|
|
300
|
-
if command -v claude &> /dev/null; then
|
|
301
|
-
echo "$prompt" | claude --print 2>/dev/null
|
|
302
|
-
else
|
|
303
|
-
# Fallback: heuristic-based detection
|
|
304
|
-
heuristic_overconfidence_check "$response_file"
|
|
305
|
-
fi
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
# Heuristic-based overconfidence detection (no LLM required)
|
|
309
|
-
# Usage: heuristic_overconfidence_check <response_file>
|
|
310
|
-
heuristic_overconfidence_check() {
|
|
311
|
-
local response_file="$1"
|
|
312
|
-
|
|
313
|
-
local consultant confidence text
|
|
314
|
-
consultant=$(jq -r '.consultant // "unknown"' "$response_file" 2>/dev/null)
|
|
315
|
-
confidence=$(jq -r '.confidence.score // 5' "$response_file" 2>/dev/null)
|
|
316
|
-
text=$(jq -r '(.response.summary // "") + " " + (.response.detailed // "") + " " + (.confidence.reasoning // "")' "$response_file" 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
|
317
|
-
|
|
318
|
-
# Count hedging language
|
|
319
|
-
local hedging_words="might|could|possibly|perhaps|maybe|likely|probably|seems|appears|suggest"
|
|
320
|
-
local hedging_count
|
|
321
|
-
hedging_count=$(echo "$text" | grep -oiE "$hedging_words" | wc -l | tr -d ' ')
|
|
322
|
-
|
|
323
|
-
# Count certainty language
|
|
324
|
-
local certainty_words="definitely|certainly|absolutely|always|never|must|clearly|obviously|undoubtedly"
|
|
325
|
-
local certainty_count
|
|
326
|
-
certainty_count=$(echo "$text" | grep -oiE "$certainty_words" | wc -l | tr -d ' ')
|
|
327
|
-
|
|
328
|
-
# Check for edge cases mention
|
|
329
|
-
local edge_case_mentioned=false
|
|
330
|
-
echo "$text" | grep -qiE "edge case|corner case|exception|special case" && edge_case_mentioned=true
|
|
331
|
-
|
|
332
|
-
# Check for alternatives mention
|
|
333
|
-
local alternatives_mentioned=false
|
|
334
|
-
echo "$text" | grep -qiE "alternative|another approach|other option|could also|alternatively" && alternatives_mentioned=true
|
|
335
|
-
|
|
336
|
-
# Calculate overconfidence indicators
|
|
337
|
-
local red_flags=()
|
|
338
|
-
local overconfidence=false
|
|
339
|
-
local adjusted=$confidence
|
|
340
|
-
|
|
341
|
-
# High confidence + lots of hedging = suspicious
|
|
342
|
-
if [[ $confidence -ge 8 && $hedging_count -ge 3 ]]; then
|
|
343
|
-
red_flags+=("High confidence with excessive hedging language")
|
|
344
|
-
overconfidence=true
|
|
345
|
-
adjusted=$((confidence - 2))
|
|
346
|
-
fi
|
|
347
|
-
|
|
348
|
-
# High confidence + no edge cases = suspicious
|
|
349
|
-
if [[ $confidence -ge 8 && "$edge_case_mentioned" == "false" ]]; then
|
|
350
|
-
red_flags+=("High confidence without edge case consideration")
|
|
351
|
-
overconfidence=true
|
|
352
|
-
adjusted=$((adjusted - 1))
|
|
353
|
-
fi
|
|
354
|
-
|
|
355
|
-
# Very high confidence is almost always overconfident
|
|
356
|
-
if [[ $confidence -ge 9 ]]; then
|
|
357
|
-
red_flags+=("Extremely high confidence (9-10) is rarely justified")
|
|
358
|
-
overconfidence=true
|
|
359
|
-
adjusted=$((adjusted - 1))
|
|
360
|
-
fi
|
|
361
|
-
|
|
362
|
-
# Clamp adjusted confidence
|
|
363
|
-
[[ $adjusted -lt 1 ]] && adjusted=1
|
|
364
|
-
[[ $adjusted -gt 10 ]] && adjusted=10
|
|
365
|
-
|
|
366
|
-
local recommendation="keep"
|
|
367
|
-
if [[ "$overconfidence" == "true" ]]; then
|
|
368
|
-
if [[ $((confidence - adjusted)) -ge 2 ]]; then
|
|
369
|
-
recommendation="adjust_down"
|
|
370
|
-
else
|
|
371
|
-
recommendation="flag_for_review"
|
|
372
|
-
fi
|
|
373
|
-
fi
|
|
374
|
-
|
|
375
|
-
jq -n \
|
|
376
|
-
--arg consultant "$consultant" \
|
|
377
|
-
--argjson original "$confidence" \
|
|
378
|
-
--argjson overconfidence "$overconfidence" \
|
|
379
|
-
--argjson adjusted "$adjusted" \
|
|
380
|
-
--argjson hedging "$hedging_count" \
|
|
381
|
-
--argjson certainty "$certainty_count" \
|
|
382
|
-
--argjson edge_cases "$edge_case_mentioned" \
|
|
383
|
-
--argjson alternatives "$alternatives_mentioned" \
|
|
384
|
-
--arg red_flags "$(IFS='|'; echo "${red_flags[*]:-}")" \
|
|
385
|
-
--arg recommendation "$recommendation" \
|
|
386
|
-
'{
|
|
387
|
-
consultant: $consultant,
|
|
388
|
-
original_confidence: $original,
|
|
389
|
-
overconfidence_detected: $overconfidence,
|
|
390
|
-
adjusted_confidence: $adjusted,
|
|
391
|
-
analysis: {
|
|
392
|
-
hedging_language_count: $hedging,
|
|
393
|
-
certainty_claims_count: $certainty,
|
|
394
|
-
evidence_quality: (if $hedging > $certainty then "weak" elif $hedging == $certainty then "moderate" else "strong" end),
|
|
395
|
-
complexity_acknowledged: ($hedging > 0),
|
|
396
|
-
edge_cases_mentioned: $edge_cases,
|
|
397
|
-
alternatives_acknowledged: $alternatives
|
|
398
|
-
},
|
|
399
|
-
red_flags: ($red_flags | split("|") | map(select(. != ""))),
|
|
400
|
-
recommendation: $recommendation
|
|
401
|
-
}'
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
# Run judge evaluation on all responses in a directory
|
|
405
|
-
# Usage: judge_all_responses <responses_dir> <output_file>
|
|
406
|
-
judge_all_responses() {
|
|
407
|
-
local responses_dir="$1"
|
|
408
|
-
local output_file="$2"
|
|
409
|
-
|
|
410
|
-
local results='[]'
|
|
411
|
-
local overconfidence_count=0
|
|
412
|
-
local total_count=0
|
|
413
|
-
|
|
414
|
-
for f in "$responses_dir"/*.json; do
|
|
415
|
-
# Shared metadata filter (common.sh): also excludes orchestration.json,
|
|
416
|
-
# panic_diagnosis.json, optimization_metrics.json, stance_options.json,
|
|
417
|
-
# which this loop previously judged as if they were consultant answers.
|
|
418
|
-
if _is_consultant_response_file "$f"; then
|
|
419
|
-
local evaluation
|
|
420
|
-
evaluation=$(judge_response "$f")
|
|
421
|
-
|
|
422
|
-
if echo "$evaluation" | jq -e '.' > /dev/null 2>&1; then
|
|
423
|
-
results=$(echo "$results" | jq --argjson eval "$evaluation" '. + [$eval]')
|
|
424
|
-
|
|
425
|
-
local is_overconfident
|
|
426
|
-
is_overconfident=$(echo "$evaluation" | jq -r '.overconfidence_detected // false')
|
|
427
|
-
[[ "$is_overconfident" == "true" ]] && { ((overconfidence_count++)) || true; }
|
|
428
|
-
((total_count++)) || true
|
|
429
|
-
fi
|
|
430
|
-
fi
|
|
431
|
-
done
|
|
432
|
-
|
|
433
|
-
# Generate summary
|
|
434
|
-
jq -n \
|
|
435
|
-
--argjson evaluations "$results" \
|
|
436
|
-
--argjson overconfident "$overconfidence_count" \
|
|
437
|
-
--argjson total "$total_count" \
|
|
438
|
-
'{
|
|
439
|
-
judge_report: {
|
|
440
|
-
timestamp: (now | todate),
|
|
441
|
-
total_evaluated: $total,
|
|
442
|
-
overconfidence_detected: $overconfident,
|
|
443
|
-
evaluations: $evaluations,
|
|
444
|
-
summary: {
|
|
445
|
-
reliability: (if $overconfident == 0 then "high" elif ($overconfident / $total) < 0.3 then "medium" else "low" end),
|
|
446
|
-
action_required: ($overconfident > 0)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}' > "$output_file"
|
|
450
|
-
|
|
451
|
-
cat "$output_file"
|
|
452
|
-
}
|