formal-ai 0.79.0

Formal symbolic AI implementation with OpenAI-compatible APIs
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
//! Feature-specific capability questions and runtime availability.

use crate::engine::SymbolicAnswer;
use crate::event_log::EventLog;
use crate::language::detect as detect_language;
use crate::solver_handlers::finalize_simple;
use crate::web_search_core::{WEB_SEARCH_PROVIDERS, WEB_SEARCH_RRF_K};

#[derive(Debug, Clone, Copy)]
#[allow(clippy::struct_excessive_bools)]
pub struct CapabilityRuntime {
    pub offline: bool,
    pub agent_mode: bool,
    pub diagnostic_mode: bool,
    pub definition_fusion_by_default: bool,
}

impl CapabilityRuntime {
    #[allow(clippy::fn_params_excessive_bools)]
    pub const fn new(
        offline: bool,
        agent_mode: bool,
        diagnostic_mode: bool,
        definition_fusion_by_default: bool,
    ) -> Self {
        Self {
            offline,
            agent_mode,
            diagnostic_mode,
            definition_fusion_by_default,
        }
    }
}

pub fn try_feature_capability(
    prompt: &str,
    normalized: &str,
    log: &mut EventLog,
    runtime: CapabilityRuntime,
) -> Option<SymbolicAnswer> {
    let language = detect_language(prompt);
    if !is_feature_capability_question(normalized, language.slug()) {
        return None;
    }

    let feature = detect_feature_capability(normalized, language.slug())?;
    if is_feature_action_request(normalized, feature) {
        return None;
    }
    let availability = feature.availability(runtime);
    log.append("feature:question", feature.slug.to_owned());
    if availability.available {
        log.append("feature:available", feature.slug.to_owned());
    } else {
        log.append(
            "feature:unavailable",
            format!("{}:{}", feature.slug, availability.reason.slug()),
        );
    }

    let body = if feature.slug == "web_search" {
        if availability.available {
            for provider in WEB_SEARCH_PROVIDERS {
                log.append("web_search:provider", (*provider).to_owned());
            }
            log.append("web_search:combined", format!("rrf:k={WEB_SEARCH_RRF_K}"));
        }
        web_search_capability_body(
            language.slug(),
            availability.available,
            &WEB_SEARCH_PROVIDERS.join(", "),
        )
    } else {
        feature_capability_body(feature, language.slug(), availability)
    };

    Some(finalize_simple(
        prompt,
        log,
        "capabilities",
        "response:capabilities",
        &body,
        if availability.available { 0.95 } else { 0.6 },
    ))
}

#[derive(Debug, Clone, Copy)]
struct FeatureCapability {
    slug: &'static str,
    state: FeatureState,
    labels: LocalizedText,
    aliases: LocalizedText,
    examples: LocalizedText,
}

#[derive(Debug, Clone, Copy)]
enum FeatureState {
    Always,
    WebSearch,
    AgentMode,
    DiagnosticMode,
    DefinitionFusion,
}

#[derive(Debug, Clone, Copy)]
struct LocalizedText {
    en: &'static str,
    ru: &'static str,
    hi: &'static str,
    zh: &'static str,
}

#[derive(Debug, Clone, Copy)]
struct FeatureAvailability {
    available: bool,
    reason: UnavailableReason,
}

#[derive(Debug, Clone, Copy)]
enum UnavailableReason {
    None,
    OfflineOrNoProviders,
    AgentModeOff,
    DiagnosticModeOff,
    DefinitionFusionExplicit,
}

impl UnavailableReason {
    const fn slug(self) -> &'static str {
        match self {
            Self::None => "none",
            Self::OfflineOrNoProviders => "offline_or_no_providers",
            Self::AgentModeOff => "agent_mode_off",
            Self::DiagnosticModeOff => "diagnostic_mode_off",
            Self::DefinitionFusionExplicit => "definition_fusion_explicit",
        }
    }
}

