ai-consultants 3.1.1 → 3.2.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 +2 -1
- package/CLAUDE.md +13 -5
- package/README.md +11 -4
- package/SKILL.md +2 -2
- package/docs/COST_RATES.md +3 -3
- package/docs/cost_rates.json +11 -7
- package/docs/releases/v3.2.0.md +96 -0
- package/package.json +1 -1
- package/references/configuration.md +12 -1
- package/scripts/config.sh +4 -3
- package/scripts/configure.sh +51 -4
- package/scripts/lib/api.sh +6 -2
- package/scripts/lib/api_query.sh +18 -1
- package/scripts/lib/common.sh +8 -4
- package/scripts/lib/costs.sh +17 -7
- package/scripts/query_claude.sh +39 -8
package/.env.example
CHANGED
|
@@ -144,9 +144,10 @@ KIMI_TIMEOUT=180
|
|
|
144
144
|
KIMI_CMD=kimi
|
|
145
145
|
|
|
146
146
|
# Claude - The Synthesizer
|
|
147
|
-
CLAUDE_MODEL=claude-opus-
|
|
147
|
+
CLAUDE_MODEL=claude-opus-5 # ai-consultants:default
|
|
148
148
|
CLAUDE_TIMEOUT=240
|
|
149
149
|
CLAUDE_CMD=claude
|
|
150
|
+
CLAUDE_API_MAX_TOKENS=16384
|
|
150
151
|
|
|
151
152
|
# Qwen3 - The Analyst (CLI/API switchable v2.7)
|
|
152
153
|
QWEN3_MODEL=qwen3.7-max
|
package/CLAUDE.md
CHANGED
|
@@ -6,7 +6,7 @@ AI Consultants is a multi-model coverage system that queries up to 11 AI consult
|
|
|
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**: 3.
|
|
9
|
+
**Version**: 3.2.0
|
|
10
10
|
|
|
11
11
|
## Distribution
|
|
12
12
|
|
|
@@ -368,7 +368,7 @@ Three tiers of models are available for each consultant, configurable via `apply
|
|
|
368
368
|
|
|
369
369
|
| Tier | Description | Example Models |
|
|
370
370
|
|------|-------------|----------------|
|
|
371
|
-
| **premium** | Latest flagship models | claude-opus-
|
|
371
|
+
| **premium** | Latest flagship models | claude-opus-5, Gemini 3.1 Pro (High), gpt-5.5 |
|
|
372
372
|
| **standard** | Good quality at reasonable cost | claude-sonnet-4-6, Gemini 3.5 Flash (High), gpt-5.4 |
|
|
373
373
|
| **economy** | Optimized for speed and low cost | claude-haiku-4-5, Gemini 3.5 Flash (Low), gpt-5.4-nano |
|
|
374
374
|
|
|
@@ -400,12 +400,12 @@ Three new presets leverage the model tiers:
|
|
|
400
400
|
./scripts/consult_all.sh --preset fast "quick syntax question"
|
|
401
401
|
```
|
|
402
402
|
|
|
403
|
-
### Premium Model Defaults (
|
|
403
|
+
### Premium Model Defaults (July 2026)
|
|
404
404
|
All consultants now use premium models by default:
|
|
405
405
|
|
|
406
406
|
| Consultant | Default Model |
|
|
407
407
|
|------------|---------------|
|
|
408
|
-
| Claude | claude-opus-
|
|
408
|
+
| Claude | claude-opus-5 |
|
|
409
409
|
| Gemini | Gemini 3.1 Pro (High) (via agy CLI) |
|
|
410
410
|
| Codex | gpt-5.5 |
|
|
411
411
|
| Mistral | mistral-large-3 |
|
|
@@ -613,7 +613,8 @@ for f in scripts/*.sh scripts/lib/*.sh; do bash -n "$f" && echo "OK: $f"; done
|
|
|
613
613
|
| `ENABLE_SMART_ROUTING` | false | Intelligent routing by category |
|
|
614
614
|
| `ENABLE_COST_TRACKING` | true | Track costs |
|
|
615
615
|
| `MAX_SESSION_COST` | 1.00 | Max budget ($) |
|
|
616
|
-
| `CLAUDE_MODEL` | claude-opus-
|
|
616
|
+
| `CLAUDE_MODEL` | claude-opus-5 | Claude model (v2.5) |
|
|
617
|
+
| `CLAUDE_API_MAX_TOKENS` | 16384 | Claude API thinking + visible-output budget |
|
|
617
618
|
| `GEMINI_MODEL` | Gemini 3.1 Pro (High) | Gemini agy CLI model (v2.15) |
|
|
618
619
|
| `GEMINI_API_MODEL` | gemini-3.1-pro-preview | Gemini API-mode model ID (v2.15) |
|
|
619
620
|
| `CODEX_MODEL` | gpt-5.5 | Codex model (v2.5) |
|
|
@@ -786,6 +787,13 @@ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/s
|
|
|
786
787
|
|
|
787
788
|
## Changelog
|
|
788
789
|
|
|
790
|
+
### v3.2.0
|
|
791
|
+
- **Claude premium upgraded from Opus 4.8 to Opus 5.** The default `CLAUDE_MODEL`, premium/max/best tier, standalone adapter fallback, configuration examples, model table, and cost catalog now resolve to the canonical `claude-opus-5` ID (`scripts/config.sh:274`, `scripts/query_claude.sh:29`). Pricing remains $5/$25 per million tokens; `claude-opus-4-8` stays in the legacy catalog for historical responses and intentional pins.
|
|
792
|
+
- **Opus 5 adaptive thinking is accounted for end to end.** Claude CLI mode now requests the JSON result envelope, extracts visible `.result`, aggregates provider usage across `modelUsage`, and persists the provider's exact `costUSD` (`scripts/query_claude.sh:72-126`, `scripts/lib/common.sh:904-980`, `scripts/lib/costs.sh:307-354`). This fixes the review finding that pricing only the visible answer undercounted hidden thinking and cache charges. The implementation deliberately prefers provider cost over reconstructing cache pricing from token totals.
|
|
793
|
+
- **Anthropic API responses no longer disappear when thinking precedes text.** `parse_anthropic_response` selects every `type=text` block rather than assuming `.content[0].text` (`scripts/lib/api.sh:325-343`). The API token budget is now the configurable `CLAUDE_API_MAX_TOKENS=16384`, shared by adaptive thinking and visible output; `stop_reason=max_tokens` fails closed instead of admitting a partial answer into synthesis (`scripts/lib/api_query.sh:94-153`).
|
|
794
|
+
- **Historical generated defaults migrate with provenance.** Before this release, `init` copied `CLAUDE_MODEL=claude-opus-4-8` without distinguishing a generated default from a user pin, so the new runtime fallback was unreachable for existing installations. `configure` now upgrades that exact historical value to Opus 5 and writes `# ai-consultants:default`; model values supplied by environment, interactive input, or `--set` receive `# ai-consultants:pin` and survive later rewrites (`scripts/configure.sh:183-291`, `scripts/configure.sh:357-420`). An intentionally retained 4.8 value should be reasserted once with `--set CLAUDE_MODEL=claude-opus-4-8`.
|
|
795
|
+
- **Verification expanded around all four review findings.** `test_query_claude.sh` exercises CLI JSON extraction, measured usage, provider cost persistence, and session billing. `test_api_transport.sh` covers thinking-before-text, the 16,384-token request default, invalid budgets, and truncation rejection; `test_configure.sh` covers managed migration and persistent pins. Full gate: 17/17 suites; core suite: 299/299; shellcheck green. The real maintainer config was not rewritten during implementation and remained on 4.8 until the release installation step.
|
|
796
|
+
|
|
789
797
|
### v3.1.1
|
|
790
798
|
- **`doctor` no longer aborts at the first missing enabled consultant.** The v3.1.0 tag workflow exposed the pre-existing `set -e` interaction when Grok became CLI-first and the clean Ubuntu runner had no `grok` binary: the main JSON diagnostic exited before emitting output. Missing CLI/API configuration checks now add their issue and continue to the final summary, which still exits unhealthy. `test_doctor.sh` stubs the complete CLI roster, rejects empty JSON output, and includes a dedicated missing-Grok regression. Full gate: 16/16 suites; shellcheck green.
|
|
791
799
|
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# AI Consultants v3.
|
|
1
|
+
# AI Consultants v3.2.0
|
|
2
2
|
|
|
3
3
|
> **Coverage, not a single guess.** A panel of up to 11 frontier models from different vendors fans out on your question in parallel and hands you the *union* of what they collectively see — the risks, edge cases, and approaches a single model misses.
|
|
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)
|
|
@@ -444,7 +444,7 @@ parallel and returns the coverage union.
|
|
|
444
444
|
|
|
445
445
|
| Consultant | Premium | Standard | Economy |
|
|
446
446
|
|------------|---------|----------|---------|
|
|
447
|
-
| Claude | claude-opus-
|
|
447
|
+
| Claude | claude-opus-5 | claude-sonnet-4-6 | claude-haiku-4-5 |
|
|
448
448
|
| Gemini | Gemini 3.1 Pro (High) | Gemini 3.5 Flash (High) | Gemini 3.5 Flash (Low) |
|
|
449
449
|
| Codex | gpt-5.5 | gpt-5.4 | gpt-5.4-nano |
|
|
450
450
|
| Mistral | mistral-large-3 | mistral-medium-latest | devstral-small-2 |
|
|
@@ -546,7 +546,13 @@ with `--set`). Rewrites create a private timestamped backup. Use `--advanced` to
|
|
|
546
546
|
review every parameter or `--dry-run` to preview a redacted result.
|
|
547
547
|
Auto-selected `*_USE_API` values are marked `# ai-consultants:auto`, allowing a
|
|
548
548
|
later run to adapt when a CLI or credential changes. Environment variables,
|
|
549
|
-
`--set`, and unmarked values remain explicit user choices
|
|
549
|
+
`--set`, and unmarked values remain explicit user choices, except for the exact
|
|
550
|
+
historical generated Claude default described below.
|
|
551
|
+
Managed model defaults use `# ai-consultants:default`; `configure` upgrades the
|
|
552
|
+
historical unmarked `CLAUDE_MODEL=claude-opus-4-8` default to Opus 5. To keep
|
|
553
|
+
4.8 intentionally, run
|
|
554
|
+
`ai-consultants configure --set CLAUDE_MODEL=claude-opus-4-8`; explicit model
|
|
555
|
+
overrides are stored with `# ai-consultants:pin`.
|
|
550
556
|
|
|
551
557
|
Enter credentials through `--interactive`/`--advanced` or export them before the
|
|
552
558
|
run; avoid passing API keys through `--set`, where the shell may retain them in
|
|
@@ -563,6 +569,7 @@ DEFAULT_STRATEGY=coverage # coverage | compare_only | majority | risk_averse
|
|
|
563
569
|
ENABLE_SMART_ROUTING=true # Auto-select consultants by question category
|
|
564
570
|
MAX_SESSION_COST=1.00 # USD budget cap (paired with ENABLE_BUDGET_LIMIT=true to enforce)
|
|
565
571
|
KIMI_MODEL=kimi-code/k3 # Pin the Kimi consultant to K3
|
|
572
|
+
CLAUDE_API_MAX_TOKENS=16384 # Shared thinking + visible-output budget in API mode
|
|
566
573
|
```
|
|
567
574
|
|
|
568
575
|
Full reference: [`references/configuration.md`](references/configuration.md). Copy-paste workflows: [`docs/RECIPES.md`](docs/RECIPES.md). For category-aware preset suggestions: `ai-consultants doctor --suggest-preset --question "..."`.
|
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: 3.
|
|
8
|
+
version: 3.2.0
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# AI Consultants v3.
|
|
11
|
+
# AI Consultants v3.2.0 - AI Expert Panel
|
|
12
12
|
|
|
13
13
|
**Coverage, not a single guess.** Convene a panel of AI "consultants" from different vendors for coding questions: they fan out in parallel and you get the *union* of what they collectively see — the risks, edge cases, and approaches a single model misses. Each consultant has a **configurable persona** that decorrelates its analysis.
|
|
14
14
|
|
package/docs/COST_RATES.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Cost Rates - AI Consultants v3.
|
|
1
|
+
# Cost Rates - AI Consultants v3.2.0
|
|
2
2
|
|
|
3
3
|
This page documents the per-token rates used by the cost tracking system.
|
|
4
4
|
|
|
@@ -26,7 +26,7 @@ Since v2.5, models are organized into three tiers. Use `apply_model_tier()` or `
|
|
|
26
26
|
| gpt-5.5 | Premium | $0.005 | Codex |
|
|
27
27
|
| gpt-5.4 | Standard | $0.0025 | Codex |
|
|
28
28
|
| gpt-5.4-nano | Economy | $0.0002 | Codex |
|
|
29
|
-
| claude-opus-
|
|
29
|
+
| claude-opus-5 | Premium | $0.005 | Claude |
|
|
30
30
|
| claude-sonnet-4-6 | Standard | $0.003 | Claude |
|
|
31
31
|
| claude-haiku-4-5 | Economy | $0.001 | Claude |
|
|
32
32
|
| mistral-large-3 | Premium | $0.002 | Mistral |
|
|
@@ -59,7 +59,7 @@ Since v2.5, models are organized into three tiers. Use `apply_model_tier()` or `
|
|
|
59
59
|
| gpt-5.5 | Premium | $0.030 | Codex |
|
|
60
60
|
| gpt-5.4 | Standard | $0.015 | Codex |
|
|
61
61
|
| gpt-5.4-nano | Economy | $0.00125 | Codex |
|
|
62
|
-
| claude-opus-
|
|
62
|
+
| claude-opus-5 | Premium | $0.025 | Claude |
|
|
63
63
|
| claude-sonnet-4-6 | Standard | $0.015 | Claude |
|
|
64
64
|
| claude-haiku-4-5 | Economy | $0.005 | Claude |
|
|
65
65
|
| mistral-large-3 | Premium | $0.006 | Mistral |
|
package/docs/cost_rates.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
3
|
-
"updated": "2026-07-
|
|
2
|
+
"version": "3.2.0",
|
|
3
|
+
"updated": "2026-07-25",
|
|
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.",
|
|
6
|
-
"_comment_premium": "Premium tier models -
|
|
7
|
-
"claude-opus-
|
|
6
|
+
"_comment_premium": "Premium tier models - Jul 2026",
|
|
7
|
+
"claude-opus-5": {
|
|
8
8
|
"input": 0.005,
|
|
9
9
|
"output": 0.025
|
|
10
10
|
},
|
|
@@ -137,6 +137,10 @@
|
|
|
137
137
|
"output": 0.001
|
|
138
138
|
},
|
|
139
139
|
"_comment_legacy": "Legacy models for backwards compatibility",
|
|
140
|
+
"claude-opus-4-8": {
|
|
141
|
+
"input": 0.005,
|
|
142
|
+
"output": 0.025
|
|
143
|
+
},
|
|
140
144
|
"claude-opus-4-7": {
|
|
141
145
|
"input": 0.005,
|
|
142
146
|
"output": 0.025
|
|
@@ -331,8 +335,8 @@
|
|
|
331
335
|
"qwen3.8-max-preview"
|
|
332
336
|
],
|
|
333
337
|
"consultant_fallbacks": {
|
|
334
|
-
"_comment": "Premium defaults - Updated
|
|
335
|
-
"claude": "claude-opus-
|
|
338
|
+
"_comment": "Premium defaults - Updated Jul 2026",
|
|
339
|
+
"claude": "claude-opus-5",
|
|
336
340
|
"gemini": "Gemini 3.1 Pro (High)",
|
|
337
341
|
"codex": "gpt-5.5",
|
|
338
342
|
"mistral": "mistral-large-3",
|
|
@@ -347,7 +351,7 @@
|
|
|
347
351
|
"model_tiers": {
|
|
348
352
|
"_comment": "Model tiers for apply_model_tier() function",
|
|
349
353
|
"premium": {
|
|
350
|
-
"claude": "claude-opus-
|
|
354
|
+
"claude": "claude-opus-5",
|
|
351
355
|
"gemini": "Gemini 3.1 Pro (High)",
|
|
352
356
|
"codex": "gpt-5.5",
|
|
353
357
|
"mistral": "mistral-large-3",
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Release v3.2.0
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-25
|
|
4
|
+
**Type:** Minor — Claude moves to Opus 5 with adaptive-thinking-safe transports and billing
|
|
5
|
+
**Previous:** v3.1.1
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- **Claude now uses `claude-opus-5` as its premium default** across direct configuration, model tiers, documentation, and cost tracking.
|
|
10
|
+
- **Claude CLI costs now come directly from the provider**, including adaptive thinking and cache charges that are absent from the visible answer.
|
|
11
|
+
- **Anthropic API thinking blocks are handled correctly**, and responses truncated by the shared thinking/output budget are rejected instead of synthesized as complete.
|
|
12
|
+
- **Existing generated Opus 4.8 defaults migrate to Opus 5**, while explicit model pins are recorded and preserved.
|
|
13
|
+
- **Opus 4.8 remains supported** for historical responses and intentional overrides.
|
|
14
|
+
|
|
15
|
+
## What's New
|
|
16
|
+
|
|
17
|
+
### Opus 5 premium default
|
|
18
|
+
|
|
19
|
+
The Claude consultant, premium/max/best quality tier, standalone adapter fallback, examples, and cost catalog now use the canonical `claude-opus-5` model ID. Standard and economy tiers remain on Claude Sonnet 4.6 and Haiku 4.5.
|
|
20
|
+
|
|
21
|
+
Opus 5 retains the previous $5 per million input tokens and $25 per million output tokens. The legacy Opus 4.8 rates remain available so historical sessions and pinned installations continue to be priced correctly.
|
|
22
|
+
|
|
23
|
+
### Exact Claude CLI usage and cost
|
|
24
|
+
|
|
25
|
+
Claude CLI mode now requests its JSON result envelope. AI Consultants extracts:
|
|
26
|
+
|
|
27
|
+
- the visible answer from `.result`;
|
|
28
|
+
- measured input, cache, and output usage from `modelUsage`;
|
|
29
|
+
- the provider-reported `costUSD`.
|
|
30
|
+
|
|
31
|
+
The exact provider cost takes precedence over local token-rate reconstruction. This includes adaptive-thinking and cache charges even though those tokens do not appear in the visible answer.
|
|
32
|
+
|
|
33
|
+
### Adaptive-thinking-safe API mode
|
|
34
|
+
|
|
35
|
+
Anthropic responses may place a thinking block before one or more visible text blocks. The parser now collects every visible `type=text` block instead of assuming the first content block contains the answer.
|
|
36
|
+
|
|
37
|
+
The new `CLAUDE_API_MAX_TOKENS` setting defaults to 16,384 tokens. Anthropic counts adaptive thinking and visible output against this shared budget. If the provider returns `stop_reason=max_tokens`, the consultation fails as truncated rather than entering synthesis as a complete response.
|
|
38
|
+
|
|
39
|
+
### Managed configuration migration
|
|
40
|
+
|
|
41
|
+
Older `ai-consultants init` templates wrote the then-current Opus 4.8 default as an ordinary value. Running `ai-consultants configure` now recognizes that exact historical generated default, upgrades it to Opus 5, and records managed provenance.
|
|
42
|
+
|
|
43
|
+
Explicit model choices are written with an `# ai-consultants:pin` marker and survive subsequent configuration refreshes.
|
|
44
|
+
|
|
45
|
+
## Breaking Changes
|
|
46
|
+
|
|
47
|
+
None — this release is backwards-compatible. Opus 4.8 remains selectable and priced.
|
|
48
|
+
|
|
49
|
+
If `CLAUDE_MODEL=claude-opus-4-8` was an intentional unmarked override rather than the generated default, reassert it once after upgrading:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ai-consultants configure --set CLAUDE_MODEL=claude-opus-4-8
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Upgrade Guide
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# If installed via git clone
|
|
59
|
+
cd ~/.claude/skills/ai-consultants && git pull
|
|
60
|
+
|
|
61
|
+
# If installed via curl | bash
|
|
62
|
+
curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/scripts/install.sh | bash
|
|
63
|
+
|
|
64
|
+
# If used through npx
|
|
65
|
+
npx ai-consultants@latest "your question"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Refresh persistent configuration so a historical generated Opus 4.8 value migrates:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
ai-consultants configure
|
|
72
|
+
ai-consultants doctor
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
API users may override the shared thinking/output budget if needed:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ai-consultants configure --set CLAUDE_API_MAX_TOKENS=32768
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Verification
|
|
82
|
+
|
|
83
|
+
- Full repository gate: 17/17 suites
|
|
84
|
+
- Core suite: 299/299 checks
|
|
85
|
+
- Claude CLI JSON/cost regression suite: 6/6 checks
|
|
86
|
+
- Anthropic transport regression suite: 48/48 checks
|
|
87
|
+
- Shellcheck and release-surface validation
|
|
88
|
+
- Live local Claude CLI JSON envelope verified with `claude-opus-5`
|
|
89
|
+
|
|
90
|
+
## Commits
|
|
91
|
+
|
|
92
|
+
- `3963c3c` feat: upgrade Claude consultant to Opus 5
|
|
93
|
+
|
|
94
|
+
## Contributors
|
|
95
|
+
|
|
96
|
+
- Matteo Scurati
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-consultants",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.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"
|
|
@@ -54,6 +54,11 @@ ai-consultants configure --dry-run
|
|
|
54
54
|
Use the hidden interactive credential prompts (or exported environment variables)
|
|
55
55
|
for API keys; command-line arguments may be visible in shell history and process
|
|
56
56
|
inspection.
|
|
57
|
+
Model defaults carry an `# ai-consultants:default` marker. On rewrite,
|
|
58
|
+
`configure` upgrades the historical unmarked
|
|
59
|
+
`CLAUDE_MODEL=claude-opus-4-8` generated default to Opus 5. An explicit model
|
|
60
|
+
override supplied with `--set` is stored with `# ai-consultants:pin`, so
|
|
61
|
+
`--set CLAUDE_MODEL=claude-opus-4-8` keeps the legacy model intentionally.
|
|
57
62
|
The exhaustive parameter contract is [`.env.example`](../.env.example); the
|
|
58
63
|
configurator derives its accepted keys from that template, while
|
|
59
64
|
[`scripts/config.sh`](../scripts/config.sh) remains the runtime source of truth.
|
|
@@ -235,7 +240,8 @@ ENABLE_DEEPSEEK=false
|
|
|
235
240
|
```bash
|
|
236
241
|
GEMINI_MODEL=Gemini 3.1 Pro (High) # agy CLI display name; API mode uses GEMINI_API_MODEL
|
|
237
242
|
CODEX_MODEL=gpt-5.5
|
|
238
|
-
CLAUDE_MODEL=claude-opus-
|
|
243
|
+
CLAUDE_MODEL=claude-opus-5
|
|
244
|
+
CLAUDE_API_MAX_TOKENS=16384 # API only: adaptive thinking + visible output
|
|
239
245
|
MISTRAL_MODEL=mistral-large-3
|
|
240
246
|
CURSOR_MODEL=composer-2.5
|
|
241
247
|
KIMI_MODEL=kimi-code/k3
|
|
@@ -246,6 +252,11 @@ DEEPSEEK_MODEL=deepseek-v4-pro
|
|
|
246
252
|
MINIMAX_MODEL=MiniMax-M2.7
|
|
247
253
|
```
|
|
248
254
|
|
|
255
|
+
Anthropic counts adaptive thinking and visible response tokens against the same
|
|
256
|
+
`CLAUDE_API_MAX_TOKENS` limit. The default is 16,384; a response that reaches
|
|
257
|
+
that limit is rejected as truncated instead of entering synthesis as a complete
|
|
258
|
+
answer.
|
|
259
|
+
|
|
249
260
|
`GROK_MODEL` is passed explicitly to `grok -m`. The default transport is the
|
|
250
261
|
headless Grok Build CLI using a private `--prompt-file` inside an isolated,
|
|
251
262
|
tool-free strict sandbox. If the CLI is missing, cannot execute, or has no
|
package/scripts/config.sh
CHANGED
|
@@ -271,7 +271,8 @@ KIMI_CMD="${KIMI_CMD:-kimi}"
|
|
|
271
271
|
# CLAUDE CONFIGURATION - The Synthesizer (v2.2)
|
|
272
272
|
# =============================================================================
|
|
273
273
|
|
|
274
|
-
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-
|
|
274
|
+
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-5}"
|
|
275
|
+
CLAUDE_API_MAX_TOKENS="${CLAUDE_API_MAX_TOKENS:-16384}"
|
|
275
276
|
CLAUDE_TIMEOUT_SECONDS="${CLAUDE_TIMEOUT:-240}"
|
|
276
277
|
CLAUDE_CMD="${CLAUDE_CMD:-claude}"
|
|
277
278
|
|
|
@@ -581,7 +582,7 @@ get_model_for_tier() {
|
|
|
581
582
|
case "$tier" in
|
|
582
583
|
premium|max|best)
|
|
583
584
|
case "$consultant" in
|
|
584
|
-
claude) echo "claude-opus-
|
|
585
|
+
claude) echo "claude-opus-5" ;;
|
|
585
586
|
gemini) echo "Gemini 3.1 Pro (High)" ;;
|
|
586
587
|
codex) echo "gpt-5.5" ;;
|
|
587
588
|
mistral) echo "mistral-large-3" ;;
|
|
@@ -778,4 +779,4 @@ EOF
|
|
|
778
779
|
# VERSION
|
|
779
780
|
# =============================================================================
|
|
780
781
|
|
|
781
|
-
AI_CONSULTANTS_VERSION="3.
|
|
782
|
+
AI_CONSULTANTS_VERSION="3.2.0"
|
package/scripts/configure.sh
CHANGED
|
@@ -181,6 +181,25 @@ set_value() {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
AUTO_MARKER="# ai-consultants:auto"
|
|
184
|
+
DEFAULT_MARKER="# ai-consultants:default"
|
|
185
|
+
PIN_MARKER="# ai-consultants:pin"
|
|
186
|
+
|
|
187
|
+
has_value_marker() {
|
|
188
|
+
local file="$1" key="$2" marker="$3" line normalized
|
|
189
|
+
[[ -r "$file" ]] || return 1
|
|
190
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
191
|
+
line="${line%$'\r'}"
|
|
192
|
+
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
193
|
+
normalized="${line#"${line%%[![:space:]]*}"}"
|
|
194
|
+
if [[ "$normalized" =~ ^export[[:space:]]+ ]]; then
|
|
195
|
+
normalized="${normalized#export}"
|
|
196
|
+
normalized="${normalized#"${normalized%%[![:space:]]*}"}"
|
|
197
|
+
fi
|
|
198
|
+
[[ "$normalized" == "$key="* ]] || continue
|
|
199
|
+
[[ "$normalized" == *"$marker"* ]] && return 0
|
|
200
|
+
done < "$file"
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
184
203
|
|
|
185
204
|
is_auto_managed_value() {
|
|
186
205
|
local file="$1" key="$2" line normalized raw="" seen=false
|
|
@@ -239,13 +258,33 @@ set_auto_value() {
|
|
|
239
258
|
# Merge existing persistent values first, then current environment overrides.
|
|
240
259
|
while IFS= read -r key; do
|
|
241
260
|
if [[ -f "$OUTPUT_FILE" ]] && value=$(read_value "$OUTPUT_FILE" "$key"); then
|
|
242
|
-
|
|
261
|
+
if has_value_marker "$OUTPUT_FILE" "$key" "$DEFAULT_MARKER"; then
|
|
262
|
+
set_value "$key" "$value $DEFAULT_MARKER"
|
|
263
|
+
elif has_value_marker "$OUTPUT_FILE" "$key" "$PIN_MARKER"; then
|
|
264
|
+
set_value "$key" "$value $PIN_MARKER"
|
|
265
|
+
else
|
|
266
|
+
set_value "$key" "$value"
|
|
267
|
+
fi
|
|
243
268
|
fi
|
|
244
269
|
if [[ -n "${!key+x}" ]]; then
|
|
245
|
-
|
|
270
|
+
if [[ "$key" == *_MODEL ]]; then
|
|
271
|
+
set_value "$key" "${!key} $PIN_MARKER"
|
|
272
|
+
else
|
|
273
|
+
set_value "$key" "${!key}"
|
|
274
|
+
fi
|
|
246
275
|
fi
|
|
247
276
|
done < <(list_parameters)
|
|
248
277
|
|
|
278
|
+
# Before model defaults had provenance markers, `init` copied the then-current
|
|
279
|
+
# Claude default as an ordinary-looking value. Refresh that exact historical
|
|
280
|
+
# default when configure rewrites the file. A real legacy pin is preserved by
|
|
281
|
+
# `--set CLAUDE_MODEL=claude-opus-4-8`, which records the pin marker.
|
|
282
|
+
if [[ "$(read_value "$WORK_FILE" CLAUDE_MODEL 2>/dev/null || true)" == "claude-opus-4-8" ]] \
|
|
283
|
+
&& ! has_value_marker "$WORK_FILE" CLAUDE_MODEL "$PIN_MARKER"; then
|
|
284
|
+
set_value CLAUDE_MODEL "claude-opus-5 $DEFAULT_MARKER"
|
|
285
|
+
echo "Migrated managed Claude default: claude-opus-4-8 -> claude-opus-5" >&2
|
|
286
|
+
fi
|
|
287
|
+
|
|
249
288
|
configure_cli_only() {
|
|
250
289
|
local enable_key="$1" cmd_key="$2" cmd enabled=false
|
|
251
290
|
cmd=$(effective_input_value "$cmd_key")
|
|
@@ -327,7 +366,11 @@ prompt_value() {
|
|
|
327
366
|
else
|
|
328
367
|
read -r -p "$key [$current]: " reply
|
|
329
368
|
if [[ -n "$reply" ]]; then
|
|
330
|
-
|
|
369
|
+
if [[ "$key" == *_MODEL ]]; then
|
|
370
|
+
set_value "$key" "$reply $PIN_MARKER"
|
|
371
|
+
else
|
|
372
|
+
set_value "$key" "$reply"
|
|
373
|
+
fi
|
|
331
374
|
fi
|
|
332
375
|
fi
|
|
333
376
|
}
|
|
@@ -368,7 +411,11 @@ fi
|
|
|
368
411
|
|
|
369
412
|
# Explicit command-line overrides have final precedence.
|
|
370
413
|
for ((i=0; i<${#SET_KEYS[@]}; i++)); do
|
|
371
|
-
|
|
414
|
+
if [[ "${SET_KEYS[$i]}" == *_MODEL ]]; then
|
|
415
|
+
set_value "${SET_KEYS[$i]}" "${SET_VALUES[$i]} $PIN_MARKER"
|
|
416
|
+
else
|
|
417
|
+
set_value "${SET_KEYS[$i]}" "${SET_VALUES[$i]}"
|
|
418
|
+
fi
|
|
372
419
|
done
|
|
373
420
|
|
|
374
421
|
enabled_count=0
|
package/scripts/lib/api.sh
CHANGED
|
@@ -249,7 +249,7 @@ build_openai_request() {
|
|
|
249
249
|
build_anthropic_request() {
|
|
250
250
|
local prompt="$1"
|
|
251
251
|
local model="${2:-claude-sonnet-4-6}"
|
|
252
|
-
local max_tokens="${3:-
|
|
252
|
+
local max_tokens="${3:-16384}"
|
|
253
253
|
|
|
254
254
|
jq -n \
|
|
255
255
|
--arg model "$model" \
|
|
@@ -327,7 +327,11 @@ parse_anthropic_response() {
|
|
|
327
327
|
local response="$1"
|
|
328
328
|
|
|
329
329
|
local content
|
|
330
|
-
|
|
330
|
+
# Opus 5 may put a thinking block before the visible text block. Select
|
|
331
|
+
# every text block instead of assuming content[0] is user-visible output.
|
|
332
|
+
content=$(echo "$response" | jq -r \
|
|
333
|
+
'[.content[]? | select(.type == "text") | (.text // "")] | join("\n")' \
|
|
334
|
+
2>/dev/null)
|
|
331
335
|
|
|
332
336
|
if [[ -n "$content" && "$content" != "null" ]]; then
|
|
333
337
|
echo "$content"
|
package/scripts/lib/api_query.sh
CHANGED
|
@@ -94,7 +94,14 @@ run_api_mode_query() {
|
|
|
94
94
|
if [[ -n "$effort" ]]; then
|
|
95
95
|
log_warn "[$consultant_name] $effort_var is not supported on the 'anthropic' wire format and is ignored."
|
|
96
96
|
fi
|
|
97
|
-
|
|
97
|
+
local max_tokens_var api_max_tokens
|
|
98
|
+
max_tokens_var="$(to_upper "$consultant_name")_API_MAX_TOKENS"
|
|
99
|
+
api_max_tokens="${!max_tokens_var:-16384}"
|
|
100
|
+
if ! [[ "$api_max_tokens" =~ ^[1-9][0-9]*$ ]]; then
|
|
101
|
+
log_error "[$consultant_name] $max_tokens_var must be a positive integer (got: $api_max_tokens)"
|
|
102
|
+
return 1
|
|
103
|
+
fi
|
|
104
|
+
request_body=$(build_anthropic_request "$query" "$model" "$api_max_tokens")
|
|
98
105
|
auth_style="anthropic"
|
|
99
106
|
;;
|
|
100
107
|
qwen)
|
|
@@ -134,6 +141,16 @@ run_api_mode_query() {
|
|
|
134
141
|
local raw_response
|
|
135
142
|
raw_response=$(cat "$temp_response")
|
|
136
143
|
|
|
144
|
+
# Anthropic counts adaptive thinking and visible output against the same
|
|
145
|
+
# max_tokens budget. A max_tokens stop is therefore an incomplete answer,
|
|
146
|
+
# not a successful partial response suitable for synthesis.
|
|
147
|
+
if [[ "$api_format" == "anthropic" ]] \
|
|
148
|
+
&& [[ "$(jq -r '.stop_reason // empty' <<<"$raw_response" 2>/dev/null)" == "max_tokens" ]]; then
|
|
149
|
+
log_error "[$consultant_name] API response was truncated at ${api_max_tokens:-the configured} max tokens"
|
|
150
|
+
rm -f "$temp_response"
|
|
151
|
+
return 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
137
154
|
local parsed_content
|
|
138
155
|
case "$api_format" in
|
|
139
156
|
google_ai)
|
package/scripts/lib/common.sh
CHANGED
|
@@ -902,6 +902,7 @@ resolve_response_tokens() {
|
|
|
902
902
|
|
|
903
903
|
# Build metadata JSON for responses
|
|
904
904
|
# Usage: build_response_metadata <latency_ms> <model> [error_msg] [tokens] [source]
|
|
905
|
+
# [tokens_input] [tokens_output] [provider_cost_usd]
|
|
905
906
|
#
|
|
906
907
|
# tokens_used was hardcoded to 0 until v2.25, which made every session's cost
|
|
907
908
|
# report read $0.00 regardless of what was actually spent (calculate_session_cost
|
|
@@ -915,6 +916,7 @@ build_response_metadata() {
|
|
|
915
916
|
local source="${5:-unknown}"
|
|
916
917
|
local tokens_in="${6:-}"
|
|
917
918
|
local tokens_out="${7:-}"
|
|
919
|
+
local provider_cost="${8:-}"
|
|
918
920
|
|
|
919
921
|
jq -n \
|
|
920
922
|
--argjson latency "$latency" \
|
|
@@ -925,9 +927,11 @@ build_response_metadata() {
|
|
|
925
927
|
--arg source "$source" \
|
|
926
928
|
--arg t_in "$tokens_in" \
|
|
927
929
|
--arg t_out "$tokens_out" \
|
|
930
|
+
--arg provider_cost "$provider_cost" \
|
|
928
931
|
'{tokens_used: $tokens, tokens_source: $source, latency_ms: $latency, model_version: $model, timestamp: $timestamp}
|
|
929
932
|
+ (if $t_in != "" then {tokens_input: ($t_in | tonumber)} else {} end)
|
|
930
933
|
+ (if $t_out != "" then {tokens_output: ($t_out | tonumber)} else {} end)
|
|
934
|
+
+ (if $provider_cost != "" then {provider_cost_usd: ($provider_cost | tonumber)} else {} end)
|
|
931
935
|
+ (if $error != "" then {error: $error} else {} end)'
|
|
932
936
|
}
|
|
933
937
|
|
|
@@ -943,15 +947,14 @@ build_structured_response() {
|
|
|
943
947
|
local tokens_source="${7:-unknown}"
|
|
944
948
|
local tokens_in="${8:-}"
|
|
945
949
|
local tokens_out="${9:-}"
|
|
946
|
-
local
|
|
947
|
-
local tokens_out="${9:-}"
|
|
950
|
+
local provider_cost="${10:-}"
|
|
948
951
|
|
|
949
952
|
jq -n \
|
|
950
953
|
--arg consultant "$consultant" \
|
|
951
954
|
--arg model "$model" \
|
|
952
955
|
--arg persona "$persona" \
|
|
953
956
|
--argjson inner "$inner_json" \
|
|
954
|
-
--argjson metadata "$(build_response_metadata "$latency" "$model" "" "$tokens" "$tokens_source" "$tokens_in" "$tokens_out")" \
|
|
957
|
+
--argjson metadata "$(build_response_metadata "$latency" "$model" "" "$tokens" "$tokens_source" "$tokens_in" "$tokens_out" "$provider_cost")" \
|
|
955
958
|
'{consultant: $consultant, model: $model, persona: $persona, response: $inner.response, confidence: $inner.confidence, metadata: $metadata}'
|
|
956
959
|
}
|
|
957
960
|
|
|
@@ -967,13 +970,14 @@ build_fallback_response() {
|
|
|
967
970
|
local tokens_source="${7:-unknown}"
|
|
968
971
|
local tokens_in="${8:-}"
|
|
969
972
|
local tokens_out="${9:-}"
|
|
973
|
+
local provider_cost="${10:-}"
|
|
970
974
|
|
|
971
975
|
jq -n \
|
|
972
976
|
--arg consultant "$consultant" \
|
|
973
977
|
--arg model "$model" \
|
|
974
978
|
--arg persona "$persona" \
|
|
975
979
|
--arg response "$response_text" \
|
|
976
|
-
--argjson metadata "$(build_response_metadata "$latency" "$model" "" "$tokens" "$tokens_source" "$tokens_in" "$tokens_out")" \
|
|
980
|
+
--argjson metadata "$(build_response_metadata "$latency" "$model" "" "$tokens" "$tokens_source" "$tokens_in" "$tokens_out" "$provider_cost")" \
|
|
977
981
|
'{consultant: $consultant, model: $model, persona: $persona,
|
|
978
982
|
response: {summary: "Unstructured response - see detailed", detailed: $response, approach: "unknown", pros: [], cons: [], caveats: ["Unstructured output from consultant"]},
|
|
979
983
|
confidence: {score: 5, reasoning: "Confidence not provided by consultant", uncertainty_factors: ["Non-standard response format"]},
|
package/scripts/lib/costs.sh
CHANGED
|
@@ -306,11 +306,8 @@ _billable_response_files() {
|
|
|
306
306
|
# Calculate total session cost from responses
|
|
307
307
|
# Usage: calculate_session_cost <responses_dir>
|
|
308
308
|
#
|
|
309
|
-
# Prefers
|
|
310
|
-
# (API mode)
|
|
311
|
-
# split to record: consultations are large-context/short-reply, so applying it
|
|
312
|
-
# to a measured total materially overstates cost when output rates exceed
|
|
313
|
-
# input rates.
|
|
309
|
+
# Prefers an exact provider cost when recorded (Claude CLI), then the provider's
|
|
310
|
+
# prompt/completion split (API mode), and only then the legacy 60/40 guess.
|
|
314
311
|
calculate_session_cost() {
|
|
315
312
|
local responses_dir="$1"
|
|
316
313
|
local total_cost=0
|
|
@@ -318,6 +315,13 @@ calculate_session_cost() {
|
|
|
318
315
|
|
|
319
316
|
while IFS= read -r f; do
|
|
320
317
|
[[ -n "$f" ]] || continue
|
|
318
|
+
local provider_cost
|
|
319
|
+
provider_cost=$(jq -r '.metadata.provider_cost_usd // empty' "$f" 2>/dev/null)
|
|
320
|
+
if [[ "$provider_cost" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
|
|
321
|
+
total_cost=$(echo "scale=6; $total_cost + $provider_cost" | bc)
|
|
322
|
+
continue
|
|
323
|
+
fi
|
|
324
|
+
|
|
321
325
|
local model input_tokens output_tokens
|
|
322
326
|
model=$(jq -r '.model // "default"' "$f" 2>/dev/null)
|
|
323
327
|
input_tokens=$(jq -r '.metadata.tokens_input // empty' "$f" 2>/dev/null)
|
|
@@ -338,6 +342,11 @@ calculate_session_cost() {
|
|
|
338
342
|
total_cost=$(echo "scale=6; $total_cost + $cost" | bc)
|
|
339
343
|
done < <(_billable_response_files "$responses_dir")
|
|
340
344
|
|
|
345
|
+
# Provider-reported costs may carry fewer decimal places than locally
|
|
346
|
+
# estimated values. Normalize the public result to the existing 6-place
|
|
347
|
+
# contract without changing its numeric value.
|
|
348
|
+
total_cost=$(echo "scale=6; $total_cost / 1" | bc)
|
|
349
|
+
|
|
341
350
|
# bc drops the leading zero on sub-1 values (".115000"); restore it as
|
|
342
351
|
# estimate_query_cost does, so callers can compare numerically.
|
|
343
352
|
[[ "$total_cost" == .* ]] && total_cost="0$total_cost"
|
|
@@ -351,8 +360,9 @@ calculate_session_cost() {
|
|
|
351
360
|
#
|
|
352
361
|
# Two things can make the number less than it looks:
|
|
353
362
|
# - credit-billed models contribute 0 because they have no per-token price;
|
|
354
|
-
# - CLI-mode consultants
|
|
355
|
-
#
|
|
363
|
+
# - CLI-mode consultants without provider usage have a 4-chars-per-token
|
|
364
|
+
# approximation (metadata.tokens_source = "estimated"). Claude CLI is the
|
|
365
|
+
# exception: its JSON envelope supplies measured usage and exact cost.
|
|
356
366
|
# Both are stated rather than folded silently into a confident-looking total.
|
|
357
367
|
#
|
|
358
368
|
# Rescans the directory rather than reading state left by
|
package/scripts/query_claude.sh
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
# Usage: ./query_claude.sh "question" [context_file] [output_file]
|
|
5
5
|
#
|
|
6
6
|
# Environment variables:
|
|
7
|
-
# CLAUDE_MODEL - Model to use (default: claude-opus-
|
|
7
|
+
# CLAUDE_MODEL - Model to use (default: claude-opus-5)
|
|
8
8
|
# CLAUDE_TIMEOUT - Timeout in seconds (default: 240)
|
|
9
9
|
# CLAUDE_USE_API - Use API mode instead of CLI (default: false)
|
|
10
|
+
# CLAUDE_API_MAX_TOKENS - API thinking + visible-output budget (default: 16384)
|
|
10
11
|
# ANTHROPIC_API_KEY - API key for API mode
|
|
11
12
|
# ENABLE_PERSONA - Enable "The Synthesizer" persona (default: true)
|
|
12
13
|
|
|
@@ -25,7 +26,7 @@ OUTPUT_FILE="${3:-/tmp/claude_response.json}"
|
|
|
25
26
|
ENABLE_PERSONA="${ENABLE_PERSONA:-true}"
|
|
26
27
|
CONSULTANT_NAME="Claude"
|
|
27
28
|
CLAUDE_CMD="${CLAUDE_CMD:-claude}"
|
|
28
|
-
MODEL_USED="${CLAUDE_MODEL:-claude-opus-
|
|
29
|
+
MODEL_USED="${CLAUDE_MODEL:-claude-opus-5}"
|
|
29
30
|
|
|
30
31
|
# --- Build query ---
|
|
31
32
|
FULL_QUERY=$(build_full_query "$QUERY" "$CONTEXT_FILE")
|
|
@@ -69,12 +70,13 @@ else
|
|
|
69
70
|
log_api_mode_status "claude"
|
|
70
71
|
check_command "$CLAUDE_CMD" "Claude CLI" "Visit https://docs.anthropic.com/en/docs/claude-code" || exit 1
|
|
71
72
|
|
|
72
|
-
#
|
|
73
|
+
# JSON output exposes provider-measured usage and cost. In particular,
|
|
74
|
+
# output_tokens includes adaptive thinking that is absent from .result.
|
|
73
75
|
echo "$FULL_QUERY" | run_query \
|
|
74
76
|
"Claude" \
|
|
75
77
|
"$TEMP_OUTPUT" \
|
|
76
78
|
"$CLAUDE_TIMEOUT_SECONDS" \
|
|
77
|
-
"$CLAUDE_CMD" --print --model "$MODEL_USED"
|
|
79
|
+
"$CLAUDE_CMD" --print --model "$MODEL_USED" --output-format json
|
|
78
80
|
|
|
79
81
|
exit_code=$?
|
|
80
82
|
fi
|
|
@@ -88,16 +90,45 @@ PERSONA_NAME=$(get_persona_name "$CONSULTANT_NAME")
|
|
|
88
90
|
|
|
89
91
|
# --- Post-processing: wrap in full schema using shared helpers ---
|
|
90
92
|
if [[ $exit_code -eq 0 && -f "$TEMP_OUTPUT" && -s "$TEMP_OUTPUT" ]]; then
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
PROVIDER_COST=""
|
|
94
|
+
if ! is_api_mode "claude"; then
|
|
95
|
+
CLI_ENVELOPE=$(cat "$TEMP_OUTPUT")
|
|
96
|
+
if ! echo "$CLI_ENVELOPE" | jq -e \
|
|
97
|
+
'.type == "result" and (.result | type == "string")' >/dev/null 2>&1; then
|
|
98
|
+
rm -f "$TEMP_OUTPUT"
|
|
99
|
+
build_error_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" \
|
|
100
|
+
"Claude CLI returned an invalid JSON result envelope" "$LATENCY_MS" > "$OUTPUT_FILE"
|
|
101
|
+
cat "$OUTPUT_FILE"
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
RAW_RESPONSE=$(echo "$CLI_ENVELOPE" | jq -r '.result')
|
|
105
|
+
_TOK_IN=$(echo "$CLI_ENVELOPE" | jq -r \
|
|
106
|
+
'([.modelUsage[]?
|
|
107
|
+
| (.inputTokens // 0)
|
|
108
|
+
+ (.cacheCreationInputTokens // 0)
|
|
109
|
+
+ (.cacheReadInputTokens // 0)] | add)
|
|
110
|
+
// ((.usage.input_tokens // 0)
|
|
111
|
+
+ (.usage.cache_creation_input_tokens // 0)
|
|
112
|
+
+ (.usage.cache_read_input_tokens // 0))')
|
|
113
|
+
_TOK_OUT=$(echo "$CLI_ENVELOPE" | jq -r \
|
|
114
|
+
'([.modelUsage[]? | (.outputTokens // 0)] | add)
|
|
115
|
+
// (.usage.output_tokens // 0)')
|
|
116
|
+
_TOK=$((_TOK_IN + _TOK_OUT))
|
|
117
|
+
_TOK_SRC="measured"
|
|
118
|
+
PROVIDER_COST=$(echo "$CLI_ENVELOPE" | jq -r \
|
|
119
|
+
'[.modelUsage[]?.costUSD | numbers] | add // empty')
|
|
120
|
+
else
|
|
121
|
+
RAW_RESPONSE=$(cat "$TEMP_OUTPUT")
|
|
122
|
+
read -r _TOK _TOK_SRC _TOK_IN _TOK_OUT <<< "$(resolve_response_tokens "$FULL_QUERY" "$RAW_RESPONSE")"
|
|
123
|
+
fi
|
|
93
124
|
clear_api_token_split
|
|
94
125
|
rm -f "$TEMP_OUTPUT"
|
|
95
126
|
|
|
96
127
|
# Try to parse as structured JSON
|
|
97
128
|
if echo "$RAW_RESPONSE" | jq -e '.response.summary' > /dev/null 2>&1; then
|
|
98
|
-
build_structured_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" "$RAW_RESPONSE" "$LATENCY_MS" "$_TOK" "$_TOK_SRC" "$_TOK_IN" "$_TOK_OUT" > "$OUTPUT_FILE"
|
|
129
|
+
build_structured_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" "$RAW_RESPONSE" "$LATENCY_MS" "$_TOK" "$_TOK_SRC" "$_TOK_IN" "$_TOK_OUT" "$PROVIDER_COST" > "$OUTPUT_FILE"
|
|
99
130
|
else
|
|
100
|
-
build_fallback_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" "$RAW_RESPONSE" "$LATENCY_MS" "$_TOK" "$_TOK_SRC" "$_TOK_IN" "$_TOK_OUT" > "$OUTPUT_FILE"
|
|
131
|
+
build_fallback_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" "$RAW_RESPONSE" "$LATENCY_MS" "$_TOK" "$_TOK_SRC" "$_TOK_IN" "$_TOK_OUT" "$PROVIDER_COST" > "$OUTPUT_FILE"
|
|
101
132
|
fi
|
|
102
133
|
else
|
|
103
134
|
rm -f "$TEMP_OUTPUT"
|