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