impl FeatureCapability {
    fn label(self, language: &str) -> &'static str {
        localized(self.labels, language)
    }

    fn example(self, language: &str) -> &'static str {
        localized(self.examples, language)
    }

    fn aliases(self, language: &str) -> &'static str {
        localized(self.aliases, language)
    }

    const fn availability(self, runtime: CapabilityRuntime) -> FeatureAvailability {
        match self.state {
            FeatureState::Always => FeatureAvailability {
                available: true,
                reason: UnavailableReason::None,
            },
            FeatureState::WebSearch => FeatureAvailability {
                available: !runtime.offline && !WEB_SEARCH_PROVIDERS.is_empty(),
                reason: if runtime.offline || WEB_SEARCH_PROVIDERS.is_empty() {
                    UnavailableReason::OfflineOrNoProviders
                } else {
                    UnavailableReason::None
                },
            },
            FeatureState::AgentMode => FeatureAvailability {
                available: runtime.agent_mode,
                reason: if runtime.agent_mode {
                    UnavailableReason::None
                } else {
                    UnavailableReason::AgentModeOff
                },
            },
            FeatureState::DiagnosticMode => FeatureAvailability {
                available: runtime.diagnostic_mode,
                reason: if runtime.diagnostic_mode {
                    UnavailableReason::None
                } else {
                    UnavailableReason::DiagnosticModeOff
                },
            },
            FeatureState::DefinitionFusion => FeatureAvailability {
                available: runtime.definition_fusion_by_default,
                reason: if runtime.definition_fusion_by_default {
                    UnavailableReason::None
                } else {
                    UnavailableReason::DefinitionFusionExplicit
                },
            },
        }
    }
}

fn localized(text: LocalizedText, language: &str) -> &'static str {
    match language {
        "ru" => text.ru,
        "hi" => text.hi,
        "zh" => text.zh,
        _ => text.en,
    }
}

fn detect_feature_capability(normalized: &str, language: &str) -> Option<FeatureCapability> {
    FEATURE_CAPABILITIES.iter().copied().find(|feature| {
        contains_alias(normalized, feature.aliases(language))
            || (language != "en" && contains_alias(normalized, feature.aliases("en")))
    })
}

fn contains_alias(normalized: &str, aliases: &str) -> bool {
    aliases.split('|').any(|alias| normalized.contains(alias))
}

fn is_feature_capability_question(normalized: &str, language: &str) -> bool {
    match language {
        "ru" => contains_alias(
            normalized,
            "можешь|умеешь|поддерживаешь|у тебя есть|есть ли|доступен|доступна|включен|включена|подключен|подключена|можно ли",
        ),
        "zh" => contains_alias(normalized, "能|可以|支持|有|启用|可用"),
        "hi" => contains_alias(normalized, "क्या|सकते|सकती|समर्थन|उपलब्ध"),
        _ => contains_alias(
            normalized,
            "can you|can formal-ai|are you able|are you connected|do you support|do you have|enabled|available|can i",
        ),
    }
}

fn is_feature_action_request(normalized: &str, feature: FeatureCapability) -> bool {
    match feature.slug {
        "arithmetic" => starts_with_alias(normalized, "can you calculate |can you compute "),
        "planning" => contains_alias(
            normalized,
            "can you summarize |can you brainstorm |can you roleplay ",
        ),
        _ => false,
    }
}

fn starts_with_alias(normalized: &str, aliases: &str) -> bool {
    aliases
        .split('|')
        .any(|alias| normalized.starts_with(alias))
}

