Add gpt-oss-120b, qwen3-30b-a3b-fp8, and the domain IAB classifier - #3
Conversation
…IAB classifier Brings the CLI in line with the models published in the API reference. - `chat` gains `-m, --model` (default `LFM2.5-1.2B-Instruct`) covering `gpt-oss-120b`, `qwen3-30b-a3b-fp8`, and `LFM2.5-1.2B-Thinking`, plus `-r, --reasoning` to print the trace reasoning models return. `qwen3-30b-a3b-fp8` has no Responses endpoint, so it is routed to `/v1/chat/completions` transparently. - New `classify_domain` command for `zlm-v1-iab-domain-classifier`, which classifies a bare hostname with no page fetch. - `classify_iab_enriched` now sends `zlm-v2-iab-classify-edge-enriched`; the docs renamed the model from `zlm-v1-...`. - Reasoning models emit a `reasoning` output item ahead of the assistant message, so response parsing now selects the `message` item instead of assuming `output[0]`. - Refresh `ZGPU_PRICING` against the published catalog — the edge models are $0.02/$0.05 per 1M, not the $0.05/$0.40 the table still carried. Verified against the live API: all four model paths return expected output, and the reasoning trace is separated from the answer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe CLI adds ChangesCLI AI commands
Estimated code review effort: 3 (Moderate) | ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/DOCUMENTATION.md`:
- Around line 705-713: Update the “Common output behavior” documentation section
to describe selecting the assistant message from output and extracting its
output_text content, rather than assuming output[0]. Ensure it reflects
reasoning-first payloads and the existing fallback/pretty-print behavior used by
the parser.
- Line 191: Label the fenced code block at docs/DOCUMENTATION.md lines 191-191
as bash, label the fenced code block at lines 637-637 as bash, and label the
endpoint-contract fence at lines 685-685 as http or text to satisfy markdownlint
MD040.
In `@src/lib/responses.ts`:
- Around line 32-35: Update the response extraction logic around the message
selection in responses.ts so it only falls back to an untyped output item, never
a typed reasoning item. When no message or untyped output item exists, return
undefined so the existing missing-content error path is preserved; keep
output_text and legacy text extraction unchanged for valid items.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d7f45871-ad3e-4790-bdbc-7d0f98616a18
📒 Files selected for processing (12)
README.mddocs/ADDING_COMMANDS.mddocs/DOCUMENTATION.mdsrc/cli.tssrc/commands/chat.tssrc/commands/classifyDomain.tssrc/commands/classifyIabEnriched.tssrc/lib/chatCompletions.tssrc/lib/responses.tssrc/lib/savings.tstests/responses.test.tstests/savings.test.ts
| Chat with a ZeroGPU text-generation model. Defaults to `LFM2.5-1.2B-Instruct`. | ||
|
|
||
| **Synopsis** | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add languages to the fenced code blocks. These fences fail markdownlint MD040.
docs/DOCUMENTATION.md#L191-L191: label the CLI synopsis fence asbash.docs/DOCUMENTATION.md#L637-L637: label the CLI synopsis fence asbash.docs/DOCUMENTATION.md#L685-L685: label the endpoint-contract fence ashttportext.
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)
[warning] 191-191: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
📍 Affects 1 file
docs/DOCUMENTATION.md#L191-L191(this comment)docs/DOCUMENTATION.md#L637-L637docs/DOCUMENTATION.md#L685-L685
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/DOCUMENTATION.md` at line 191, Label the fenced code block at
docs/DOCUMENTATION.md lines 191-191 as bash, label the fenced code block at
lines 637-637 as bash, and label the endpoint-contract fence at lines 685-685 as
http or text to satisfy markdownlint MD040.
Source: Linters/SAST tools
| type?: string; | ||
| content?: Array<{ type?: string; text?: string }>; | ||
| }>; | ||
| } | ||
| ``` | ||
| It picks the first `content` entry whose `type === "output_text"` (falling back to `content[0]`), then prints `text` — pretty-printed if it parses as JSON, otherwise as a raw string. | ||
|
|
||
| Reasoning models emit a `reasoning` output item **ahead of** the assistant message, so `chat` selects the item whose `type === "message"` rather than assuming `output[0]`, and reads the trace from the `reasoning` item when `--reasoning` is passed. On the Chat Completions path the answer is `choices[0].message.content` and the trace is `choices[0].message.reasoning`. | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Align the common output contract with the new parser.
The earlier “Common output behavior” section still says every inference command reads output[0], which contradicts this message-item selection rule. Update that section to describe output_text extraction from the assistant message so integrations do not assume reasoning-first payloads are unsupported.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/DOCUMENTATION.md` around lines 705 - 713, Update the “Common output
behavior” documentation section to describe selecting the assistant message from
output and extracting its output_text content, rather than assuming output[0].
Ensure it reflects reasoning-first payloads and the existing
fallback/pretty-print behavior used by the parser.
| const items = data.output ?? []; | ||
| const message = items.find((item) => item.type === "message") ?? items[0]; | ||
| const parts = message?.content ?? []; | ||
| return parts.find((p) => p.type === "output_text")?.text ?? parts[0]?.text; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not treat a typed reasoning item as assistant output.
If a response contains only a reasoning item, items[0] is returned and its trace is printed as chat content even without --reasoning. Only fall back to an untyped output item for backward compatibility; otherwise return undefined and preserve the missing-content error path.
Proposed fix
- const message = items.find((item) => item.type === "message") ?? items[0];
+ const message =
+ items.find((item) => item.type === "message") ??
+ items.find((item) => item.type === undefined);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const items = data.output ?? []; | |
| const message = items.find((item) => item.type === "message") ?? items[0]; | |
| const parts = message?.content ?? []; | |
| return parts.find((p) => p.type === "output_text")?.text ?? parts[0]?.text; | |
| const items = data.output ?? []; | |
| const message = | |
| items.find((item) => item.type === "message") ?? | |
| items.find((item) => item.type === undefined); | |
| const parts = message?.content ?? []; | |
| return parts.find((p) => p.type === "output_text")?.text ?? parts[0]?.text; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/responses.ts` around lines 32 - 35, Update the response extraction
logic around the message selection in responses.ts so it only falls back to an
untyped output item, never a typed reasoning item. When no message or untyped
output item exists, return undefined so the existing missing-content error path
is preserved; keep output_text and legacy text extraction unchanged for valid
items.
Brings the CLI in line with the models published in the API reference. Three models were live in the docs with no CLI path to them, and one was renamed underneath us.
New models
gpt-oss-120bzerogpu chat -m gpt-oss-120bqwen3-30b-a3b-fp8zerogpu chat -m qwen3-30b-a3b-fp8zlm-v1-iab-domain-classifierzerogpu classify_domain <domain>chatgains--modelRather than a command per model,
chattakes-m, --modeland keepsLFM2.5-1.2B-Instructas the default, so every existing invocation behaves exactly as before.-r, --reasoningprints the trace that the reasoning models return alongside their answer.zerogpu chat "Why is my p99 latency spiking?" -m gpt-oss-120b -rqwen3-30b-a3b-fp8is the one model the platform serves only through Chat Completions, so the CLI posts it to/v1/chat/completionsinstead of/v1/responses, maps--instructionsto asystemmessage, and normalizesprompt_tokens/completion_tokensback to Responses token names for savings tracking. The routing is invisible to the caller.classify_domainClassifies a bare hostname — no crawl, no page body — for bidstream enrichment and inventory-level targeting.
Fixes carried along
zlm-v1-iab-classify-edge-enriched→zlm-v2-iab-classify-edge-enriched;classify_iab_enrichedwas still sending the v1 id.output[0]assumption. gpt-oss-120b returns areasoningitem before the assistant message, so the old extraction would have printed the reasoning as the answer. Response parsing now selects themessageitem.savings.ts. The table carried $0.05/$0.40 per 1M for the edge models; the published catalog says $0.02/$0.05. Savings figures were understated. The unknown-model fallback is now the priciest published rate so it can never overstate savings.Verification
npm run build,npm run lint, andnpm test(37 tests, incl. new coverage for reasoning-item extraction and usage mapping) all pass. All four model paths were also exercised against the live API —gpt-oss-120b(answer correctly separated from its reasoning trace),qwen3-30b-a3b-fp8via Chat Completions,classify_domain, andclassify_iab_enrichedon the v2 id.No version bump here — that is
npm run release's job per RELEASING.md.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
classify_domainto classify domains against the IAB taxonomy without fetching page content.chatwith multiple model options, multilingual and reasoning-capable models, and an optional reasoning trace.Updates
classify_iab_enrichedto use the enriched v2 model.Documentation