Skip to main content

sqlite_graphrag/i18n/validation/
messages_a.rs

1use crate::i18n::{current, Language};
2
3/// Localized message for `name_length`.
4pub fn name_length(max: usize) -> String {
5    match current() {
6        Language::English => format!("name must be 1-{max} chars"),
7        Language::Portuguese => format!("nome deve ter entre 1 e {max} caracteres"),
8    }
9}
10
11/// Localized message for `reserved_name`.
12pub fn reserved_name() -> String {
13    match current() {
14        Language::English => {
15            "names and namespaces starting with __ are reserved for internal use".to_string()
16        }
17        Language::Portuguese => {
18            "nomes e namespaces iniciados com __ são reservados para uso interno".to_string()
19        }
20    }
21}
22
23/// Localized message for `name_kebab`.
24pub fn name_kebab(nome: &str) -> String {
25    match current() {
26        Language::English => format!(
27            "name must be kebab-case slug (lowercase letters, digits, hyphens): '{nome}'"
28        ),
29        Language::Portuguese => {
30            format!("nome deve estar em kebab-case (minúsculas, dígitos, hífens): '{nome}'")
31        }
32    }
33}
34
35/// Localized message for `description_exceeds`.
36pub fn description_exceeds(max: usize) -> String {
37    match current() {
38        Language::English => format!("description must be <= {max} chars"),
39        Language::Portuguese => format!("descrição deve ter no máximo {max} caracteres"),
40    }
41}
42
43/// Localized message for `body_exceeds`.
44pub fn body_exceeds(max: usize) -> String {
45    match current() {
46        Language::English => format!("body exceeds {max} bytes"),
47        Language::Portuguese => format!("corpo excede {max} bytes"),
48    }
49}
50
51/// Localized message for `new_name_length`.
52pub fn new_name_length(max: usize) -> String {
53    match current() {
54        Language::English => format!("new-name must be 1-{max} chars"),
55        Language::Portuguese => format!("novo nome deve ter entre 1 e {max} caracteres"),
56    }
57}
58
59/// Localized message for `new_name_kebab`.
60pub fn new_name_kebab(nome: &str) -> String {
61    match current() {
62        Language::English => format!(
63            "new-name must be kebab-case slug (lowercase letters, digits, hyphens): '{nome}'"
64        ),
65        Language::Portuguese => format!(
66            "novo nome deve estar em kebab-case (minúsculas, dígitos, hífens): '{nome}'"
67        ),
68    }
69}
70
71/// Localized message for `namespace_length`.
72pub fn namespace_length() -> String {
73    match current() {
74        Language::English => "namespace must be 1-80 chars".to_string(),
75        Language::Portuguese => "namespace deve ter entre 1 e 80 caracteres".to_string(),
76    }
77}
78
79/// Localized message for `namespace_format`.
80pub fn namespace_format() -> String {
81    match current() {
82        Language::English => "namespace must be alphanumeric + hyphens/underscores".to_string(),
83        Language::Portuguese => {
84            "namespace deve ser alfanumérico com hífens/sublinhados".to_string()
85        }
86    }
87}
88
89/// Localized message for `path_traversal`.
90pub fn path_traversal(p: &str) -> String {
91    match current() {
92        Language::English => format!("path traversal rejected: {p}"),
93        Language::Portuguese => format!("traversal de caminho rejeitado: {p}"),
94    }
95}
96
97/// Rejects a `config set` key that is not in the canonical registry.
98///
99/// `suggestion` carries the nearest known key when one is similar enough,
100/// so a typo is actionable without the operator listing every key.
101pub fn config_key_unknown(key: &str, suggestion: Option<&str>) -> String {
102    match (current(), suggestion) {
103        (Language::English, Some(s)) => format!(
104            "unknown config key '{key}'; did you mean '{s}'? \
105             list valid keys with `config doctor --json`"
106        ),
107        (Language::English, None) => format!(
108            "unknown config key '{key}'; \
109             list valid keys with `config doctor --json`"
110        ),
111        (Language::Portuguese, Some(s)) => format!(
112            "chave de config desconhecida '{key}'; você quis dizer '{s}'? \
113             liste as chaves válidas com `config doctor --json`"
114        ),
115        (Language::Portuguese, None) => format!(
116            "chave de config desconhecida '{key}'; \
117             liste as chaves válidas com `config doctor --json`"
118        ),
119    }
120}
121
122/// Rejects a `config set` key that was advertised historically but never read.
123///
124/// Distinct from [`config_key_unknown`] because the operator followed the
125/// old documentation rather than mistyping, so the message names the
126/// replacement directly instead of guessing.
127pub fn config_key_retired(key: &str, replacement: &str) -> String {
128    match current() {
129        Language::English => format!(
130            "config key '{key}' was never read by this binary; \
131             use '{replacement}' instead"
132        ),
133        Language::Portuguese => format!(
134            "a chave de config '{key}' nunca foi lida por este binário; \
135             use '{replacement}' no lugar"
136        ),
137    }
138}
139
140/// Localized message for `invalid_tz`.
141pub fn invalid_tz(v: &str) -> String {
142    match current() {
143        Language::English => format!(
144            "display.tz invalid: '{v}'; use an IANA name like 'America/Sao_Paulo'"
145        ),
146        Language::Portuguese => format!(
147            "display.tz inválido: '{v}'; use um nome IANA como 'America/Sao_Paulo'"
148        ),
149    }
150}
151
152/// Localized message for `empty_query`.
153pub fn empty_query() -> String {
154    match current() {
155        Language::English => "query cannot be empty".to_string(),
156        Language::Portuguese => "a consulta não pode estar vazia".to_string(),
157    }
158}
159
160/// Localized message for `empty_body`.
161pub fn empty_body() -> String {
162    match current() {
163        Language::English => "body cannot be empty: provide --body, --body-file, or --body-stdin with content, or supply a graph via --entities-file/--graph-stdin".to_string(),
164        Language::Portuguese => "o corpo não pode estar vazio: forneça --body, --body-file ou --body-stdin com conteúdo, ou um grafo via --entities-file/--graph-stdin".to_string(),
165    }
166}
167
168/// Localized message for `invalid_namespace_config`.
169pub fn invalid_namespace_config(path: &str, err: &str) -> String {
170    match current() {
171        Language::English => {
172            format!("invalid project namespace config '{path}': {err}")
173        }
174        Language::Portuguese => {
175            format!("configuração de namespace de projeto inválida '{path}': {err}")
176        }
177    }
178}
179
180/// Localized message for `invalid_projects_mapping`.
181pub fn invalid_projects_mapping(path: &str, err: &str) -> String {
182    match current() {
183        Language::English => format!("invalid projects mapping '{path}': {err}"),
184        Language::Portuguese => format!("mapeamento de projetos inválido '{path}': {err}"),
185    }
186}
187
188/// Localized message for `self_referential_link`.
189pub fn self_referential_link() -> String {
190    match current() {
191        Language::English => "--from and --to must be different entities — self-referential relationships are not supported".to_string(),
192        Language::Portuguese => "--from e --to devem ser entidades diferentes — relacionamentos auto-referenciais não são suportados".to_string(),
193    }
194}
195
196/// Localized message for `invalid_link_weight`.
197pub fn invalid_link_weight(weight: f64) -> String {
198    match current() {
199        Language::English => {
200            format!("--weight: must be between 0.0 and 1.0 (actual: {weight})")
201        }
202        Language::Portuguese => {
203            format!("--weight: deve estar entre 0.0 e 1.0 (atual: {weight})")
204        }
205    }
206}
207
208/// Localized message for `sync_destination_equals_source`.
209pub fn sync_destination_equals_source() -> String {
210    match current() {
211        Language::English => {
212            "destination path must differ from the source database path".to_string()
213        }
214        Language::Portuguese => {
215            "caminho de destino deve ser diferente do caminho do banco de dados fonte"
216                .to_string()
217        }
218    }
219}
220
221// ── R-I18N-01 onda 1: reusable Validation catalog helpers ──────────────
222// Prefer these over ad-hoc `AppError::Validation(format!(...))` so EN/PT
223// stay in one place. English is the default agent language; PT follows
224// `current()` when locale is Portuguese.
225
226/// Generic "missing / required field" helper.
227pub fn missing_field(field: &str) -> String {
228    match current() {
229        Language::English => format!("missing required field: {field}"),
230        Language::Portuguese => format!("campo obrigatório ausente: {field}"),
231    }
232}
233
234/// Directory path does not exist.
235pub fn directory_not_found(path: &str) -> String {
236    match current() {
237        Language::English => format!("directory not found: {path}"),
238        Language::Portuguese => format!("diretório não encontrado: {path}"),
239    }
240}
241
242/// Path exists but is not a directory.
243pub fn not_a_directory(path: &str) -> String {
244    match current() {
245        Language::English => format!("path is not a directory: {path}"),
246        Language::Portuguese => format!("caminho não é um diretório: {path}"),
247    }
248}
249
250/// `--max-files` cap exceeded (generic form used by ingest-claude/codex).
251pub fn max_files_exceeded(found: usize, max: usize) -> String {
252    match current() {
253        Language::English => {
254            format!("found {found} files, exceeds --max-files cap of {max}")
255        }
256        Language::Portuguese => {
257            format!("encontrados {found} arquivos, excede o limite --max-files de {max}")
258        }
259    }
260}
261
262/// `--max-files` cap exceeded with pattern-matching wording (ingest).
263pub fn max_files_exceeded_matching(found: usize, max: usize) -> String {
264    match current() {
265        Language::English => format!(
266            "found {found} files matching pattern, exceeds --max-files cap of {max} \
267             (raise the cap or narrow the pattern)"
268        ),
269        Language::Portuguese => format!(
270            "encontrados {found} arquivos no padrão, excede o limite --max-files de {max} \
271             (aumente o limite ou restrinja o padrão)"
272        ),
273    }
274}
275
276/// `--max-files` cap exceeded with all-or-nothing abort (ingest-opencode).
277pub fn max_files_exceeded_all_or_nothing(found: usize, max: usize) -> String {
278    match current() {
279        Language::English => format!(
280            "found {found} files exceeding --max-files cap of {max}; aborting (all-or-nothing)"
281        ),
282        Language::Portuguese => format!(
283            "encontrados {found} arquivos excedendo o limite --max-files de {max}; \
284             abortando (tudo-ou-nada)"
285        ),
286    }
287}
288
289/// File bytes are not valid UTF-8.
290pub fn file_not_utf8(err: &impl std::fmt::Display) -> String {
291    match current() {
292        Language::English => format!("file is not valid UTF-8: {err}"),
293        Language::Portuguese => format!("arquivo não é UTF-8 válido: {err}"),
294    }
295}
296
297/// Queue resume (`status=processing` → `pending`) failed.
298pub fn queue_resume_failed(err: &impl std::fmt::Display) -> String {
299    match current() {
300        Language::English => format!("queue resume failed: {err}"),
301        Language::Portuguese => format!("falha ao retomar a fila: {err}"),
302    }
303}
304
305/// Queue retry-failed reset failed.
306pub fn queue_retry_failed_reset_failed(err: &impl std::fmt::Display) -> String {
307    match current() {
308        Language::English => format!("queue retry-failed reset failed: {err}"),
309        Language::Portuguese => {
310            format!("falha ao redefinir itens com falha da fila: {err}")
311        }
312    }
313}
314
315/// Queue clear failed.
316pub fn queue_clear_failed(err: &impl std::fmt::Display) -> String {
317    match current() {
318        Language::English => format!("queue clear failed: {err}"),
319        Language::Portuguese => format!("falha ao limpar a fila: {err}"),
320    }
321}
322
323/// Queue insert failed.
324pub fn queue_insert_failed(err: &impl std::fmt::Display) -> String {
325    match current() {
326        Language::English => format!("queue insert failed: {err}"),
327        Language::Portuguese => format!("falha ao inserir na fila: {err}"),
328    }
329}
330
331/// Invalid JSON for a CLI flag that takes a file path (e.g. `--entities-file`).
332pub fn invalid_json_in_flag(flag: &str, err: &impl std::fmt::Display) -> String {
333    match current() {
334        Language::English => format!("invalid JSON in {flag}: {err}"),
335        Language::Portuguese => format!("JSON inválido em {flag}: {err}"),
336    }
337}
338
339/// Invalid JSON payload on a stdin flag (e.g. `--graph-stdin`).
340pub fn invalid_json_payload_on_flag(flag: &str, err: &impl std::fmt::Display) -> String {
341    match current() {
342        Language::English => format!("invalid JSON payload on {flag}: {err}"),
343        Language::Portuguese => format!("payload JSON inválido em {flag}: {err}"),
344    }
345}
346
347/// Relation format error scoped to a source→target edge.
348pub fn relation_format_for_relationship(
349    err: &impl std::fmt::Display,
350    source: &str,
351    target: &str,
352) -> String {
353    match current() {
354        Language::English => format!("{err} for relationship '{source}' -> '{target}'"),
355        Language::Portuguese => {
356            format!("{err} para relacionamento '{source}' -> '{target}'")
357        }
358    }
359}
360
361/// Relationship strength outside [0.0, 1.0].
362pub fn invalid_relationship_strength(strength: f64, source: &str, target: &str) -> String {
363    match current() {
364        Language::English => format!(
365            "invalid strength {strength} for relationship '{source}' -> '{target}'; \
366             expected value in [0.0, 1.0]"
367        ),
368        Language::Portuguese => format!(
369            "força inválida {strength} para relacionamento '{source}' -> '{target}'; \
370             valor esperado em [0.0, 1.0]"
371        ),
372    }
373}
374
375/// Ingest aborted on first failure (`--fail-fast` / default all-or-nothing path).
376pub fn ingest_aborted_on_first_failure(err: &impl std::fmt::Display) -> String {
377    match current() {
378        Language::English => format!("ingest aborted on first failure: {err}"),
379        Language::Portuguese => format!("ingest abortado na primeira falha: {err}"),
380    }
381}
382
383/// Name normalized to empty (only hyphens/underscores/spaces).
384pub fn name_empty_after_normalization() -> String {
385    match current() {
386        Language::English => {
387            "name cannot be empty after normalization (input was blank or contained only hyphens/underscores/spaces)"
388                .to_string()
389        }
390        Language::Portuguese => {
391            "nome não pode ficar vazio após normalização (entrada em branco ou só com hífens/sublinhados/espaços)"
392                .to_string()
393        }
394    }
395}
396
397/// `--strict-name` refused auto-normalization.
398pub fn strict_name_not_canonical(original: &str, normalized: &str) -> String {
399    match current() {
400        Language::English => format!(
401            "--strict-name is set but '{original}' is not canonical kebab-case; \
402             re-run with --name '{normalized}' (or drop --strict-name to allow auto-normalization)"
403        ),
404        Language::Portuguese => format!(
405            "--strict-name está ativo mas '{original}' não é kebab-case canônico; \
406             reexecute com --name '{normalized}' (ou remova --strict-name para permitir auto-normalização)"
407        ),
408    }
409}
410
411/// `--enable-ner` and `--skip-extraction` conflict.
412pub fn enable_ner_skip_extraction_exclusive() -> String {
413    match current() {
414        Language::English => {
415            "--enable-ner and --skip-extraction are mutually exclusive; remove one"
416                .to_string()
417        }
418        Language::Portuguese => {
419            "--enable-ner e --skip-extraction são mutuamente exclusivos; remova um"
420                .to_string()
421        }
422    }
423}
424
425/// CREATE path requires `--type` and `--description`.
426pub fn type_and_description_required() -> String {
427    match current() {
428        Language::English => {
429            "--type and --description are required when creating a new memory".to_string()
430        }
431        Language::Portuguese => {
432            "--type e --description são obrigatórios ao criar uma nova memória".to_string()
433        }
434    }
435}
436
437/// External CLI binary missing at an explicit path.
438pub fn binary_not_found_at_path(tool: &str, path: &str) -> String {
439    match current() {
440        Language::English => format!("{tool} binary not found at explicit path: {path}"),
441        Language::Portuguese => {
442            format!("binário {tool} não encontrado no caminho explícito: {path}")
443        }
444    }
445}
446
447/// Executable not found in PATH.
448pub fn executable_not_in_path(binary: &str) -> String {
449    match current() {
450        Language::English => format!(
451            "executable '{binary}' not found in PATH; ensure Codex CLI is installed"
452        ),
453        Language::Portuguese => format!(
454            "executável '{binary}' não encontrado no PATH; certifique-se de que o Codex CLI está instalado"
455        ),
456    }
457}
458
459/// Tool version below the minimum required.
460pub fn version_below_minimum(tool: &str, actual: &str, min: &str) -> String {
461    match current() {
462        Language::English => {
463            format!("{tool} version {actual} is below minimum required {min}")
464        }
465        Language::Portuguese => {
466            format!("versão {actual} de {tool} está abaixo do mínimo exigido {min}")
467        }
468    }
469}
470
471/// External process timed out.
472pub fn process_timed_out(cmd: &str, secs: u64) -> String {
473    match current() {
474        Language::English => format!("{cmd} timed out after {secs} seconds"),
475        Language::Portuguese => format!("{cmd} expirou após {secs} segundos"),
476    }
477}
478
479/// External process exited with a non-zero code.
480pub fn process_exited(cmd: &str, code: Option<i32>, stderr: &str) -> String {
481    match current() {
482        Language::English => format!("{cmd} exited with code {code:?}: {stderr}"),
483        Language::Portuguese => {
484            format!("{cmd} encerrou com código {code:?}: {stderr}")
485        }
486    }
487}
488
489/// Failed to build the HTTP client.
490pub fn http_client_build_failed(err: &impl std::fmt::Display) -> String {
491    match current() {
492        Language::English => format!("failed to build HTTP client: {err}"),
493        Language::Portuguese => format!("falha ao construir cliente HTTP: {err}"),
494    }
495}
496
497/// Invalid JSON schema for an OpenRouter request body.
498pub fn invalid_json_schema_for_request(err: &impl std::fmt::Display) -> String {
499    match current() {
500        Language::English => {
501            format!("invalid JSON schema for OpenRouter request: {err}")
502        }
503        Language::Portuguese => {
504            format!("schema JSON inválido para requisição OpenRouter: {err}")
505        }
506    }
507}
508
509/// Model returned no structured content.
510pub fn model_no_structured_content(model: &str) -> String {
511    match current() {
512        Language::English => format!(
513            "model '{model}' returned no structured content (incompatible with \
514             structured outputs, or refused the request)"
515        ),
516        Language::Portuguese => format!(
517            "modelo '{model}' não retornou conteúdo estruturado (incompatível com \
518             saídas estruturadas, ou recusou a requisição)"
519        ),
520    }
521}
522
523/// Model content could not be parsed even after JSON repair.
524pub fn model_json_parse_failed(model: &str, err: &impl std::fmt::Display) -> String {
525    match current() {
526        Language::English => format!(
527            "model '{model}' returned content that could not be parsed even after \
528             JSON repair: {err}"
529        ),
530        Language::Portuguese => format!(
531            "modelo '{model}' retornou conteúdo que não pôde ser parseado mesmo após \
532             reparo de JSON: {err}"
533        ),
534    }
535}
536
537/// Model returned non-object JSON after repair.
538pub fn model_non_object_json(model: &str, shape: &str) -> String {
539    match current() {
540        Language::English => format!(
541            "model '{model}' returned non-object JSON after repair (got {shape}); \
542             likely a refusal or malformed structured output"
543        ),
544        Language::Portuguese => format!(
545            "modelo '{model}' retornou JSON não-objeto após reparo (obteve {shape}); \
546             provavelmente uma recusa ou saída estruturada malformada"
547        ),
548    }
549}
550
551/// HTTP request failed (transport-level).
552pub fn http_request_failed(err: &impl std::fmt::Display) -> String {
553    match current() {
554        Language::English => format!("HTTP request failed: {err}"),
555        Language::Portuguese => format!("requisição HTTP falhou: {err}"),
556    }
557}
558
559/// Failed to read HTTP response body.
560pub fn failed_to_read_response_body(err: &impl std::fmt::Display) -> String {
561    match current() {
562        Language::English => format!("failed to read response body: {err}"),
563        Language::Portuguese => format!("falha ao ler corpo da resposta: {err}"),
564    }
565}
566
567/// Failed to parse chat response JSON.
568pub fn failed_to_parse_chat_response(err: &impl std::fmt::Display) -> String {
569    match current() {
570        Language::English => format!("failed to parse chat response: {err}"),
571        Language::Portuguese => format!("falha ao parsear resposta de chat: {err}"),
572    }
573}
574
575/// OpenRouter returned a non-success status for a model.
576pub fn openrouter_status_error(
577    status: &impl std::fmt::Display,
578    model: &str,
579    body: &str,
580) -> String {
581    match current() {
582        Language::English => {
583            format!("OpenRouter returned {status} for model '{model}': {body}")
584        }
585        Language::Portuguese => {
586            format!("OpenRouter retornou {status} para o modelo '{model}': {body}")
587        }
588    }
589}
590
591/// OpenRouter 5xx server error.
592pub fn openrouter_server_error(status: &impl std::fmt::Display) -> String {
593    match current() {
594        Language::English => format!("OpenRouter server error: {status}"),
595        Language::Portuguese => format!("erro de servidor OpenRouter: {status}"),
596    }
597}
598
599/// Unexpected HTTP status with body snippet.
600pub fn unexpected_http_status(status: &impl std::fmt::Display, body: &str) -> String {
601    match current() {
602        Language::English => format!("unexpected HTTP {status}: {body}"),
603        Language::Portuguese => format!("HTTP inesperado {status}: {body}"),
604    }
605}
606
607/// `--target` only applies to re-embed operation.
608pub fn reembed_target_only(target: &str) -> String {
609    match current() {
610        Language::English => {
611            format!("--target {target} only applies to --operation re-embed")
612        }
613        Language::Portuguese => {
614            format!("--target {target} só se aplica a --operation re-embed")
615        }
616    }
617}
618
619/// System load average exceeds 2× ncpus.
620pub fn system_load_exceeded(load: f64, ncpus: usize) -> String {
621    match current() {
622        Language::English => format!(
623            "system load average {load:.2} exceeds 2x ncpus ({ncpus}); \
624             pass --no-max-load-check to override (not recommended)"
625        ),
626        Language::Portuguese => format!(
627            "carga média do sistema {load:.2} excede 2x ncpus ({ncpus}); \
628             passe --no-max-load-check para sobrescrever (não recomendado)"
629        ),
630    }
631}
632
633/// Preflight rate-limit with a distinct fallback provider.
634pub fn preflight_rate_limit_fallback(mode: &str, reason: &str, fallback: &str) -> String {
635    match current() {
636        Language::English => format!(
637            "preflight detected rate limit on {mode}: {reason}; \
638             re-invoke with `--mode {fallback}` to use the fallback provider"
639        ),
640        Language::Portuguese => format!(
641            "preflight detectou limite de taxa em {mode}: {reason}; \
642             reexecute com `--mode {fallback}` para usar o provedor de fallback"
643        ),
644    }
645}
646
647/// Preflight rate-limit when fallback equals current mode.
648pub fn preflight_rate_limit_same_mode(mode: &str, reason: &str) -> String {
649    match current() {
650        Language::English => format!(
651            "preflight detected rate limit on {mode}: {reason}; \
652             --fallback-mode matches --mode, no recovery possible"
653        ),
654        Language::Portuguese => format!(
655            "preflight detectou limite de taxa em {mode}: {reason}; \
656             --fallback-mode coincide com --mode, sem recuperação possível"
657        ),
658    }
659}
660
661/// Preflight rate-limit with operator suggestion (no fallback configured).
662pub fn preflight_rate_limit_suggestion(mode: &str, reason: &str, suggestion: &str) -> String {
663    match current() {
664        Language::English => format!(
665            "preflight detected rate limit on {mode}: {reason}; \
666             {suggestion}; pass --fallback-mode codex to recover"
667        ),
668        Language::Portuguese => format!(
669            "preflight detectou limite de taxa em {mode}: {reason}; \
670             {suggestion}; passe --fallback-mode codex para recuperar"
671        ),
672    }
673}
674
675/// OpenRouter mode requires an explicit model flag.
676pub fn openrouter_model_required() -> String {
677    match current() {
678        Language::English => {
679            "--mode openrouter requires --openrouter-model (no default model is allowed)"
680                .to_string()
681        }
682        Language::Portuguese => {
683            "--mode openrouter exige --openrouter-model (nenhum modelo padrão é permitido)"
684                .to_string()
685        }
686    }
687}
688
689/// OpenRouter API key could not be resolved.
690pub fn openrouter_api_key_not_found() -> String {
691    match current() {
692        Language::English => {
693            "OpenRouter API key not found; store it via \
694             `config add-key --provider openrouter`, or pass --openrouter-api-key \
695             (product env is deprecated)"
696                .to_string()
697        }
698        Language::Portuguese => {
699            "chave de API OpenRouter não encontrada; armazene via \
700             `config add-key --provider openrouter`, ou passe --openrouter-api-key \
701             (env de produto está depreciada)"
702                .to_string()
703        }
704    }
705}
706