fn feature_capability_body(
    feature: FeatureCapability,
    language: &str,
    availability: FeatureAvailability,
) -> String {
    let label = feature.label(language);
    let example = feature.example(language);
    if availability.available {
        return match language {
            "ru" => format!(
                "Да. Возможность «{label}» доступна в этой конфигурации. Пример сообщения: `{example}`."
            ),
            "zh" => format!("可以。当前配置中「{label}」可用。示例消息:`{example}`。"),
            "hi" => format!("हाँ। इस configuration में `{label}` available है। Example message: `{example}`."),
            _ => format!(
                "Yes. {label} is available in this configuration. Example message: `{example}`."
            ),
        };
    }

    let reason = unavailable_reason_body(availability.reason, language);
    match language {
        "ru" => format!(
            "Нет. Возможность «{label}» сейчас недоступна в этой конфигурации: {reason}. Пример сообщения после включения: `{example}`."
        ),
        "zh" => format!("不可以。当前配置中「{label}」不可用:{reason}。启用后的示例消息:`{example}`。"),
        "hi" => format!("नहीं। इस configuration में `{label}` अभी available नहीं है: {reason}. Enable करने के बाद example message: `{example}`."),
        _ => format!(
            "No. {label} is not available in this configuration: {reason}. Example message after enabling it: `{example}`."
        ),
    }
}

fn unavailable_reason_body(reason: UnavailableReason, language: &str) -> &'static str {
    match (reason, language) {
        (UnavailableReason::OfflineOrNoProviders, "ru") => {
            "offline-режим включен или нет доступных поисковых провайдеров"
        }
        (UnavailableReason::OfflineOrNoProviders, "zh") => {
            "offline 模式开启或没有可用搜索 provider"
        }
        (UnavailableReason::OfflineOrNoProviders, "hi") => {
            "offline mode enabled है या कोई search provider configured नहीं है"
        }
        (UnavailableReason::OfflineOrNoProviders, _) => {
            "offline mode is enabled or no search providers are configured"
        }
        (UnavailableReason::AgentModeOff, "ru") => {
            "agent mode выключен; для многошаговых действий нужен явный opt-in"
        }
        (UnavailableReason::AgentModeOff, "zh") => "agent mode 已关闭;多步骤操作需要显式启用",
        (UnavailableReason::AgentModeOff, "hi") => {
            "agent mode off है; multi-step actions के लिए explicit opt-in चाहिए"
        }
        (UnavailableReason::AgentModeOff, _) => {
            "agent mode is off; multi-step actions require explicit opt-in"
        }
        (UnavailableReason::DiagnosticModeOff, "ru") => {
            "диагностика выключена; включите ее, чтобы видеть трассировку"
        }
        (UnavailableReason::DiagnosticModeOff, "zh") => "诊断已关闭;开启后才会显示 trace",
        (UnavailableReason::DiagnosticModeOff, "hi") => {
            "diagnostics off है; trace दिखाने के लिए इसे enable करें"
        }
        (UnavailableReason::DiagnosticModeOff, _) => {
            "diagnostics are off; enable them to show traces"
        }
        (UnavailableReason::DefinitionFusionExplicit, "ru") => {
            "автоматическое слияние определений работает только после включения режима auto"
        }
        (UnavailableReason::DefinitionFusionExplicit, "zh") => {
            "自动 definition fusion 需要切换到 auto 模式"
        }
        (UnavailableReason::DefinitionFusionExplicit, "hi") => {
            "automatic definition fusion के लिए auto mode enable करना होगा"
        }
        (UnavailableReason::DefinitionFusionExplicit, _) => {
            "automatic definition fusion is set to explicit-only"
        }
        (UnavailableReason::None, _) => "available",
    }
}

const fn text(
    en: &'static str,
    ru: &'static str,
    hi: &'static str,
    zh: &'static str,
) -> LocalizedText {
    LocalizedText { en, ru, hi, zh }
}

