Skip to main content

ort_openrouter_cli/output/
from_json.rs

1//! ort: Open Router CLI
2//! https://github.com/grahamking/ort
3//!
4//! MIT License
5//! Copyright (c) 2025-2026 Graham King
6
7use core::str::FromStr;
8
9extern crate alloc;
10use alloc::borrow::{Cow, ToOwned};
11use alloc::string::{String, ToString};
12use alloc::vec;
13use alloc::vec::Vec;
14
15use crate::common::config;
16use crate::{
17    ChatCompletionsResponse, Choice, LastData, Message, Priority, PromptOpts, ReasoningConfig,
18    ReasoningEffort, Role, Usage,
19};
20
21impl ChatCompletionsResponse {
22    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
23        let mut p = Parser::new(json);
24        p.skip_ws();
25        p.expect(b'{')?;
26
27        let mut provider = None;
28        let mut model = None;
29        let mut choices = vec![];
30        let mut usage = None;
31
32        loop {
33            p.skip_ws();
34            if p.try_consume(b'}') {
35                break;
36            }
37
38            let key = p
39                .parse_simple_str()
40                .map_err(|err| "ChatCompletionsResponse parsing key: ".to_string() + err)?;
41            p.skip_ws();
42            p.expect(b':')?;
43            p.skip_ws();
44
45            match key {
46                "provider" => {
47                    if provider.is_some() {
48                        return Err("duplicate field: provider".into());
49                    }
50                    provider = Some(p.parse_string()?);
51                }
52                "model" => {
53                    if model.is_some() {
54                        return Err("duplicate field: model".into());
55                    }
56                    model = Some(p.parse_string()?);
57                }
58                "choices" => {
59                    if !choices.is_empty() {
60                        return Err("duplicate field: choices".into());
61                    }
62                    if !p.try_consume(b'[') {
63                        return Err("choices: Expected array".into());
64                    }
65                    p.skip_ws();
66                    // If the array isn't empty..
67                    if !p.try_consume(b']') {
68                        loop {
69                            let j = p.value_slice()?;
70                            let choice = Choice::from_json(j)?;
71                            choices.push(choice);
72                            p.skip_ws();
73                            if p.try_consume(b',') {
74                                continue;
75                            }
76                            p.skip_ws();
77                            if p.try_consume(b']') {
78                                break;
79                            }
80                        }
81                    }
82                }
83                "usage" => {
84                    if p.peek_is_null() {
85                        p.parse_null()?;
86                        usage = None;
87                    } else {
88                        let j = p.value_slice()?;
89                        usage = Some(Usage::from_json(j)?);
90                    }
91                }
92                _ => {
93                    p.skip_value()?;
94                }
95            }
96
97            p.skip_ws();
98            if p.try_consume(b',') {
99                continue;
100            }
101            p.skip_ws();
102            if p.try_consume(b'}') {
103                break;
104            }
105        }
106
107        Ok(ChatCompletionsResponse {
108            provider,
109            model,
110            choices,
111            usage,
112        })
113    }
114}
115
116impl Choice {
117    pub fn from_json(json: &str) -> Result<Self, String> {
118        let mut p = Parser::new(json);
119        p.skip_ws();
120        p.expect(b'{')?;
121
122        let mut delta = None;
123
124        'top: loop {
125            p.skip_ws();
126            if p.try_consume(b'}') {
127                break;
128            }
129
130            let key = p
131                .parse_simple_str()
132                .map_err(|err| "Choice::from_json parsing key: ".to_string() + err)?;
133            p.skip_ws();
134            p.expect(b':')?;
135            p.skip_ws();
136
137            match key {
138                "delta" => {
139                    let j = p.value_slice()?;
140                    delta = Some(Message::from_json(j)?);
141                    break 'top;
142                }
143                _ => {
144                    p.skip_value()?;
145                }
146            }
147
148            p.skip_ws();
149            if p.try_consume(b',') {
150                continue;
151            }
152            p.skip_ws();
153            if p.try_consume(b'}') {
154                break;
155            }
156        }
157
158        Ok(Choice {
159            delta: delta.expect("Missing delta in message"),
160        })
161    }
162}
163
164impl Usage {
165    pub fn from_json(json: &str) -> Result<Self, String> {
166        let mut p = Parser::new(json);
167        p.skip_ws();
168        p.expect(b'{')?;
169
170        // Currently we only extract cost
171        let mut cost = 0.0;
172
173        'top: loop {
174            p.skip_ws();
175            if p.try_consume(b'}') {
176                break;
177            }
178
179            let key = p
180                .parse_simple_str()
181                .map_err(|err| "Usage parsing key: ".to_string() + err)?;
182            p.skip_ws();
183            p.expect(b':')?;
184            p.skip_ws();
185
186            match key {
187                "cost" => {
188                    cost = p.parse_f32()?;
189                    // As we only care about cost, we are done as soon as we have it
190                    break 'top;
191                }
192                _ => {
193                    p.skip_value()?;
194                }
195            }
196
197            p.skip_ws();
198            if p.try_consume(b',') {
199                continue;
200            }
201            p.skip_ws();
202            if p.try_consume(b'}') {
203                break;
204            }
205        }
206
207        Ok(Usage { cost })
208    }
209}
210
211impl LastData {
212    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
213        if json.is_empty() {
214            return Err(
215                "Cannot continue, last-<$TMUX_PANE>.json file is empty. Usually that mains previous run failed.".into(),
216            );
217        }
218        let mut p = Parser::new(json);
219        p.skip_ws();
220        p.expect(b'{')?;
221
222        let mut opts = None;
223        let mut messages = vec![];
224
225        loop {
226            p.skip_ws();
227            if p.try_consume(b'}') {
228                break;
229            }
230
231            let key = p
232                .parse_simple_str()
233                .map_err(|err| "LastData parsing key: ".to_string() + err)?;
234            p.skip_ws();
235            p.expect(b':')?;
236            p.skip_ws();
237
238            match key {
239                "opts" => {
240                    if opts.is_some() {
241                        return Err("duplicate field: opts".into());
242                    }
243                    let j = p.value_slice()?;
244                    opts = Some(PromptOpts::from_json(j)?);
245                }
246                "messages" => {
247                    if !messages.is_empty() {
248                        return Err("duplicate field: messages".into());
249                    }
250                    if !p.try_consume(b'[') {
251                        return Err("messages: Expected array".into());
252                    }
253                    loop {
254                        let j = p.value_slice()?;
255                        let msg = Message::from_json(j)?;
256                        messages.push(msg);
257                        p.skip_ws();
258                        if p.try_consume(b',') {
259                            continue;
260                        }
261                        p.skip_ws();
262                        if p.try_consume(b']') {
263                            break;
264                        }
265                    }
266                }
267                _ => return Err("unknown field".into()),
268            }
269
270            p.skip_ws();
271            if p.try_consume(b',') {
272                continue;
273            }
274            p.skip_ws();
275            if p.try_consume(b'}') {
276                break;
277            }
278        }
279
280        Ok(LastData {
281            opts: opts.expect("Missing prompt opts"),
282            messages,
283        })
284    }
285}
286
287impl Message {
288    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
289        let mut p = Parser::new(json);
290        p.skip_ws();
291        p.expect(b'{')?;
292
293        let mut role = None;
294        let mut content = None;
295        let mut reasoning = None;
296
297        loop {
298            p.skip_ws();
299            if p.try_consume(b'}') {
300                break;
301            }
302
303            let key = p
304                .parse_simple_str()
305                .map_err(|err| "Message parsing key: ".to_string() + err)?;
306            p.skip_ws();
307            p.expect(b':')?;
308            p.skip_ws();
309
310            match key {
311                "role" => {
312                    if role.is_some() {
313                        return Err("duplicate field: role".into());
314                    }
315                    if p.peek_is_null() {
316                        p.parse_null()?;
317                        role = None;
318                    } else {
319                        let r = p.parse_simple_str()?;
320                        role = Some(Role::from_str(r)?);
321                    }
322                }
323                "content" => {
324                    if content.is_some() {
325                        return Err("duplicate field: content".into());
326                    }
327                    if p.peek_is_null() {
328                        p.parse_null()?;
329                        content = None;
330                    } else {
331                        content = Some(p.parse_string()?);
332                    }
333                }
334                "reasoning" => {
335                    if reasoning.is_some() {
336                        return Err("duplicate field: reasoning".into());
337                    }
338                    if p.peek_is_null() {
339                        p.parse_null()?;
340                        reasoning = None
341                    } else {
342                        reasoning = Some(p.parse_string()?);
343                    }
344                }
345                _ => {
346                    p.skip_value()?;
347                }
348            }
349
350            p.skip_ws();
351            if p.try_consume(b',') {
352                continue;
353            }
354            p.skip_ws();
355            if p.try_consume(b'}') {
356                break;
357            }
358        }
359
360        Ok(Message::new(
361            // NVIDIA doesn't always send it. sus.
362            role.unwrap_or(Role::Assistant),
363            content,
364            reasoning,
365        ))
366    }
367}
368
369impl ReasoningConfig {
370    pub fn from_json(json: &str) -> Result<ReasoningConfig, Cow<'static, str>> {
371        let mut p = Parser::new(json);
372        p.skip_ws();
373        p.expect(b'{')?;
374
375        let mut enabled: Option<bool> = None;
376        let mut effort: Option<ReasoningEffort> = None;
377        let mut tokens: Option<u32> = None;
378
379        loop {
380            p.skip_ws();
381            if p.try_consume(b'}') {
382                break;
383            }
384
385            // Key
386            let key = p
387                .parse_simple_str()
388                .map_err(|err| "ReasoningConfig parsing key: ".to_string() + err)?;
389            p.skip_ws();
390            p.expect(b':')?;
391            p.skip_ws();
392
393            // Value by key
394            match key {
395                "enabled" => {
396                    if enabled.is_some() {
397                        return Err("duplicate field: enabled".into());
398                    }
399                    if p.peek_is_null() {
400                        p.parse_null()?;
401                        enabled = None;
402                    } else {
403                        enabled = Some(p.parse_bool()?);
404                    }
405                }
406                "effort" => {
407                    if effort.is_some() {
408                        return Err("duplicate field: effort".into());
409                    }
410                    if p.peek_is_null() {
411                        p.parse_null()?;
412                        effort = None;
413                    } else {
414                        let v = p
415                            .parse_simple_str()
416                            .map_err(|err| "Parsing effort: ".to_string() + err)?;
417                        let e = if v.eq_ignore_ascii_case("none") {
418                            ReasoningEffort::None
419                        } else if v.eq_ignore_ascii_case("low") {
420                            ReasoningEffort::Low
421                        } else if v.eq_ignore_ascii_case("medium") {
422                            ReasoningEffort::Medium
423                        } else if v.eq_ignore_ascii_case("high") {
424                            ReasoningEffort::High
425                        } else if v.eq_ignore_ascii_case("xhigh") {
426                            ReasoningEffort::XHigh
427                        } else {
428                            return Err("invalid effort".into());
429                        };
430                        effort = Some(e);
431                    }
432                }
433                "tokens" => {
434                    if tokens.is_some() {
435                        return Err("duplicate field: tokens".into());
436                    }
437                    if p.peek_is_null() {
438                        p.parse_null()?;
439                        tokens = None;
440                    } else {
441                        tokens = Some(p.parse_u32()?);
442                    }
443                }
444                _ => return Err("unknown field".into()),
445            }
446
447            p.skip_ws();
448            if p.try_consume(b',') {
449                continue;
450            }
451
452            p.skip_ws();
453            if p.try_consume(b'}') {
454                break;
455            }
456
457            // If neither comma nor closing brace, it's malformed.
458            if !p.eof() {
459                return Err("expected ',' or '}'".into());
460            } else {
461                return Err("unexpected end of input".into());
462            }
463        }
464
465        p.skip_ws();
466        if !p.eof() {
467            return Err("trailing characters after JSON object".into());
468        }
469
470        let enabled = enabled.ok_or("missing required field: enabled")?;
471
472        Ok(ReasoningConfig {
473            enabled,
474            effort,
475            tokens,
476        })
477    }
478}
479
480impl PromptOpts {
481    pub fn from_json(input: &str) -> Result<Self, Cow<'static, str>> {
482        let mut p = Parser::new(input);
483
484        p.skip_ws();
485        p.expect(b'{')?;
486
487        let mut prompt: Option<String> = None;
488        let mut model: Option<String> = None;
489        let mut provider: Option<String> = None;
490        let mut system: Option<String> = None;
491        let mut priority: Option<Priority> = None;
492        let mut reasoning: Option<ReasoningConfig> = None;
493        let mut show_reasoning: Option<bool> = None;
494        let mut quiet: Option<bool> = None;
495        let mut merge_config = true;
496
497        p.skip_ws();
498        if p.try_consume(b'}') {
499            return Ok(PromptOpts {
500                prompt,
501                models: vec![],
502                provider,
503                system,
504                priority,
505                reasoning,
506                show_reasoning,
507                quiet,
508                merge_config,
509            });
510        }
511
512        loop {
513            p.skip_ws();
514            let key = p.parse_simple_str()?;
515            p.skip_ws();
516            p.expect(b':')?;
517            p.skip_ws();
518
519            match key {
520                "prompt" => {
521                    prompt = p.parse_opt_string()?;
522                }
523                "model" => {
524                    model = p.parse_opt_string()?;
525                }
526                "provider" => {
527                    provider = p.parse_opt_string()?;
528                }
529                "system" => {
530                    system = p.parse_opt_string()?;
531                }
532                "priority" => {
533                    if p.peek_is_null() {
534                        p.parse_null()?;
535                        priority = None;
536                    } else {
537                        let s = p.parse_simple_str()?;
538                        priority = Some(Priority::from_str(s).map_err(|_| "invalid priority")?);
539                    }
540                }
541                "reasoning" => {
542                    if p.peek_is_null() {
543                        p.parse_null()?;
544                        reasoning = None;
545                    } else {
546                        // Grab the exact object slice and delegate to ReasoningConfig::from_json
547                        let slice = p.value_slice()?; // must be an object
548                        let cfg = ReasoningConfig::from_json(slice).map_err(|e| {
549                            "parser::PromptOpts::from_json invalid reasoning: ".to_string() + &e
550                        })?;
551                        reasoning = Some(cfg);
552                    }
553                }
554                "show_reasoning" => {
555                    if p.peek_is_null() {
556                        p.parse_null()?;
557                        show_reasoning = None;
558                    } else {
559                        show_reasoning = Some(p.parse_bool()?);
560                    }
561                }
562                "quiet" => {
563                    if p.peek_is_null() {
564                        p.parse_null()?;
565                        quiet = None;
566                    } else {
567                        quiet = Some(p.parse_bool()?);
568                    }
569                }
570                "merge_config" => {
571                    if p.peek_is_null() {
572                        p.parse_null()?;
573                        merge_config = true;
574                    } else {
575                        merge_config = p.parse_bool()?;
576                    }
577                }
578                _ => {
579                    // Unknown field: skip its value
580                    p.skip_value()?;
581                }
582            }
583
584            p.skip_ws();
585            if p.try_consume(b',') {
586                continue;
587            } else {
588                p.expect(b'}')?;
589                break;
590            }
591        }
592
593        Ok(PromptOpts {
594            prompt,
595            models: model.map(|m| vec![m]).unwrap_or_default(),
596            provider,
597            system,
598            priority,
599            reasoning,
600            show_reasoning,
601            quiet,
602            merge_config,
603        })
604    }
605}
606
607impl config::ConfigFile {
608    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
609        let mut p = Parser::new(json);
610        p.skip_ws();
611        p.expect(b'{')?;
612
613        let mut settings: Option<config::Settings> = None;
614        let mut keys: Vec<config::ApiKey> = vec![];
615        let mut prompt_opts: Option<PromptOpts> = None;
616
617        loop {
618            p.skip_ws();
619            if p.try_consume(b'}') {
620                break;
621            }
622
623            let key = p
624                .parse_simple_str()
625                .map_err(|err| "ConfigFile parsing key: ".to_string() + err)?;
626            p.skip_ws();
627            p.expect(b':')?;
628            p.skip_ws();
629
630            match key {
631                "settings" => {
632                    if settings.is_some() {
633                        return Err("duplicate field: settings".into());
634                    }
635                    let settings_json = p.value_slice()?;
636                    settings = Some(config::Settings::from_json(settings_json)?);
637                }
638                "keys" => {
639                    if !keys.is_empty() {
640                        return Err("duplicate field: keys".into());
641                    }
642                    if !p.try_consume(b'[') {
643                        return Err("keys: Expected array".into());
644                    }
645                    loop {
646                        let j = p.value_slice()?;
647                        let api_key = config::ApiKey::from_json(j)?;
648                        keys.push(api_key);
649                        p.skip_ws();
650                        if p.try_consume(b',') {
651                            continue;
652                        }
653                        p.skip_ws();
654                        if p.try_consume(b']') {
655                            break;
656                        }
657                    }
658                }
659                "prompt_opts" => {
660                    if prompt_opts.is_some() {
661                        return Err("duplicate field: prompt_opts".into());
662                    }
663                    let opts_json = p.value_slice()?;
664                    prompt_opts = Some(PromptOpts::from_json(opts_json)?);
665                }
666                _ => return Err("unknown field".into()),
667            }
668            p.skip_ws();
669            if p.try_consume(b',') {
670                continue;
671            }
672            p.skip_ws();
673            if p.try_consume(b'}') {
674                break;
675            }
676        }
677
678        Ok(config::ConfigFile {
679            settings,
680            keys,
681            prompt_opts,
682        })
683    }
684}
685
686impl config::Settings {
687    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
688        let mut p = Parser::new(json);
689        p.skip_ws();
690        p.expect(b'{')?;
691
692        let mut save_to_file = None;
693        let mut dns = vec![];
694
695        loop {
696            p.skip_ws();
697            if p.try_consume(b'}') {
698                break;
699            }
700
701            let key = p
702                .parse_simple_str()
703                .map_err(|err| "Settings parsing key: ".to_string() + err)?;
704            p.skip_ws();
705            p.expect(b':')?;
706            p.skip_ws();
707
708            match key {
709                "save_to_file" => {
710                    if save_to_file.is_some() {
711                        return Err("duplicate field: save_to_file".into());
712                    }
713                    if p.peek_is_null() {
714                        p.parse_null()?;
715                        save_to_file = None;
716                    } else {
717                        save_to_file = Some(p.parse_bool()?);
718                    }
719                }
720                "dns" => {
721                    if !dns.is_empty() {
722                        return Err("duplicate field: dns".into());
723                    }
724                    if !p.try_consume(b'[') {
725                        return Err("dns: Expected array".into());
726                    }
727                    loop {
728                        let addr = p.parse_string()?;
729                        dns.push(addr);
730                        p.skip_ws();
731                        if p.try_consume(b',') {
732                            continue;
733                        }
734                        p.skip_ws();
735                        if p.try_consume(b']') {
736                            break;
737                        }
738                    }
739                }
740                _ => return Err("unknown field".into()),
741            }
742
743            p.skip_ws();
744            if p.try_consume(b',') {
745                continue;
746            }
747            p.skip_ws();
748            if p.try_consume(b'}') {
749                break;
750            }
751
752            // If neither comma nor closing brace, it's malformed.
753            if !p.eof() {
754                return Err("expected ',' or '}'".into());
755            } else {
756                return Err("unexpected end of input".into());
757            }
758        }
759
760        let default = config::Settings::default();
761        Ok(config::Settings {
762            save_to_file: save_to_file.unwrap_or(default.save_to_file),
763            dns,
764        })
765    }
766}
767
768impl config::ApiKey {
769    pub fn from_json(json: &str) -> Result<Self, Cow<'static, str>> {
770        let mut p = Parser::new(json);
771        p.skip_ws();
772        p.expect(b'{')?;
773
774        let mut name = None;
775        let mut value = None;
776
777        loop {
778            p.skip_ws();
779            if p.try_consume(b'}') {
780                break;
781            }
782
783            let key = p
784                .parse_simple_str()
785                .map_err(|err| "ApiKey parsing key: ".to_string() + err)?;
786            p.skip_ws();
787            p.expect(b':')?;
788            p.skip_ws();
789
790            match key {
791                "name" => {
792                    if name.is_some() {
793                        return Err("duplicate field: name".into());
794                    }
795                    name = Some(
796                        p.parse_string()
797                            .map_err(|err| "Parsing name: ".to_string() + &err)?,
798                    );
799                }
800                "value" => {
801                    if value.is_some() {
802                        return Err("duplicate field: value".into());
803                    }
804                    value = Some(
805                        p.parse_string()
806                            .map_err(|err| "Parsing name: ".to_string() + &err)?,
807                    );
808                }
809                _ => return Err("unknown field".into()),
810            }
811            p.skip_ws();
812            if p.try_consume(b',') {
813                continue;
814            } else {
815                p.expect(b'}')?;
816                break;
817            }
818        }
819
820        Ok(config::ApiKey::new(
821            name.expect("Missing ApiKey name"),
822            value.expect("Missing ApiKey value"),
823        ))
824    }
825}
826
827// --------------------------------------------
828
829// Minimal, fast JSON scanner tailored for our needs.
830struct Parser<'a> {
831    s: &'a str,
832    b: &'a [u8],
833    i: usize,
834}
835
836impl<'a> Parser<'a> {
837    fn new(s: &'a str) -> Self {
838        Self {
839            s,
840            b: s.as_bytes(),
841            i: 0,
842        }
843    }
844
845    fn eof(&self) -> bool {
846        self.i >= self.b.len()
847    }
848
849    fn peek(&self) -> Option<u8> {
850        if self.eof() {
851            None
852        } else {
853            Some(self.b[self.i])
854        }
855    }
856
857    fn try_consume(&mut self, ch: u8) -> bool {
858        if self.peek() == Some(ch) {
859            self.i += 1;
860            true
861        } else {
862            false
863        }
864    }
865
866    fn expect(&mut self, ch: u8) -> Result<(), &'static str> {
867        if self.try_consume(ch) {
868            Ok(())
869        } else {
870            Err("expected character")
871        }
872    }
873
874    fn skip_ws(&mut self) {
875        while let Some(c) = self.peek() {
876            match c {
877                b' ' | b'\n' | b'\r' | b'\t' => self.i += 1,
878                _ => break,
879            }
880        }
881    }
882
883    fn starts_with_bytes(&self, pat: &[u8]) -> bool {
884        let end = self.i + pat.len();
885        end <= self.b.len() && &self.b[self.i..end] == pat
886    }
887
888    fn parse_null(&mut self) -> Result<(), &'static str> {
889        if self.starts_with_bytes(b"null") {
890            self.i += 4;
891            Ok(())
892        } else {
893            Err("expected null")
894        }
895    }
896
897    fn peek_is_null(&self) -> bool {
898        self.starts_with_bytes(b"null")
899    }
900
901    fn parse_bool(&mut self) -> Result<bool, String> {
902        self.skip_ws();
903        if self.starts_with_bytes(b"true") {
904            self.i += 4;
905            Ok(true)
906        } else if self.starts_with_bytes(b"false") {
907            self.i += 5;
908            Ok(false)
909        } else {
910            Err("Expected boolean, got: ".to_string() + &String::from_utf8_lossy(&self.b[self.i..]))
911        }
912    }
913
914    fn parse_u32(&mut self) -> Result<u32, &'static str> {
915        self.skip_ws();
916        if self.eof() {
917            return Err("expected number");
918        }
919        if self.peek() == Some(b'-') {
920            return Err("negative not allowed");
921        }
922        let mut val: u32 = 0;
923        let mut read_any = false;
924        let len = self.b.len();
925        while self.i < len {
926            let c = self.b[self.i];
927            if c.is_ascii_digit() {
928                read_any = true;
929                let digit = (c - b'0') as u32;
930                // Overflow-safe accumulation
931                if val > (u32::MAX - digit) / 10 {
932                    return Err("u32 overflow");
933                }
934                val = val * 10 + digit;
935                self.i += 1;
936            } else {
937                break;
938            }
939        }
940        if !read_any {
941            return Err("expected integer");
942        }
943        Ok(val)
944    }
945
946    fn parse_f32(&mut self) -> Result<f32, &'static str> {
947        self.skip_ws();
948        if self.eof() {
949            return Err("expected number");
950        }
951
952        let len = self.b.len();
953
954        // Sign
955        let mut neg = false;
956        if let Some(c) = self.peek() {
957            if c == b'-' {
958                neg = true;
959                self.i += 1;
960            } else if c == b'+' {
961                self.i += 1;
962            }
963        }
964
965        // Mantissa accumulation (up to 9 significant digits)
966        let mut mant: u32 = 0;
967        let mut mant_digits: i32 = 0;
968        let mut ints: i32 = 0;
969
970        // Integer part
971        while self.i < len {
972            let c = self.b[self.i];
973            if c.is_ascii_digit() {
974                if mant_digits < 9 {
975                    mant = mant.saturating_mul(10).wrapping_add((c - b'0') as u32);
976                    mant_digits += 1;
977                }
978                self.i += 1;
979                ints += 1;
980            } else {
981                break;
982            }
983        }
984
985        // Fractional part
986        let mut frac_any = false;
987        if self.peek() == Some(b'.') {
988            self.i += 1;
989            let start_frac = self.i;
990            while self.i < len {
991                let c = self.b[self.i];
992                if c.is_ascii_digit() {
993                    if mant_digits < 9 {
994                        mant = mant.saturating_mul(10).wrapping_add((c - b'0') as u32);
995                        mant_digits += 1;
996                    }
997                    self.i += 1;
998                } else {
999                    break;
1000                }
1001            }
1002            frac_any = self.i > start_frac;
1003        }
1004
1005        if ints == 0 && !frac_any {
1006            return Err("expected number");
1007        }
1008
1009        // Exponent part
1010        let mut exp_part: i32 = 0;
1011        if let Some(ech) = self.peek()
1012            && (ech == b'e' || ech == b'E')
1013        {
1014            self.i += 1;
1015            let mut eneg = false;
1016            if let Some(signch) = self.peek() {
1017                if signch == b'-' {
1018                    eneg = true;
1019                    self.i += 1;
1020                } else if signch == b'+' {
1021                    self.i += 1;
1022                }
1023            }
1024            if self.eof() || !self.b[self.i].is_ascii_digit() {
1025                return Err("expected exponent");
1026            }
1027            let mut eacc: i32 = 0;
1028            while self.i < len {
1029                let c = self.b[self.i];
1030                if c.is_ascii_digit() {
1031                    let d = (c - b'0') as i32;
1032                    if eacc < 1_000_000_000 / 10 {
1033                        eacc = eacc * 10 + d;
1034                    } else {
1035                        eacc = 1_000_000_000; // clamp large exponents
1036                    }
1037                    self.i += 1;
1038                } else {
1039                    break;
1040                }
1041            }
1042            exp_part = if eneg { -eacc } else { eacc };
1043        }
1044
1045        // Effective base-10 exponent relative to the mantissa we built
1046        let exp10 = ints - mant_digits + exp_part;
1047
1048        // Scale using f64 to avoid premature underflow; cast to f32 at the end
1049        let mut val = mant as f64;
1050
1051        const POW10_POS: [f64; 39] = [
1052            1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1053            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
1054            1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38,
1055        ];
1056        const POW10_NEG: [f64; 46] = [
1057            1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13,
1058            1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25,
1059            1e-26, 1e-27, 1e-28, 1e-29, 1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37,
1060            1e-38, 1e-39, 1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45,
1061        ];
1062
1063        if exp10 > 0 {
1064            let mut e = exp10;
1065            while e > 0 {
1066                let chunk = if e > 38 { 38 } else { e } as usize;
1067                val *= POW10_POS[chunk];
1068                if !val.is_finite() {
1069                    return Err("f32 overflow");
1070                }
1071                e -= chunk as i32;
1072            }
1073        } else if exp10 < 0 {
1074            let mut e = -exp10;
1075            while e > 0 {
1076                let chunk = if e > 45 { 45 } else { e } as usize;
1077                val *= POW10_NEG[chunk];
1078                if val == 0.0 {
1079                    break;
1080                }
1081                e -= chunk as i32;
1082            }
1083        }
1084
1085        let mut out = val as f32;
1086        if !out.is_finite() {
1087            return Err("f32 overflow");
1088        }
1089        if neg {
1090            out = -out;
1091        }
1092        Ok(out)
1093    }
1094
1095    fn parse_simple_str(&mut self) -> Result<&'a str, &'static str> {
1096        self.skip_ws();
1097        if self.peek() != Some(b'"') {
1098            return Err("expected string");
1099        }
1100        self.i += 1;
1101        let start = self.i;
1102        let len = self.b.len();
1103        while self.i < len {
1104            let c = self.b[self.i];
1105            if c == b'\\' {
1106                // For maximum speed and simplicity, we reject escapes.
1107                return Err("string escapes are not supported");
1108            }
1109            if c == b'"' {
1110                let end = self.i;
1111                self.i += 1; // consume closing quote
1112                // Safety: start and end are at UTF-8 code point boundaries (quotes),
1113                // so slicing is valid even if contents contain non-ASCII.
1114                return Ok(&self.s[start..end]);
1115            }
1116            self.i += 1;
1117        }
1118        Err("unterminated string")
1119    }
1120
1121    fn parse_string(&mut self) -> Result<String, Cow<'static, str>> {
1122        self.skip_ws();
1123        if self.peek() != Some(b'"') {
1124            return Err(("expected string got: ".to_string()
1125                + &String::from_utf8_lossy(&self.b[self.i..]))
1126                .into());
1127        }
1128        let start = self.i + 1;
1129        let mut i = start;
1130        let len = self.b.len();
1131
1132        // First pass: detect if we need to unescape
1133        let mut needs_unescape = false;
1134        while i < len {
1135            let c = self.b[i];
1136            if c == b'\\' {
1137                needs_unescape = true;
1138                break;
1139            }
1140            if c == b'"' {
1141                // no escapes
1142                let s = core::str::from_utf8(&self.b[start..i]).map_err(|_| "utf8 error")?;
1143                self.i = i + 1;
1144                return Ok(s.to_owned());
1145            }
1146            i += 1;
1147        }
1148        if !needs_unescape {
1149            return Err("unterminated string".into());
1150        }
1151
1152        // Second pass: build with unescape
1153        // The "256" should include the biggest single-chunk reasoning item, which
1154        // depends on the inference server's caching.
1155        let mut out = String::with_capacity((i - start) + 256);
1156        let mut seg_start = start;
1157        while i < len {
1158            let c = self.b[i];
1159            if c == b'\\' {
1160                // push preceding segment
1161                if i > seg_start {
1162                    let prev =
1163                        core::str::from_utf8(&self.b[seg_start..i]).map_err(|_| "utf8 error")?;
1164                    out.push_str(prev);
1165                }
1166                i += 1;
1167                if i >= len {
1168                    return Err("bad escape".into());
1169                }
1170                let e = self.b[i];
1171                match e {
1172                    b'"' => out.push('"'),
1173                    b'\\' => out.push('\\'),
1174                    b'/' => out.push('/'),
1175                    b'b' => out.push('\u{0008}'),
1176                    b'f' => out.push('\u{000C}'),
1177                    b'n' => out.push('\n'),
1178                    b'r' => out.push('\r'),
1179                    b't' => out.push('\t'),
1180                    b'u' => {
1181                        let (cp, new_i) = self.parse_u_escape(i + 1)?;
1182                        i = new_i - 1; // -1 because loop will i += 1 at end
1183                        if let Some(ch) = core::char::from_u32(cp) {
1184                            out.push(ch);
1185                        } else {
1186                            return Err("invalid unicode".into());
1187                        }
1188                    }
1189                    _ => return Err("bad escape".into()),
1190                }
1191                i += 1;
1192                seg_start = i;
1193                continue;
1194            } else if c == b'"' {
1195                // end
1196                if i > seg_start {
1197                    out.push_str(
1198                        core::str::from_utf8(&self.b[seg_start..i]).map_err(|_| "utf8 error")?,
1199                    );
1200                }
1201                self.i = i + 1;
1202                return Ok(out);
1203            } else {
1204                i += 1;
1205            }
1206        }
1207        Err("unterminated string".into())
1208    }
1209
1210    // Parses \uXXXX (with surrogate-pair handling). Input index points at first hex digit after 'u'.
1211    fn parse_u_escape(&self, i: usize) -> Result<(u32, usize), &'static str> {
1212        fn hex4(bytes: &[u8], i: usize) -> Result<(u16, usize), &'static str> {
1213            let end = i + 4;
1214            if end > bytes.len() {
1215                return Err("short \\u");
1216            }
1217            let mut v: u16 = 0;
1218            for b in bytes.iter().take(end).skip(i) {
1219                v = (v << 4) | hex_val(*b)?;
1220            }
1221            Ok((v, end))
1222        }
1223        fn hex_val(b: u8) -> Result<u16, &'static str> {
1224            match b {
1225                b'0'..=b'9' => Ok((b - b'0') as u16),
1226                b'a'..=b'f' => Ok((b - b'a' + 10) as u16),
1227                b'A'..=b'F' => Ok((b - b'A' + 10) as u16),
1228                _ => Err("bad hex"),
1229            }
1230        }
1231
1232        let (first, i2) = hex4(self.b, i)?;
1233        let cp = first as u32;
1234
1235        // Surrogate pair handling
1236        if (0xD800..=0xDBFF).contains(&first) {
1237            // Expect \uXXXX next
1238            if i2 + 2 > self.b.len() || self.b[i2] != b'\\' || self.b[i2 + 1] != b'u' {
1239                return Err("missing low surrogate");
1240            }
1241            let (second, i3) = hex4(self.b, i2 + 2)?;
1242            if !(0xDC00..=0xDFFF).contains(&second) {
1243                return Err("invalid low surrogate");
1244            }
1245            let high = (first as u32) - 0xD800;
1246            let low = (second as u32) - 0xDC00;
1247            let code = 0x10000 + ((high << 10) | low);
1248            Ok((code, i3))
1249        } else if (0xDC00..=0xDFFF).contains(&first) {
1250            Err("unpaired low surrogate")
1251        } else {
1252            Ok((cp, i2))
1253        }
1254    }
1255
1256    fn parse_opt_string(&mut self) -> Result<Option<String>, Cow<'static, str>> {
1257        if self.peek_is_null() {
1258            self.parse_null()?;
1259            Ok(None)
1260        } else {
1261            let s = self.parse_string()?;
1262            Ok(Some(s))
1263        }
1264    }
1265
1266    // Returns a slice of the next JSON value and advances past it.
1267    fn value_slice(&mut self) -> Result<&'a str, &'static str> {
1268        self.skip_ws();
1269        let start = self.i;
1270        let end = self.find_value_end()?;
1271        let out = &self.s[start..end];
1272        self.i = end;
1273        Ok(out)
1274    }
1275
1276    // Skips the next JSON value (string/number/boolean/null/object/array).
1277    fn skip_value(&mut self) -> Result<(), &'static str> {
1278        let _ = self.value_slice()?;
1279        Ok(())
1280    }
1281
1282    fn find_value_end(&mut self) -> Result<usize, &'static str> {
1283        if self.eof() {
1284            return Err("unexpected end");
1285        }
1286        match self.b[self.i] {
1287            b'"' => self.scan_string_end(),
1288            b'{' => self.scan_brace_block(b'{', b'}'),
1289            b'[' => self.scan_brace_block(b'[', b']'),
1290            b't' => {
1291                if self.starts_with_bytes(b"true") {
1292                    Ok(self.i + 4)
1293                } else {
1294                    Err("bad literal")
1295                }
1296            }
1297            b'f' => {
1298                if self.starts_with_bytes(b"false") {
1299                    Ok(self.i + 5)
1300                } else {
1301                    Err("bad literal")
1302                }
1303            }
1304            b'n' => {
1305                if self.starts_with_bytes(b"null") {
1306                    Ok(self.i + 4)
1307                } else {
1308                    Err("bad literal")
1309                }
1310            }
1311            b'-' | b'0'..=b'9' => self.scan_number_end(),
1312            _t => {
1313                //let t_str = crate::utils::num_to_string(t as usize);
1314                //crate::utils::print_string(c"unexpected token: ", &t_str);
1315                Err("unexpected token")
1316            }
1317        }
1318    }
1319
1320    fn scan_string_end(&self) -> Result<usize, &'static str> {
1321        let mut i = self.i + 1;
1322        let len = self.b.len();
1323        let mut escaped = false;
1324        while i < len {
1325            let c = self.b[i];
1326            if escaped {
1327                escaped = false;
1328                i += 1;
1329                continue;
1330            }
1331            if c == b'\\' {
1332                escaped = true;
1333                i += 1;
1334                continue;
1335            }
1336            if c == b'"' {
1337                return Ok(i + 1);
1338            }
1339            i += 1;
1340        }
1341        Err("unterminated string")
1342    }
1343
1344    fn scan_brace_block(&self, open: u8, close: u8) -> Result<usize, &'static str> {
1345        let mut i = self.i;
1346        let len = self.b.len();
1347        let mut depth = 0usize;
1348        while i < len {
1349            let c = self.b[i];
1350            if c == b'"' {
1351                // Skip string
1352                let p = Parser {
1353                    s: self.s,
1354                    b: self.b,
1355                    i,
1356                };
1357                i = p.scan_string_end()?; // returns position after closing "
1358                continue;
1359            }
1360            if c == open {
1361                depth += 1;
1362            } else if c == close {
1363                depth -= 1;
1364                if depth == 0 {
1365                    return Ok(i + 1);
1366                }
1367            }
1368            i += 1;
1369        }
1370        Err("unterminated structure")
1371    }
1372
1373    fn scan_number_end(&self) -> Result<usize, &'static str> {
1374        let len = self.b.len();
1375        let mut i = self.i;
1376
1377        if self.b[i] == b'-' {
1378            i += 1;
1379            if i >= len {
1380                return Err("bad number");
1381            }
1382        }
1383
1384        // int part
1385        match self.b[i] {
1386            b'0' => {
1387                i += 1;
1388            }
1389            b'1'..=b'9' => {
1390                i += 1;
1391                while i < len {
1392                    match self.b[i] {
1393                        b'0'..=b'9' => i += 1,
1394                        _ => break,
1395                    }
1396                }
1397            }
1398            _ => return Err("bad number"),
1399        }
1400
1401        // frac
1402        if i < len && self.b[i] == b'.' {
1403            i += 1;
1404            if i >= len || !self.b[i].is_ascii_digit() {
1405                return Err("bad number");
1406            }
1407            while i < len && self.b[i].is_ascii_digit() {
1408                i += 1;
1409            }
1410        }
1411
1412        // exp
1413        if i < len && (self.b[i] == b'e' || self.b[i] == b'E') {
1414            i += 1;
1415            if i < len && (self.b[i] == b'+' || self.b[i] == b'-') {
1416                i += 1;
1417            }
1418            if i >= len || !self.b[i].is_ascii_digit() {
1419                return Err("bad number");
1420            }
1421            while i < len && self.b[i].is_ascii_digit() {
1422                i += 1;
1423            }
1424        }
1425
1426        Ok(i)
1427    }
1428}
1429
1430#[cfg(test)]
1431mod tests {
1432    extern crate alloc;
1433    use alloc::string::ToString;
1434
1435    use super::*;
1436    use crate::LastData;
1437
1438    #[test]
1439    fn rp1() {
1440        let cfg = ReasoningConfig::from_json(r#"{"enabled": false}"#).unwrap();
1441        assert!(!cfg.enabled);
1442        assert!(cfg.effort.is_none());
1443        assert!(cfg.tokens.is_none());
1444    }
1445
1446    #[test]
1447    fn rp2() {
1448        let cfg = ReasoningConfig::from_json(r#"{"enabled": true, "effort": "medium"}"#).unwrap();
1449        assert!(cfg.enabled);
1450        assert_eq!(cfg.effort, Some(ReasoningEffort::Medium));
1451        assert!(cfg.tokens.is_none());
1452    }
1453
1454    #[test]
1455    fn rp3() {
1456        let cfg = ReasoningConfig::from_json(r#"{"enabled": true, "tokens": 2048}"#).unwrap();
1457        assert!(cfg.enabled);
1458        assert_eq!(cfg.tokens, Some(2048));
1459        assert!(cfg.effort.is_none());
1460    }
1461
1462    #[test]
1463    fn rp4() {
1464        let cfg = ReasoningConfig::from_json(r#"{"enabled":true,"effort":"high","tokens":null}"#)
1465            .unwrap();
1466        assert!(cfg.enabled);
1467        assert_eq!(cfg.effort, Some(ReasoningEffort::High));
1468        assert!(cfg.tokens.is_none());
1469    }
1470
1471    #[test]
1472    fn cpo1() {
1473        let s = r#"
1474 {
1475     "prompt": "\n\nExample JSON 1: {\"enabled\": false}\n",
1476     "model": "google/gemma-3n-e4b-it:free",
1477     "system": "Make your answer concise but complete. No yapping. Direct professional tone. No emoji.",
1478     "show_reasoning": false,
1479     "reasoning": { "enabled": false },
1480     "merge_config": true
1481 }
1482 "#;
1483        let opts = PromptOpts::from_json(s).unwrap();
1484        assert!(!opts.show_reasoning.unwrap());
1485        assert_eq!(opts.models, vec!["google/gemma-3n-e4b-it:free"]);
1486        assert!(!opts.reasoning.unwrap().enabled);
1487        assert!(opts.merge_config);
1488    }
1489
1490    #[test]
1491    fn cpo2() {
1492        let s = r#"
1493    {"model":"openai/gpt-5","provider":"openai","system":"Make your answer concise but complete. No yapping. Direct professional tone. No emoji.","priority":null,"reasoning":{"enabled":true,"effort":"high","tokens":null},"show_reasoning":false,"quiet":true}
1494    "#;
1495        let opts = PromptOpts::from_json(s).unwrap();
1496        assert!(!opts.show_reasoning.unwrap());
1497        assert_eq!(opts.models, vec!["openai/gpt-5"]);
1498        assert!(opts.reasoning.as_ref().unwrap().enabled);
1499        assert_eq!(
1500            opts.reasoning.as_ref().unwrap().effort,
1501            Some(ReasoningEffort::High)
1502        );
1503    }
1504
1505    #[test]
1506    fn last_data() {
1507        let s = r#"
1508{"opts":{"model":"google/gemma-3n-e4b-it:free","provider":"google-ai-studio","system":"Make your answer concise but complete. No yapping. Direct professional tone. No emoji.","priority":null,"reasoning":{"enabled":false,"effort":null,"tokens":null},"show_reasoning":false},"messages":[{"role":"user","content":"Hello"},{"role":"assistant","content":"Hello there! 😊How can I help you today? I'm ready for anything – questions, stories, ideas, or just a friendly chat!Let me know what's on your mind. ✨"}]}
1509"#;
1510        let l = LastData::from_json(s).unwrap();
1511        assert_eq!(l.opts.provider.as_deref(), Some("google-ai-studio"));
1512        assert_eq!(l.messages.len(), 2);
1513    }
1514
1515    #[test]
1516    fn test_usage() {
1517        let s = r#"{"prompt_tokens":42,"completion_tokens":2,"total_tokens":44,"cost":0.0534,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}"#;
1518        let usage = Usage::from_json(s).unwrap();
1519        assert_eq!(usage.cost, 0.0534);
1520    }
1521
1522    #[test]
1523    fn test_choice() {
1524        let s = r#"{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}"#;
1525        let choice = Choice::from_json(s).unwrap();
1526        assert_eq!(choice.delta.content.as_deref(), Some("Hello"));
1527    }
1528
1529    #[test]
1530    fn test_chat_completions_response_simple() {
1531        let arr = [
1532            r#"{"id":"gen-1756743299-7ytIBcjALWQQShwMQfw9","provider":"Meta","model":"meta-llama/llama-3.3-8b-instruct:free","object":"chat.completion.chunk","created":1756743300,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1533            r#"{"id":"gen-1756743299-7ytIBcjALWQQShwMQfw9","provider":"Meta","model":"meta-llama/llama-3.3-8b-instruct:free","object":"chat.completion.chunk","created":1756743300,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}"#,
1534            r#"{"id":"gen-1756743299-7ytIBcjALWQQShwMQfw9","provider":"Meta","model":"meta-llama/llama-3.3-8b-instruct:free","object":"chat.completion.chunk","created":1756743300,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":42,"completion_tokens":2,"total_tokens":44,"cost":0,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}"#,
1535        ];
1536        for a in arr {
1537            let ccr = ChatCompletionsResponse::from_json(a).unwrap();
1538            assert_eq!(ccr.provider.as_deref(), Some("Meta"));
1539            assert_eq!(
1540                ccr.model.as_deref(),
1541                Some("meta-llama/llama-3.3-8b-instruct:free")
1542            );
1543            assert_eq!(ccr.choices.len(), 1);
1544        }
1545    }
1546
1547    #[test]
1548    fn test_chat_completions_response_more() {
1549        let arr = [
1550            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1551            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1552            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1553            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1554            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1555            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"Rea","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1556            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":"l","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}"#,
1557            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":" Madrid, 14 times.","reasoning":null,"reasoning_details":[]},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}"#,
1558            r#"{"id":"gen-1756749262-liysSWPMM37eb25U5gXO","provider":"WandB","model":"deepseek/deepseek-chat-v3.1","object":"chat.completion.chunk","created":1756749262,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":33,"completion_tokens":8,"total_tokens":41,"cost":0.0000310365,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.00001815,"upstream_inference_completions_cost":0.0000132},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0}}}"#,
1559        ];
1560        for a in arr {
1561            let ccr = ChatCompletionsResponse::from_json(a).unwrap();
1562            assert_eq!(ccr.provider.as_deref(), Some("WandB"));
1563            assert_eq!(ccr.model.as_deref(), Some("deepseek/deepseek-chat-v3.1"));
1564            assert_eq!(ccr.choices.len(), 1);
1565        }
1566    }
1567
1568    // Various null fields, including inside the message, and usage.
1569    #[test]
1570    fn test_nvidia_misc() {
1571        let s = r#"{"id":"8f20d6699e194a0abed38c671384d32d","object":"chat.completion.chunk","created":1770582573,"model":"qwen/qwen3-next-80b-a3b-instruct","choices":[{"index":0,"delta":{"role":null,"content":"Ta","reasoning_content":null,"tool_calls":null},"logprobs":null,"finish_reason":null,"matched_stop":null}],"usage":null}"#;
1572        let ccr = ChatCompletionsResponse::from_json(s).unwrap();
1573        assert_eq!(ccr.choices[0].delta.content.as_deref(), Some("Ta"));
1574    }
1575
1576    #[test]
1577    fn api_key() {
1578        let s = r#"{"name":"openrouter","value":"sk-or-v1-a123b456c789d012a345b8032470394876576573242374098174093274abcdef"}"#;
1579        let got = config::ApiKey::from_json(s).unwrap();
1580        let expect = config::ApiKey::new(
1581            "openrouter".to_string(),
1582            "sk-or-v1-a123b456c789d012a345b8032470394876576573242374098174093274abcdef".to_string(),
1583        );
1584        assert_eq!(got, expect);
1585    }
1586
1587    #[test]
1588    fn settings() {
1589        let s = r#"{
1590    "save_to_file": true,
1591    "dns": ["104.18.2.115", "104.18.3.115"]
1592}"#;
1593        let settings = config::Settings::from_json(s).unwrap();
1594        assert!(settings.save_to_file);
1595        assert_eq!(settings.dns, ["104.18.2.115", "104.18.3.115"]);
1596    }
1597
1598    #[test]
1599    fn config_file() {
1600        let s = r#"
1601{
1602    "keys": [{"name": "openrouter", "value": "sk-or-v1-abcd1234"}],
1603    "settings": {
1604        "save_to_file": true,
1605        "dns": ["104.18.2.115", "104.18.3.115"]
1606    },
1607    "prompt_opts": {
1608        "model": "google/gemma-3n-e4b-it:free",
1609        "system": "Make your answer concise but complete. No yapping. Direct professional tone. No emoji.",
1610        "quiet": false,
1611        "show_reasoning": false,
1612        "reasoning": {
1613            "enabled": false
1614        }
1615    }
1616}
1617"#;
1618        let cfg = config::ConfigFile::from_json(s).unwrap();
1619        assert_eq!(cfg.keys.len(), 1);
1620        assert!(cfg.settings.is_some());
1621        assert!(cfg.prompt_opts.is_some());
1622    }
1623}