ai-consultants 2.24.0 → 2.25.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 +17 -1
- package/CLAUDE.md +22 -1
- package/README.md +2 -2
- package/SKILL.md +2 -2
- package/docs/COST_RATES.md +1 -1
- package/docs/JSON_SCHEMA.md +33 -1
- package/docs/RECIPES.md +66 -0
- package/docs/cost_rates.json +9 -1
- package/docs/releases/v2.25.0.md +101 -0
- package/package.json +1 -1
- package/scripts/config.sh +1 -1
- package/scripts/consult_all.sh +6 -1
- package/scripts/lib/api.sh +90 -2
- package/scripts/lib/api_query.sh +48 -7
- package/scripts/lib/common.sh +168 -11
- package/scripts/lib/costs.sh +131 -12
- package/scripts/lib/schema.json +14 -1
- package/scripts/query_claude.sh +19 -10
- package/scripts/query_codex.sh +17 -10
- package/scripts/query_cursor.sh +4 -1
- package/scripts/query_gemini.sh +16 -9
- package/scripts/query_kimi.sh +4 -1
- package/scripts/query_minimax.sh +4 -1
- package/scripts/query_mistral.sh +19 -10
- package/scripts/query_qwen3.sh +38 -13
- package/scripts/roster_calibrate.sh +15 -0
package/.env.example
CHANGED
|
@@ -107,6 +107,9 @@ ENABLE_DEEPSEEK=false
|
|
|
107
107
|
# CLAUDE_API_URL=https://api.anthropic.com/v1/messages
|
|
108
108
|
# MISTRAL_API_URL=https://api.mistral.ai/v1/chat/completions
|
|
109
109
|
# QWEN3_API_URL=https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
|
|
110
|
+
# Token Plan alternative (OpenAI-compatible, needs QWEN3_FORMAT=openai and a
|
|
111
|
+
# Token Plan key in QWEN3_API_KEY; pass the FULL path, it is used verbatim):
|
|
112
|
+
# https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions
|
|
110
113
|
|
|
111
114
|
# =============================================================================
|
|
112
115
|
# MODEL CONFIGURATION (June 2026 premium defaults)
|
|
@@ -148,6 +151,14 @@ CLAUDE_CMD=claude
|
|
|
148
151
|
QWEN3_MODEL=qwen3.7-max
|
|
149
152
|
QWEN3_TIMEOUT=180
|
|
150
153
|
QWEN3_CMD=qwen
|
|
154
|
+
# Reasoning effort. API mode ONLY - the qwen CLI has no effort flag, so in CLI
|
|
155
|
+
# mode this is ignored (with a warning); set model.reasoningEffort in
|
|
156
|
+
# ~/.qwen/settings.json instead. Accepted: none|minimal|low|medium|high|xhigh|max
|
|
157
|
+
# (the provider's own enum). The valid subset depends on the model:
|
|
158
|
+
# qwen3.8-max-preview takes all of them EXCEPT 'none' - thinking cannot be
|
|
159
|
+
# disabled on it - and defaults to xhigh. An unsupported combination is
|
|
160
|
+
# rejected by the provider with a 400, not silently ignored.
|
|
161
|
+
# QWEN3_REASONING_EFFORT=
|
|
151
162
|
|
|
152
163
|
# =============================================================================
|
|
153
164
|
# API-BASED CONSULTANT CONFIGURATION
|
|
@@ -174,7 +185,12 @@ MINIMAX_MODEL=MiniMax-M2.7
|
|
|
174
185
|
MINIMAX_TIMEOUT=180
|
|
175
186
|
MINIMAX_API_URL=https://api.minimax.io/v1/chat/completions
|
|
176
187
|
|
|
177
|
-
#
|
|
188
|
+
# Wire format for a consultant's API mode. Honored since v2.25 (previously
|
|
189
|
+
# declared but never read). Values: google_ai|anthropic|qwen|openai; an
|
|
190
|
+
# unrecognized value falls back to the consultant's default with a warning.
|
|
191
|
+
# Change this only to reach an endpoint that speaks a different protocol than
|
|
192
|
+
# the provider's own - e.g. QWEN3_FORMAT=openai for Qwen Cloud Token Plan,
|
|
193
|
+
# which is OpenAI-compatible while DashScope is not. See docs/RECIPES.md.
|
|
178
194
|
QWEN3_FORMAT=qwen
|
|
179
195
|
GLM_FORMAT=openai
|
|
180
196
|
GROK_FORMAT=openai
|
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.25.0
|
|
10
10
|
|
|
11
11
|
## Distribution
|
|
12
12
|
|
|
@@ -801,6 +801,27 @@ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/s
|
|
|
801
801
|
|
|
802
802
|
## Changelog
|
|
803
803
|
|
|
804
|
+
### v2.25.0
|
|
805
|
+
- **`tokens_used` was hardcoded to 0, so the cost report priced pipeline metadata and nothing else.** `build_response_metadata` (`lib/common.sh`) emitted a literal `tokens_used: 0` and was the only writer of that field in the repo; `calculate_session_cost` (`lib/costs.sh:248`) multiplies it by the model rate. Structurally zero for all 11 consultants, both transports, since the field existed. **Do not describe this as "every session reported $0.00"** — I did, in three changelogs, and it is wrong: the pipeline files caught by the same unfiltered glob have no `tokens_used` key at all, so they took the `// 1000` fallback at the default rate (~$0.009 each). Measured against HEAD on a realistic three-consultant directory, v2.24 reports **$0.0270**, entirely phantom. The reported number tracked how many pipeline stages ran. Worse in API mode: `run_api_mode_query` (`lib/api_query.sh:154`) called `extract_token_usage`, which computes the right number (verified: extracts 85 from a live Token Plan body), `log_debug`'d it, and dropped it on the floor.
|
|
806
|
+
- **Four paths write response metadata**, which is why the fix is spread out: `process_consultant_response` (codex/cursor/gemini/kimi/minimax/qwen3), direct builder calls (claude/mistral), `run_api_consultant` (glm/deepseek/grok), and the error path. All converge on `build_response_metadata`, so that is where the new `tokens`/`tokens_source` parameters land; the builders thread them through and default to `0`/`unknown` so pre-existing 5-arg calls still work.
|
|
807
|
+
- **The measured split travels in a module variable, `_API_TOKEN_SPLIT`.** `run_api_mode_query` publishes it via `set_api_token_split`; `resolve_response_tokens` reads it; the CALLER clears it via `clear_api_token_split`. The asymmetry is the whole subtlety: `resolve_response_tokens` runs inside `$(...)`, so it can *read* the variable (subshells inherit) but an assignment there dies with the subshell — it cannot clear it. Its callers are plain statements and can. **An earlier cut used a temp-file sidecar justified by the claim that some callers of `run_api_mode_query` run in a command substitution. That claim was false** — all six call sites (`query_{claude,codex,gemini,mistral,qwen3}.sh` and `run_api_consultant`) are plain statements — and it bought a cross-function file lifecycle with five cleanup sites for nothing. Caught by `/code-review max`, which also noted the false comment had been promoted to binding policy in this very file. The real subshell constraint applies to `calculate_session_cost` / `format_cost_caveats`, which ARE always `$(...)` and therefore take their input as arguments.
|
|
808
|
+
- **The provider's prompt/completion SPLIT is kept, not just the total.** `extract_token_split` (api.sh) preserves it and `metadata.tokens_input`/`tokens_output` record it; `calculate_session_cost` prefers them over the 60/40 fallback. Collapsing to a total and re-splitting it 60/40 overstated API-mode cost ~2.7x on a realistic 20000-prompt/500-completion gpt-5.5 call ($0.3075 vs $0.1150) — while still labeling it `measured`, the one value that is supposed to mean "the provider's own figure". The 60/40 guess survives only for CLI mode, which has no split to record.
|
|
809
|
+
- **CLI mode estimates, and says so.** No CLI exposes token counts, and CLI-first is mandatory since v2.21, so leaving CLI at 0 would have fixed almost nothing. `resolve_response_tokens` falls back to `estimate_tokens` (the pre-existing 4-chars-per-token helper at `common.sh:864`, previously unused for this) over prompt + reply. The six `process_consultant_response` call sites pass `"${#FULL_QUERY}"`; claude/mistral/`run_api_consultant` resolve inline. `metadata.tokens_source` records `measured|estimated|unknown` so a consumer can tell the difference — added to both `lib/schema.json` and `docs/JSON_SCHEMA.md`.
|
|
810
|
+
- **Budget impact is narrower than it first looks.** `enforce_budget` is called four times in `consult_all.sh`. The first two (`:345`, `:451`) pass literal `0` as current cost and project from `ESTIMATED_COST`, derived from `CONTEXT_SIZE` — those always worked. Only `:755` and `:862` pass `CURRENT_COST` from `calculate_session_cost`, and that was the zero. Do not describe this as "budget enforcement never triggered"; it did, off estimates.
|
|
811
|
+
- **Five `*_FORMAT` flags were dead since v2.6.** `QWEN3_`/`GLM_`/`GROK_`/`DEEPSEEK_`/`MINIMAX_FORMAT` are declared in `config.sh:174,185,195,205,216` and documented in `.env.example:178-182`, but `get_api_format()` (`common.sh:396`) hardcoded the mapping and `api_query.sh:50` is its only consumer — ten occurrences, all definitions, zero reads. Same shape as the `ENABLE_REFLECTION` removal in v2.23.0, but the opposite call: that capability was covered elsewhere, this one is not — there is no other route to a non-DashScope Qwen endpoint, so deleting the flag would have forced a Qwen-only hardcode. Now honored, with validation against `google_ai|anthropic|qwen|openai` and fallback-with-warning on anything else.
|
|
812
|
+
- **Note the deliberate asymmetry**: a bad `*_FORMAT` falls back to the default; a bad `*_REASONING_EFFORT` fails. Format has a correct per-consultant default to fall back to. Effort does not — silently substituting the model's default when the user asked for `xhigh` *is* the silent-no-op bug the knob exists to avoid.
|
|
813
|
+
- **The effort enum came from the API, not the docs, and the docs were wrong.** Every public write-up on `qwen3.8-max-preview` reported `low|high|xhigh`. A live 400 reports `'reasoning_effort' must be one of: 'none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'`. The first implementation allowed five values and would have rejected `minimal`, which the model accepts. The per-model subset is intentionally NOT enforced in shell — `none` is rejected by this model at a second layer (`The value of the enable_thinking parameter is restricted to True`), which is a model fact that belongs to the provider, not to us. Hardcoding per-model facts is what produced the stale `MODEL_USED` bugs also fixed here.
|
|
814
|
+
- **Qwen 3.8 is opt-in and stays that way.** It needs a Token Plan subscription (`https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1`, its own key, credit billing) and is not on DashScope, so swapping `config.sh:668` would break the Qwen consultant for every user without one. `test_suite.sh` now asserts the negative explicitly (`premium != qwen3.8-max-preview`) so the contract is self-documenting. `references/affinity.json` is untouched **by construction**: affinity and capability axes are keyed on the consultant name, never the model id, so changing `QWEN3_MODEL` implies no affinity change and `test_routing_parity.sh` needed no edit.
|
|
815
|
+
- **No invented cost rate.** `qwen3.8-max-preview` is credit-billed with no published per-token price, so it is catalogued at 0/0 plus a new `unpriced_models` list. Doing nothing was NOT neutral: `calculate_session_cost` never calls `resolve_model_for_cost`, so an absent model falls to the `*)` arm of `get_input_cost_per_1k` (`costs.sh:163`) at 0.005/0.015 — ~4x the real qwen3.7-max input rate, reported confidently. The same fallback sits in `roster_calibrate.sh:34-35`, so a measured cost axis would have been corrupted by a model that is not billed per token at all. Run `run_calibration.sh` only after this entry exists.
|
|
816
|
+
- **Verified live against Token Plan**, not just fixtures: endpoint 200, structured response through the real adapter (confidence 9/10, persona applied — not the confidence-5 stub the Gemini fence bug produced in v2.15.0), `622 measured` tokens in API mode, `311 estimated` in CLI mode via Codex, and a full `consult_all.sh` run reporting `$0.0550 [token counts estimated for 3 of 3]` where it would previously have said `0¢`.
|
|
817
|
+
- **Making `tokens_used` real turned five latent mis-billings into money, all found by `/code-review max` (55 agents, 52 verified findings → 15 defects).** Every one was harmless while the field was hardcoded 0. `calculate_session_cost` globbed `*.json` unfiltered, so `voting.json`/`orchestration.json`/`synthesis.json` were each priced at the `// 1000` fallback times the default rate (measured 2.8x inflation); a cache hit replayed the original response's metadata and billed at full price ($0.52 for zero API calls); debate rounds live in `round_N/` subdirectories the non-recursive glob never saw; and `<consultant>_escalated.json` was left beside the file it had just been copied over, counting one query twice. New `_billable_response_files` is the single gate for all four — **any future loop over the responses dir should use it**, not a bare glob. `format_cost_caveats` additionally counted `unknown` (i.e. failed) responses in the "estimated for N of M" denominator, which made failures read as provider-measured.
|
|
818
|
+
- **The reasoning-effort knob was a silent no-op on the exact path the docs steer users to.** `${AGENT}_REASONING_EFFORT` was resolved inside the `openai` arm of the format switch, but `config.sh:174` defaults `QWEN3_FORMAT=qwen` — so `QWEN3_USE_API=true` + `QWEN3_REASONING_EFFORT=high` against DashScope built a body with no effort field, emitted no warning, and never validated the value. Resolution is now hoisted **above** the switch so every wire format sees it, and the three formats that cannot carry it (`qwen`, `google_ai`, `anthropic`) say so. Related: `validate_reasoning_effort`'s `return 1` propagated to a bare `run_api_mode_query` call under `set -euo pipefail`, killing the query script before `exit_code=$?` — no error envelope, a 0-byte output file, and the consultant silently vanishing from the panel instead of being reported as failed. All five API-capable query scripts now use the explicit `if ! …; then` guard `run_query` already used; this also fixes the same pre-existing hole for network failures.
|
|
819
|
+
- **Cataloguing the credit-billed model at 0/0 fixed the estimator and broke the calibrator.** `roster_calibrate.sh` falls back to `FALLBACK_IN/OUT` only when the catalog lookup *misses*; with a 0/0 entry the lookup now succeeds, so every qwen3.8-max-preview response cost 0.00000000 and the "cheapest = 10" rank-normalizer scored Qwen3 the cheapest consultant on the panel — which `--write` would have persisted into `affinity.json`, preferentially routing work to a model whose real consumption is invisible there. It now sources `costs.sh` and skips unpriced models from the cost axis: no data beats wrong data.
|
|
820
|
+
- **Applying the review fixes introduced four more bugs, every one caught by a test rather than by reading.** Worth recording because they are all the same shape — a change that *looks* applied but is not: (1) the `roster_calibrate.sh` guard called `is_unpriced_model` in a script that did not source `costs.sh`, so it would have been a silent no-op; (2) the shared CLI effort warning fired in API mode too, where the setting is honored, until it was made self-guarding; (3) `warn_effort_ignored_in_cli` used `is_api_mode "$agent" && return 0` — an &&-list that short-circuits returns non-zero as a statement and kills the caller under `set -e`, **the exact v2.22.0 `prompt_value` bug re-created**; and (4) `build_fallback_response` used `$tokens_in` without declaring the local, so under `set -u` **every unstructured reply would have aborted for all 11 consultants**. Only (4) was caught by an existing test — `test_query_kimi.sh`, whose stub happens to return an unstructured envelope — which means the fallback path had no direct coverage at all. `test_response_tokens` now exercises all three builders at both the legacy and the full arity under `set -u`, plus the `set -e` safety of the warning helper.
|
|
821
|
+
- **`${#FULL_QUERY}` is characters, `estimate_tokens` counts bytes.** The estimate summed the two, under-counting multibyte input roughly threefold (`日本語のテスト` is 7 chars, 21 bytes). `resolve_response_tokens` now takes the prompt TEXT and runs both halves through `estimate_tokens`, so the units match.
|
|
822
|
+
- **Three suites were not hermetic against `LOG_LEVEL`, and it read as a flake.** One `npm test` run reported `test_api_transport.sh` failed and could not be reproduced. It is not flaky: `_log` filters by `LOG_LEVEL`, so `log_warn` is silent at `ERROR`, and any assertion matching on warning output fails for that environment and passes everywhere else — deterministic per-environment, exactly the v2.23.0 release-gate shape. Found by sweeping every suite at DEBUG/INFO/WARN/ERROR rather than by re-running and hoping. Two were pre-existing: `test_context_optimization.sh` (3 assertions, **two of them the v2.17.2 secret-exfiltration guards** — a security regression test that depended on the caller's verbosity) and `test_update_clis.sh` (2 assertions). All three now `export LOG_LEVEL=INFO` before sourcing `config.sh`, which honors an ambient value. **If you add an assertion that matches on log output, pin the level in the suite.** Note the earlier "all assertions passed" reading was wrong — it came from a `grep -A40` truncated before the summary line, not from the actual output.
|
|
823
|
+
- **`npm test` = 22 suites.** New `test_api_transport.sh` (41 assertions) exists mainly as a back-compat gate: `get_api_format` for all 11 consultants and a byte-identical assertion on `build_openai_request`, which six consultants share. That assertion was written and confirmed green against the *unmodified* function before either was touched — the md5 of the default body is unchanged end to end.
|
|
824
|
+
|
|
804
825
|
### v2.24.0
|
|
805
826
|
- **Stale slash commands are finally removed on install/update, on both entry points.** `scripts/install.sh` and `bin/ai-consultants install` only ever `cp`'d `.claude/commands/*.md` into `~/.claude/commands`, never pruning — so a command deleted from the repo lived on the user's machine indefinitely. Measured on a real installation: **14 `ai-consultants:*.md` installed, 4 of which this repo still ships.** The other ten were dropped by `9ae73e3` (v2.10.0, "command consolidation") and had been dead for 13 releases. Not inert — they stay invocable, and `config-features.md` tells the user to set `ENABLE_REFLECTION`, removed in v2.23.0 and now rejected by `configure --set` with a non-zero exit. New `prune_removed_commands()` in `install.sh` plus an inline equivalent in `bin/ai-consultants`; both scoped to the `ai-consultants:*.md` namespace. **Known and accepted bound**: within that namespace it also removes a user-authored command, because nothing distinguishes it from one of ours deleted upstream. Documented in `CHANGELOG.md` rather than worked around.
|
|
806
827
|
- **`bin/ai-consultants install` was initially missed** — the first cut of the fix landed only in `install.sh`, leaving npx users (the path the shipped `bin` help and `docs/releases/v2.19.2.md` advertise) with exactly the stale commands the fix targeted. Caught by the `/code-review max` pass, not by tests.
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# AI Consultants v2.
|
|
1
|
+
# AI Consultants v2.25.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)
|
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.25.0
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# AI Consultants v2.
|
|
11
|
+
# AI Consultants v2.25.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
package/docs/JSON_SCHEMA.md
CHANGED
|
@@ -32,6 +32,9 @@ The schema is defined in `scripts/lib/schema.json` following JSON Schema Draft-0
|
|
|
32
32
|
"debate": {...},
|
|
33
33
|
"metadata": {
|
|
34
34
|
"tokens_used": 1500,
|
|
35
|
+
"tokens_source": "measured",
|
|
36
|
+
"tokens_input": 1200,
|
|
37
|
+
"tokens_output": 300,
|
|
35
38
|
"latency_ms": 2345,
|
|
36
39
|
"model_version": "gemini-3.1-pro-preview",
|
|
37
40
|
"timestamp": "2024-01-14T12:34:56Z"
|
|
@@ -188,6 +191,9 @@ Present only if Multi-Agent Debate is enabled (round >= 2):
|
|
|
188
191
|
{
|
|
189
192
|
"metadata": {
|
|
190
193
|
"tokens_used": 1500,
|
|
194
|
+
"tokens_source": "measured",
|
|
195
|
+
"tokens_input": 1200,
|
|
196
|
+
"tokens_output": 300,
|
|
191
197
|
"latency_ms": 2345,
|
|
192
198
|
"model_version": "gemini-3.1-pro-preview",
|
|
193
199
|
"timestamp": "2024-01-14T12:34:56Z"
|
|
@@ -197,7 +203,10 @@ Present only if Multi-Agent Debate is enabled (round >= 2):
|
|
|
197
203
|
|
|
198
204
|
| Field | Type | Description |
|
|
199
205
|
|-------|------|-------------|
|
|
200
|
-
| `tokens_used` | integer | Tokens consumed
|
|
206
|
+
| `tokens_used` | integer | Tokens consumed. Provider-reported in API mode; locally approximated in CLI mode |
|
|
207
|
+
| `tokens_source` | string | `measured` \| `estimated` \| `unknown` — how `tokens_used` was obtained |
|
|
208
|
+
| `tokens_input` | integer | Prompt tokens, when the provider reported them (API mode only) |
|
|
209
|
+
| `tokens_output` | integer | Completion tokens, when the provider reported them (API mode only) |
|
|
201
210
|
| `latency_ms` | integer | Response time in ms |
|
|
202
211
|
| `model_version` | string | Exact model version |
|
|
203
212
|
| `timestamp` | string | ISO 8601 timestamp |
|
|
@@ -225,6 +234,28 @@ Present only if Multi-Agent Debate is enabled (round >= 2):
|
|
|
225
234
|
"minor" | "moderate" | "major"
|
|
226
235
|
```
|
|
227
236
|
|
|
237
|
+
### metadata.tokens_source
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
"measured" | "estimated" | "unknown"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- `measured` — the provider's own usage figures, available in API mode.
|
|
244
|
+
- `estimated` — a local 4-chars-per-token approximation over prompt + reply.
|
|
245
|
+
CLI-backed consultants report no token counts, so this is what they get; it
|
|
246
|
+
is the majority case, since CLI is the default transport.
|
|
247
|
+
- `unknown` — not recorded (error responses, and callers on the pre-v2.25.0
|
|
248
|
+
metadata signature).
|
|
249
|
+
|
|
250
|
+
When `tokens_input`/`tokens_output` are present, price on those rather than
|
|
251
|
+
splitting `tokens_used`: output rates run several times input rates and
|
|
252
|
+
consultations are large-context/short-reply, so a fixed split overstates cost
|
|
253
|
+
substantially.
|
|
254
|
+
|
|
255
|
+
Consumers that add up cost should read this field: a total built partly on
|
|
256
|
+
estimates is not a measurement. `consult_all.sh` discloses the split on its
|
|
257
|
+
session-cost line for that reason.
|
|
258
|
+
|
|
228
259
|
## Confidence Score Guidelines
|
|
229
260
|
|
|
230
261
|
| Score | Meaning |
|
|
@@ -297,6 +328,7 @@ jq 'has("consultant") and has("response") and has("confidence")' output.json
|
|
|
297
328
|
},
|
|
298
329
|
"metadata": {
|
|
299
330
|
"tokens_used": 1250,
|
|
331
|
+
"tokens_source": "estimated",
|
|
300
332
|
"latency_ms": 1850,
|
|
301
333
|
"model_version": "gemini-3.1-pro-preview",
|
|
302
334
|
"timestamp": "2024-01-14T12:34:56Z"
|
package/docs/RECIPES.md
CHANGED
|
@@ -268,3 +268,69 @@ ai-consultants update-clis --dry-run
|
|
|
268
268
|
For every available variable and its default, see
|
|
269
269
|
[`references/configuration.md`](../references/configuration.md). The executable
|
|
270
270
|
source of truth is [`scripts/config.sh`](../scripts/config.sh).
|
|
271
|
+
|
|
272
|
+
## Qwen via Qwen Cloud Token Plan (opt-in, preview)
|
|
273
|
+
|
|
274
|
+
`qwen3.8-max-preview` is **not** served by DashScope/ModelStudio. It is reachable
|
|
275
|
+
only through a Qwen Cloud **Token Plan** subscription, which has its own base URL
|
|
276
|
+
and its own API key. This is opt-in: nothing below is a default, and the panel's
|
|
277
|
+
premium Qwen model remains `qwen3.7-max`.
|
|
278
|
+
|
|
279
|
+
Understand the tradeoffs before enabling it:
|
|
280
|
+
|
|
281
|
+
- **Preview, not GA.** Alibaba describes it as continuously evolving. No open
|
|
282
|
+
weights, no published benchmarks, no stable per-token price.
|
|
283
|
+
- **Billed in prepaid credits**, not per token — and credit consumption varies
|
|
284
|
+
with reasoning depth. Cost reports therefore exclude it and say so explicitly
|
|
285
|
+
rather than estimating a figure.
|
|
286
|
+
|
|
287
|
+
### API mode (the effort knob works here)
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
QWEN3_USE_API=true
|
|
291
|
+
QWEN3_FORMAT=openai # Token Plan is OpenAI-compatible; DashScope is not
|
|
292
|
+
QWEN3_API_URL=https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions
|
|
293
|
+
QWEN3_MODEL=qwen3.8-max-preview
|
|
294
|
+
QWEN3_API_KEY=<your Token Plan key>
|
|
295
|
+
QWEN3_REASONING_EFFORT=high # none|minimal|low|medium|high|xhigh|max; default xhigh
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Pass the **full** URL including `/chat/completions` — it is used verbatim. Use
|
|
299
|
+
`QWEN3_API_KEY` for the Token Plan key; there is deliberately no separate
|
|
300
|
+
key variable, so the key always matches whatever `QWEN3_API_URL` points at.
|
|
301
|
+
|
|
302
|
+
Accepted effort values are the provider's own enum:
|
|
303
|
+
`none|minimal|low|medium|high|xhigh|max`. Verified against the live endpoint on
|
|
304
|
+
2026-07-21 — note this is wider than the `low|high|xhigh` reported in the public
|
|
305
|
+
write-ups. The one value this model rejects is `none`: thinking is always
|
|
306
|
+
enabled and cannot be disabled (`The value of the enable_thinking parameter is
|
|
307
|
+
restricted to True`). Anything unsupported comes back as a 400, never as a
|
|
308
|
+
silently ignored setting.
|
|
309
|
+
|
|
310
|
+
### CLI mode (the effort knob does NOT work here)
|
|
311
|
+
|
|
312
|
+
The `qwen` CLI has no reasoning-effort flag. Effort is a user-owned setting, so
|
|
313
|
+
ai-consultants cannot deliver it per call and warns if you set
|
|
314
|
+
`QWEN3_REASONING_EFFORT` in CLI mode. Configure it yourself in
|
|
315
|
+
`~/.qwen/settings.json`:
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"modelProviders": {
|
|
320
|
+
"openai": [
|
|
321
|
+
{
|
|
322
|
+
"id": "qwen3.8-max-preview",
|
|
323
|
+
"name": "[Token Plan] qwen3.8-max-preview",
|
|
324
|
+
"baseUrl": "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
|
|
325
|
+
"envKey": "BAILIAN_TOKEN_PLAN_API_KEY",
|
|
326
|
+
"generationConfig": { "reasoning": { "effort": "high" } }
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Caveat worth knowing**: if you also set `generationConfig.samplingParams` on an
|
|
334
|
+
OpenAI-compatible provider, Qwen Code ships those keys to the wire verbatim and
|
|
335
|
+
**skips the `reasoning` injection entirely** — so setting both silently gives you
|
|
336
|
+
no effort control at all.
|
package/docs/cost_rates.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.25.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.",
|
|
@@ -320,8 +320,16 @@
|
|
|
320
320
|
"grok-4.3": {
|
|
321
321
|
"input": 0.00125,
|
|
322
322
|
"output": 0.0025
|
|
323
|
+
},
|
|
324
|
+
"_comment_unpriced": "Credit-billed models: drawn from a prepaid subscription pool, with no published per-token price. Rated 0 so the estimator does not fabricate a figure - an absent model would otherwise fall through to default_rate (0.005/0.015) and be reported as a confident, wrong number. Every entry here must also be listed in unpriced_models, which is what makes the session report disclose the exclusion instead of implying the model was free.",
|
|
325
|
+
"qwen3.8-max-preview": {
|
|
326
|
+
"input": 0,
|
|
327
|
+
"output": 0
|
|
323
328
|
}
|
|
324
329
|
},
|
|
330
|
+
"unpriced_models": [
|
|
331
|
+
"qwen3.8-max-preview"
|
|
332
|
+
],
|
|
325
333
|
"consultant_fallbacks": {
|
|
326
334
|
"_comment": "Premium defaults - Updated Jun 2026 (v2.17.0)",
|
|
327
335
|
"claude": "claude-opus-4-8",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Release v2.25.0
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-21
|
|
4
|
+
**Type:** Minor — cost reporting starts working, and five settings that never did
|
|
5
|
+
**Previous:** v2.24.0
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- **The session cost you were shown was phantom.** Every consultant response carried a hardcoded token count of zero, so none of them contributed anything; the figure came entirely from the pipeline's own metadata files, priced at a fallback rate. A realistic three-consultant run reported $0.0270 without pricing a single consultation.
|
|
10
|
+
- **Five `*_FORMAT` settings had never done anything** since v2.6, despite being documented in `.env.example`. Now honored.
|
|
11
|
+
- **Opt-in Qwen Cloud Token Plan support**, including `qwen3.8-max-preview`. No default changed.
|
|
12
|
+
- **New `QWEN3_REASONING_EFFORT`** for API mode — and it tells you when it cannot apply, instead of pretending.
|
|
13
|
+
- **New `metadata.tokens_source`** field distinguishing a measured token count from an estimated one.
|
|
14
|
+
|
|
15
|
+
## What's New
|
|
16
|
+
|
|
17
|
+
### Cost reporting reflects reality
|
|
18
|
+
|
|
19
|
+
`build_response_metadata` emitted `tokens_used: 0` on every response, and it was the only writer of that field. `calculate_session_cost` multiplies it by the model's rate, so every real consultation contributed exactly nothing.
|
|
20
|
+
|
|
21
|
+
What you saw instead came from the same loop reaching files it should never have priced: `voting.json` and the other pipeline artifacts carry no token count, so each fell to a 1000-token fallback at the default rate. The reported cost tracked how many pipeline stages had run.
|
|
22
|
+
|
|
23
|
+
In API mode the correct number was already being computed — `run_api_mode_query` extracted the provider's usage figures, logged them at debug level, and discarded them.
|
|
24
|
+
|
|
25
|
+
Responses now carry a real count from two sources:
|
|
26
|
+
|
|
27
|
+
| Transport | Source | Field value |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| API | the provider's own usage figures | `tokens_source: "measured"` |
|
|
30
|
+
| CLI | local 4-chars-per-token approximation over prompt + reply | `tokens_source: "estimated"` |
|
|
31
|
+
|
|
32
|
+
No CLI exposes token counts, and CLI is the default transport, so the approximation is unavoidable if the fix is to mean anything. It is labeled rather than hidden, and the session-cost line says what it rests on:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Session cost: $0.0550 [token counts estimated for 3 of 3]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Settings that were never read
|
|
39
|
+
|
|
40
|
+
`QWEN3_FORMAT`, `GLM_FORMAT`, `GROK_FORMAT`, `DEEPSEEK_FORMAT` and `MINIMAX_FORMAT` were declared and documented, but the function that picks a consultant's wire format hardcoded the mapping and never consulted them. All five now work. An unrecognized value falls back to the consultant's default with a warning, so a typo cannot produce a malformed request.
|
|
41
|
+
|
|
42
|
+
This is what makes the Token Plan endpoint reachable: it is OpenAI-compatible, whereas Qwen's own DashScope endpoint is not.
|
|
43
|
+
|
|
44
|
+
### Qwen Cloud Token Plan (opt-in)
|
|
45
|
+
|
|
46
|
+
`qwen3.8-max-preview` is reachable only through a Token Plan subscription — separate endpoint, separate key, billed in prepaid credits. It is a preview, with no published benchmarks, no open weights, and no per-token price.
|
|
47
|
+
|
|
48
|
+
Because of that it is **configuration, not a default**: the premium Qwen model remains `qwen3.7-max`, and a test asserts that explicitly. Setting it up would break nothing for users without a subscription, because nothing points at it unless you do. See the recipe in `docs/RECIPES.md`.
|
|
49
|
+
|
|
50
|
+
Credit-billed models are catalogued at zero and listed under `unpriced_models`, so the session-cost line names them as excluded. Leaving such a model out of the catalog is not neutral — an unknown model falls through to a default rate roughly 4x the real Qwen premium input rate, and reports it as a confident figure.
|
|
51
|
+
|
|
52
|
+
### Reasoning effort
|
|
53
|
+
|
|
54
|
+
`QWEN3_REASONING_EFFORT` accepts the provider's own enum: `none|minimal|low|medium|high|xhigh|max`. Note this is wider than the `low|high|xhigh` that public write-ups report for this model — the list here was read off the API, not the documentation.
|
|
55
|
+
|
|
56
|
+
**It applies in API mode only.** The `qwen` CLI has no effort flag; the level is a user-owned setting in `~/.qwen/settings.json`. Setting the variable in CLI mode logs a warning pointing at that file, rather than silently doing nothing.
|
|
57
|
+
|
|
58
|
+
Which values a given model accepts is enforced by the provider, not guessed locally. `qwen3.8-max-preview`, for instance, rejects `none` because it cannot disable thinking — a 400 with a clear message beats a stale hardcoded list.
|
|
59
|
+
|
|
60
|
+
### Review pass
|
|
61
|
+
|
|
62
|
+
The change was put through a multi-agent review at maximum depth before release (55 agents, 52 verified findings, 15 distinct defects, all fixed). Nearly all of them were in the same class: making the token count real converted long-standing latent mis-billings into real money.
|
|
63
|
+
|
|
64
|
+
Pipeline metadata files were priced as phantom consultants. Cache hits — which make no API call — were billed at full price. Debate rounds were invisible. Escalated consultants were counted twice. And the provider's measured prompt/completion split was being collapsed and re-derived with a fixed 60/40 guess, overstating API-mode cost roughly 2.7x while still reporting it as measured. All are fixed, and a single helper now gates every loop over the responses directory so the next one cannot reintroduce them piecemeal.
|
|
65
|
+
|
|
66
|
+
The review also caught the reasoning-effort knob doing nothing on Qwen's *default* API configuration — the one path the documentation steers users to — which is precisely the failure the feature was designed to avoid.
|
|
67
|
+
|
|
68
|
+
## Breaking Changes
|
|
69
|
+
|
|
70
|
+
None in the API sense — no documented behavior is removed and defaults are byte-identical.
|
|
71
|
+
|
|
72
|
+
Two behavioral changes worth knowing:
|
|
73
|
+
|
|
74
|
+
- **Reported costs go from zero to real numbers.** If you tuned `MAX_SESSION_COST` against always-zero reports, revisit it. Budget projections before debate and synthesis now include actual accumulated spend; the pre-run checks were driven by a context-size estimate and already worked.
|
|
75
|
+
- **Responses gained `metadata.tokens_source`, and `tokens_input`/`tokens_output` when the provider reports them.** Additive, but consumers parsing response JSON strictly should know.
|
|
76
|
+
|
|
77
|
+
## Upgrade Guide
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# If installed via git clone
|
|
81
|
+
cd ~/.claude/skills/ai-consultants && git pull
|
|
82
|
+
|
|
83
|
+
# If installed via curl | bash
|
|
84
|
+
curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/scripts/install.sh | bash
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
No configuration changes are required. Everything new is opt-in.
|
|
88
|
+
|
|
89
|
+
To use Qwen 3.8, you need a Qwen Cloud Token Plan subscription and its dedicated API key, then the five settings in the `docs/RECIPES.md` recipe.
|
|
90
|
+
|
|
91
|
+
## Verification
|
|
92
|
+
|
|
93
|
+
Verified against a live Token Plan subscription rather than fixtures alone: a structured response through the real adapter (confidence 9, persona applied), `622` measured tokens in API mode, `311` estimated in CLI mode, and a full consultation reporting `$0.0550` where it would previously have said `0¢`.
|
|
94
|
+
|
|
95
|
+
A sweep of every suite at all four `LOG_LEVEL` values found three that were not hermetic against it — assertions matching on warning output are silent at `ERROR`, which fails deterministically for that environment while passing everywhere else. Two were pre-existing, and two of the affected assertions were the v2.17.2 secret-exfiltration guards. All three now pin the level.
|
|
96
|
+
|
|
97
|
+
`npm test` covers 22 suites. The new `test_api_transport.sh` exists mainly as a back-compat gate — its byte-identical assertion on the request builder shared by six consultants was written and confirmed green against the unmodified function before anything changed.
|
|
98
|
+
|
|
99
|
+
## Contributors
|
|
100
|
+
|
|
101
|
+
- @matteoscurati
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-consultants",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.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"
|
package/scripts/config.sh
CHANGED
package/scripts/consult_all.sh
CHANGED
|
@@ -692,9 +692,14 @@ if is_escalation_enabled && [[ $SUCCESS_COUNT -gt 0 ]]; then
|
|
|
692
692
|
[[ "$new_confidence" =~ ^[0-9]+$ ]] || new_confidence=0
|
|
693
693
|
if [[ "$new_confidence" -gt "$original_confidence" ]]; then
|
|
694
694
|
cp "$escalation_file" "$response_file"
|
|
695
|
+
# Remove the copy: leaving it makes one query look
|
|
696
|
+
# like two to every glob over this directory -
|
|
697
|
+
# cost (now that tokens are real) and voting alike.
|
|
698
|
+
rm -f "$escalation_file"
|
|
695
699
|
log_success " $consultant escalated: confidence $original_confidence → $new_confidence"
|
|
696
700
|
ESCALATED_COUNT=$((ESCALATED_COUNT + 1))
|
|
697
701
|
else
|
|
702
|
+
rm -f "$escalation_file"
|
|
698
703
|
log_debug " $consultant escalation did not improve confidence"
|
|
699
704
|
fi
|
|
700
705
|
fi
|
|
@@ -1092,7 +1097,7 @@ log_info "Session saved: $SESSION_ID"
|
|
|
1092
1097
|
if [[ "$ENABLE_COST_TRACKING" == "true" ]]; then
|
|
1093
1098
|
ACTUAL_COST=$(calculate_session_cost "$OUTPUT_DIR")
|
|
1094
1099
|
track_session_cost "$SESSION_ID" "$ACTUAL_COST"
|
|
1095
|
-
log_info "Session cost: $(format_cost "$ACTUAL_COST")"
|
|
1100
|
+
log_info "Session cost: $(format_cost "$ACTUAL_COST")$(format_cost_caveats "$OUTPUT_DIR")"
|
|
1096
1101
|
fi
|
|
1097
1102
|
|
|
1098
1103
|
# --- Final Summary ---
|
package/scripts/lib/api.sh
CHANGED
|
@@ -174,24 +174,74 @@ build_qwen_request() {
|
|
|
174
174
|
}'
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
# Validate a reasoning-effort value, echoing it lowercased.
|
|
178
|
+
# Usage: validate_reasoning_effort <value> <consultant_name>
|
|
179
|
+
# Returns 0 and echoes the normalized value, or returns 1 and echoes nothing.
|
|
180
|
+
#
|
|
181
|
+
# Deliberately fails instead of falling back to a default: silently ignoring a
|
|
182
|
+
# requested effort level would make the knob a no-op the user cannot detect.
|
|
183
|
+
# (get_api_format does fall back, because there a correct per-agent default
|
|
184
|
+
# exists; here the only "default" would be discarding the user's request.)
|
|
185
|
+
#
|
|
186
|
+
# The accepted set is the provider's own enum, read off a live 400 from the
|
|
187
|
+
# Qwen Cloud Token Plan endpoint (2026-07-21):
|
|
188
|
+
# 'reasoning_effort' must be one of: 'none', 'minimal', 'low', 'medium',
|
|
189
|
+
# 'high', 'xhigh', 'max'
|
|
190
|
+
# Note this is WIDER than the low|high|xhigh that the public write-ups for
|
|
191
|
+
# qwen3.8-max-preview all reported — 'minimal', 'medium' and 'max' are accepted
|
|
192
|
+
# by the model too. Taken from the API rather than from documentation for
|
|
193
|
+
# exactly that reason.
|
|
194
|
+
#
|
|
195
|
+
# The per-MODEL subset is deliberately NOT enforced here: encoding per-model
|
|
196
|
+
# facts in shell is what produced the stale-model bugs this release also fixes,
|
|
197
|
+
# and the same builder serves GLM/Grok/DeepSeek/MiniMax. An unsupported
|
|
198
|
+
# combination is rejected by the provider with a 400 that run_api_query
|
|
199
|
+
# surfaces without retrying — e.g. 'none' on qwen3.8-max-preview returns "The
|
|
200
|
+
# value of the enable_thinking parameter is restricted to True", which is a
|
|
201
|
+
# model fact, not a syntax error.
|
|
202
|
+
validate_reasoning_effort() {
|
|
203
|
+
local value="$1"
|
|
204
|
+
local consultant="${2:-consultant}"
|
|
205
|
+
|
|
206
|
+
value=$(echo "$value" | tr '[:upper:]' '[:lower:]')
|
|
207
|
+
|
|
208
|
+
case "$value" in
|
|
209
|
+
none|minimal|low|medium|high|xhigh|max)
|
|
210
|
+
echo "$value"
|
|
211
|
+
return 0
|
|
212
|
+
;;
|
|
213
|
+
*)
|
|
214
|
+
log_error "[$consultant] Invalid reasoning effort '$1' (expected: none|minimal|low|medium|high|xhigh|max)"
|
|
215
|
+
return 1
|
|
216
|
+
;;
|
|
217
|
+
esac
|
|
218
|
+
}
|
|
219
|
+
|
|
177
220
|
# Build request body for OpenAI-compatible APIs (GLM, Grok, Codex API mode, Mistral API mode)
|
|
178
|
-
# Usage: build_openai_request <prompt> <model> [max_tokens]
|
|
221
|
+
# Usage: build_openai_request <prompt> <model> [max_tokens] [reasoning_effort]
|
|
222
|
+
#
|
|
223
|
+
# reasoning_effort is optional and additive: when empty the object is
|
|
224
|
+
# byte-identical to what this function produced before the parameter existed,
|
|
225
|
+
# which matters because six consultants share this builder.
|
|
179
226
|
build_openai_request() {
|
|
180
227
|
local prompt="$1"
|
|
181
228
|
local model="${2:-gpt-4}"
|
|
182
229
|
local max_tokens="${3:-4096}"
|
|
230
|
+
local reasoning_effort="${4:-}"
|
|
183
231
|
|
|
184
232
|
jq -n \
|
|
185
233
|
--arg model "$model" \
|
|
186
234
|
--arg prompt "$prompt" \
|
|
187
235
|
--argjson max_tokens "$max_tokens" \
|
|
236
|
+
--arg effort "$reasoning_effort" \
|
|
188
237
|
'{
|
|
189
238
|
model: $model,
|
|
190
239
|
messages: [
|
|
191
240
|
{ role: "user", content: $prompt }
|
|
192
241
|
],
|
|
193
242
|
max_tokens: $max_tokens
|
|
194
|
-
}
|
|
243
|
+
}
|
|
244
|
+
+ (if $effort == "" then {} else { reasoning_effort: $effort } end)'
|
|
195
245
|
}
|
|
196
246
|
|
|
197
247
|
# Build request body for Anthropic API (Claude API mode)
|
|
@@ -334,10 +384,48 @@ extract_token_usage() {
|
|
|
334
384
|
;;
|
|
335
385
|
esac
|
|
336
386
|
|
|
387
|
+
[[ "$input_tokens" =~ ^[0-9]+$ ]] || input_tokens=0
|
|
388
|
+
[[ "$output_tokens" =~ ^[0-9]+$ ]] || output_tokens=0
|
|
389
|
+
|
|
337
390
|
local total=$((input_tokens + output_tokens))
|
|
338
391
|
echo "$total"
|
|
339
392
|
}
|
|
340
393
|
|
|
394
|
+
# Same extraction, but preserving the provider's prompt/completion split.
|
|
395
|
+
# Usage: extract_token_split <response_json> <format> -> "<input> <output>"
|
|
396
|
+
#
|
|
397
|
+
# The split is what cost actually depends on: output rates run 3-6x input rates
|
|
398
|
+
# and consultations are large-context/short-reply, so collapsing to a total and
|
|
399
|
+
# re-splitting it 60/40 overstates API-mode cost several-fold - while still
|
|
400
|
+
# being labeled "measured".
|
|
401
|
+
extract_token_split() {
|
|
402
|
+
local response="$1"
|
|
403
|
+
local format="${2:-openai}"
|
|
404
|
+
|
|
405
|
+
local input_tokens=0
|
|
406
|
+
local output_tokens=0
|
|
407
|
+
|
|
408
|
+
case "$format" in
|
|
409
|
+
qwen|anthropic)
|
|
410
|
+
input_tokens=$(echo "$response" | jq -r '.usage.input_tokens // 0' 2>/dev/null)
|
|
411
|
+
output_tokens=$(echo "$response" | jq -r '.usage.output_tokens // 0' 2>/dev/null)
|
|
412
|
+
;;
|
|
413
|
+
google_ai)
|
|
414
|
+
input_tokens=$(echo "$response" | jq -r '.usageMetadata.promptTokenCount // 0' 2>/dev/null)
|
|
415
|
+
output_tokens=$(echo "$response" | jq -r '.usageMetadata.candidatesTokenCount // 0' 2>/dev/null)
|
|
416
|
+
;;
|
|
417
|
+
*) # openai format (default)
|
|
418
|
+
input_tokens=$(echo "$response" | jq -r '.usage.prompt_tokens // 0' 2>/dev/null)
|
|
419
|
+
output_tokens=$(echo "$response" | jq -r '.usage.completion_tokens // 0' 2>/dev/null)
|
|
420
|
+
;;
|
|
421
|
+
esac
|
|
422
|
+
|
|
423
|
+
[[ "$input_tokens" =~ ^[0-9]+$ ]] || input_tokens=0
|
|
424
|
+
[[ "$output_tokens" =~ ^[0-9]+$ ]] || output_tokens=0
|
|
425
|
+
|
|
426
|
+
echo "$input_tokens $output_tokens"
|
|
427
|
+
}
|
|
428
|
+
|
|
341
429
|
# =============================================================================
|
|
342
430
|
# MAIN API QUERY FUNCTION
|
|
343
431
|
# =============================================================================
|