const FEATURE_CAPABILITIES: &[FeatureCapability] = &[
    FeatureCapability {
        slug: "web_search",
        state: FeatureState::WebSearch,
        labels: text("web search", "веб-поиск", "web search", "web search"),
        aliases: text(
            "web search|internet search|search engines|can you search the internet|can you search internet|can you search the web|can you search web|can you search online|do you have internet search|do you have web search|do you have internet access|are you connected to search engines|can you use search engines|can you browse the web",
            "веб-поиск|веб поиск|поиск в интернете|поисковик|поисковые системы|можешь искать в интернете|можешь искать интернет|умеешь искать в интернете|умеешь искать интернет|можешь искать онлайн|умеешь искать онлайн|у тебя есть веб-поиск|у тебя есть веб поиск|у тебя есть поиск в интернете|есть доступ к интернету|подключен к поисковикам|подключена к поисковикам|подключен к поисковым системам|можешь пользоваться интернетом",
            "web search|internet search|search engine|इंटरनेट पर खोज सकते|ऑनलाइन खोज सकते|इंटरनेट खोज है|वेब खोज है|सर्च इंजन से जुड़े|खोज इंजन से जुड़े",
            "web search|搜索引擎|上网搜索|搜索互联网|搜索网络|联网搜索|用搜索引擎|使用搜索引擎|网络搜索",
        ),
        examples: text(
            "Search the web for Nikola Tesla",
            "Найди в интернете Никола Тесла",
            "Search the web for Nikola Tesla",
            "Search the web for Nikola Tesla",
        ),
    },
    FeatureCapability {
        slug: "diagnostics",
        state: FeatureState::DiagnosticMode,
        labels: text("diagnostic trace", "диагностика", "diagnostic trace", "诊断 trace"),
        aliases: text(
            "diagnostics|diagnostic|trace|reasoning trace|show diagnostics",
            "диагностика|диагност|трассировка|trace",
            "diagnostics|निदान|trace",
            "诊断|trace|推理跟踪",
        ),
        examples: text("Turn on diagnostics", "Включи диагностику", "Turn on diagnostics", "Turn on diagnostics"),
    },
    FeatureCapability {
        slug: "agent_mode",
        state: FeatureState::AgentMode,
        labels: text("agent mode", "agent mode", "agent mode", "agent mode"),
        aliases: text("agent mode|agent|multi-step|autonomous", "agent mode|агент|многошаг|автоном", "agent mode|एजेंट|multi-step", "agent mode|代理|多步骤"),
        examples: text("Turn on agent mode", "Включи agent mode", "Turn on agent mode", "Turn on agent mode"),
    },
    FeatureCapability {
        slug: "definition_fusion",
        state: FeatureState::DefinitionFusion,
        labels: text("automatic definition fusion", "автоматическое слияние определений", "automatic definition fusion", "自动 definition fusion"),
        aliases: text("definition fusion|merge definitions|automatic definition", "слияние определений|объединение определений", "definition fusion|merge definitions", "definition fusion|合并定义"),
        examples: text("Turn on definition fusion", "Включи слияние определений", "Turn on definition fusion", "Turn on definition fusion"),
    },
    FeatureCapability {
        slug: "configuration",
        state: FeatureState::Always,
        labels: text("message-driven configuration", "настройка через сообщения", "message-driven configuration", "消息配置"),
        aliases: text("settings|configuration|configure settings|theme|language|chat style", "настройки|настройка|конфигурация|тема|язык|стиль чата|оформление", "settings|configuration|theme|language|सेटिंग", "设置|配置|主题|语言|聊天样式"),
        examples: text("Switch to dark theme", "Включи темную тему", "Switch to dark theme", "Switch to dark theme"),
    },
    FeatureCapability {
        slug: "memory_actions",
        state: FeatureState::Always,
        labels: text("memory import/export", "импорт и экспорт памяти", "memory import/export", "记忆导入/导出"),
        aliases: text("export memory|import memory|memory export|memory import", "экспорт памяти|импорт памяти|память экспорт|память импорт", "memory export|memory import|स्मृति निर्यात|स्मृति आयात", "导出记忆|导入记忆|memory export|memory import"),
        examples: text("Export memory", "Экспортируй память", "Export memory", "Export memory"),
    },
    FeatureCapability {
        slug: "greeting",
        state: FeatureState::Always,
        labels: text("greetings", "приветствия", "अभिवादन", "问候"),
        aliases: text("greeting|greetings|say hello|respond to hello", "приветствие|приветствия|здороваться|привет", "अभिवादन|नमस्ते|hello", "问候|打招呼|你好"),
        examples: text("Hi", "Привет", "नमस्ते", "你好"),
    },
    FeatureCapability {
        slug: "hello_world",
        state: FeatureState::Always,
        labels: text("Hello World code generation", "генерация Hello World", "Hello World code generation", "Hello World 代码生成"),
        aliases: text("hello world|write code|generate code|program", "hello world|код|программу|программа", "hello world|code|program|प्रोग्राम", "hello world|代码|程序"),
        examples: text("Write hello world in Rust", "Напиши hello world на Rust", "Write hello world in Rust", "Write hello world in Rust"),
    },
    FeatureCapability {
        slug: "concept_lookup",
        state: FeatureState::Always,
        labels: text("concept lookup", "поиск понятий", "concept lookup", "概念查找"),
        aliases: text("concept lookup|concept|wikipedia lookup", "поиск понятий|понятие", "concept|अवधारणा", "概念"),
        examples: text("What is Wikipedia?", "Что такое Википедия?", "विकिपीडिया क्या है?", "维基百科是什么?"),
    },
    FeatureCapability {
        slug: "arithmetic",
        state: FeatureState::Always,
        labels: text("arithmetic", "арифметика", "अंकगणित", "算术"),
        aliases: text("arithmetic|calculate|math|2 + 2", "арифмет|считать|посчитать|2 + 2", "अंकगणित|गणना|math|2 + 2", "算术|计算|数学|2 + 2"),
        examples: text("What is 2 + 2?", "Сколько будет 2 + 2?", "2 + 2 क्या है?", "2 + 2 等于多少?"),
    },
    FeatureCapability {
        slug: "translation",
        state: FeatureState::Always,
        labels: text("translation", "перевод", "अनुवाद", "翻译"),
        aliases: text("translation|translate|language translation", "перевод|переводить|перевести", "अनुवाद|translate|translation", "翻译|translation|translate"),
        examples: text("Translate hello to Russian", "Переведи hello на русский", "Translate hello to Russian", "Translate hello to Russian"),
    },
    FeatureCapability {
        slug: "memory",
        state: FeatureState::Always,
        labels: text("conversation memory", "память разговора", "conversation memory", "会话记忆"),
        aliases: text("memory|remember|recall|conversation context", "память|помнить|запомнить|контекст", "स्मृति|याद|memory|context", "记忆|记住|回忆|上下文"),
        examples: text("Remember my name is Ada", "Запомни, меня зовут Ада", "Remember my name is Ada", "Remember my name is Ada"),
    },
    FeatureCapability {
        slug: "demo_mode",
        state: FeatureState::Always,
        labels: text("demo mode", "демо-режим", "demo mode", "演示模式"),
        aliases: text("demo mode|demo|scripted demo", "демо|демо-режим|сценарный демо", "demo|डेमो", "demo|演示"),
        examples: text("Turn off demo mode", "Выключи демо", "Turn off demo mode", "Turn off demo mode"),
    },
    FeatureCapability {
        slug: "http_url",
        state: FeatureState::Always,
        labels: text("URL navigation and HTTP fetch", "URL-навигация и HTTP-запросы", "URL navigation and HTTP fetch", "URL 导航和 HTTP 请求"),
        aliases: text("http fetch|fetch url|open url|navigate to url|visit url", "http запрос|открыть url|перейти на|сделать запрос", "http fetch|url|navigate", "http fetch|url|打开链接|访问链接"),
        examples: text("Navigate to github.com", "Сделай запрос к google.com", "Navigate to github.com", "Navigate to github.com"),
    },
    FeatureCapability {
        slug: "javascript_execution",
        state: FeatureState::Always,
        labels: text("JavaScript execution", "выполнение JavaScript", "JavaScript execution", "JavaScript 执行"),
        aliases: text("javascript|run javascript|execute javascript|js", "javascript|js", "javascript|js", "javascript|js"),
        examples: text("Run JavaScript: 1 + 1", "Выполни JavaScript: 1 + 1", "Run JavaScript: 1 + 1", "Run JavaScript: 1 + 1"),
    },
    FeatureCapability {
        slug: "planning",
        state: FeatureState::Always,
        labels: text("summaries, brainstorming, roleplay, and project planning", "резюме, брейншторминг, роли и планирование проектов", "summaries, brainstorming, roleplay, and project planning", "总结、头脑风暴、角色扮演和项目计划"),
        aliases: text("summarize|brainstorm|roleplay|software project|project plan", "резюмировать|брейншторм|роль|проект|план проекта", "summary|brainstorm|roleplay|project plan", "总结|头脑风暴|角色扮演|项目计划"),
        examples: text("Brainstorm 5 project ideas", "Предложи 5 идей проекта", "Brainstorm 5 project ideas", "Brainstorm 5 project ideas"),
    },
];

fn web_search_capability_body(language: &str, available: bool, providers: &str) -> String {
    match (language, available) {
        ("ru", true) => format!(
            "Да. В этой конфигурации веб-поиск включен: я могу использовать \
             DuckDuckGo Instant Answer по умолчанию и доступные CORS-провайдеры \
             (`{providers}`) для явных запросов вроде `Найди в интернете Никола Тесла`. \
             Результаты из top-10 по каждому провайдеру объединяются через reciprocal \
             rank fusion (k = {WEB_SEARCH_RRF_K}). Если провайдеры отключены или \
             заблокированы в браузерной сессии, я сообщу об этом вместо ответа \"да\"."
        ),
        ("ru", false) => String::from(
            "Нет. В этой конфигурации веб-поиск отключен offline-режимом или нет \
             доступных поисковых провайдеров. Я могу отвечать по локальным правилам \
             и кэшу, но не буду обращаться к поисковым системам.",
        ),
        ("zh", true) => format!(
            "可以。当前配置启用了 web search:我会默认使用 DuckDuckGo Instant Answer,\
             并可使用这些 CORS-readable provider(`{providers}`)处理明确的搜索请求,\
             例如 `Search the web for Nikola Tesla`。每个 provider 的 top-10 结果会用 \
             reciprocal rank fusion 合并(k = {WEB_SEARCH_RRF_K})。如果浏览器会话中所有 \
             provider 被禁用或阻止,我会说明不可用,而不是回答可以。"
        ),
        ("zh", false) => String::from(
            "不可以。当前配置的 offline 模式禁用了 web search,或者没有可用的搜索 \
             provider。我仍可使用本地规则和缓存回答,但不会调用搜索引擎。",
        ),
        ("hi", true) => format!(
            "हाँ। इस configuration में web search enabled है: मैं default रूप से \
             DuckDuckGo Instant Answer और उपलब्ध CORS-readable providers (`{providers}`) \
             का उपयोग explicit prompts जैसे `Search the web for Nikola Tesla` के लिए \
             कर सकता हूँ। हर provider के top-10 results reciprocal rank fusion \
             (k = {WEB_SEARCH_RRF_K}) से merge होते हैं। अगर browser session में providers \
             disabled या blocked हों, तो मैं \"हाँ\" कहने के बजाय स्थिति बताऊँगा।"
        ),
        ("hi", false) => String::from(
            "नहीं। इस configuration में offline mode या missing providers के कारण web \
             search disabled है। मैं local rules और cache से जवाब दे सकता हूँ, लेकिन \
             search engines को call नहीं करूँगा।",
        ),
        (_, true) => format!(
            "Yes. Web search is enabled in this configuration: I can use DuckDuckGo \
             Instant Answer by default plus the configured CORS-readable providers \
             (`{providers}`) for explicit prompts such as `Search the web for Nikola Tesla`. \
             The top-10 results from each provider are merged with reciprocal rank fusion \
             (k = {WEB_SEARCH_RRF_K}). If the browser session disables or blocks every \
             provider, I will say that instead of claiming search is available."
        ),
        (_, false) => String::from(
            "No. Web search is disabled by this configuration's offline mode or there \
             are no configured search providers. I can still answer from local rules \
             and cache, but I will not call search engines.",
        ),
    }
}