"""Static-asset smoke tests for onboarding-aware WebUI views.""" from pathlib import Path ROOT = Path(__file__).resolve().parents[2] / "src/opensquilla/gateway" VIEWS = ROOT / "static/js/views" TEMPLATE = ROOT / "templates/index.html" APP = ROOT / "static/js/app.js" VUE_WEB_ROUTES = Path("opensquilla-webui/src/router/webRoutes.ts") VUE_SETTINGS_VIEW = Path("opensquilla-webui/src/views/web/SettingsView.vue") def test_channels_view_is_read_only_status_surface(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") assert "channels.status" in txt assert "onboarding.catalog" not in txt assert "onboarding.channel.upsert" not in txt assert "onboarding.channel.remove" not in txt assert "onboarding.channel.enable" not in txt assert "onboarding.channel.disable" not in txt assert "Add channel" not in txt assert "Save channel" not in txt assert "data-ch-remove" not in txt assert "data-ch-toggle" not in txt assert "data-ch-logout" not in txt assert "channels.logout" not in txt assert "channels.restart" not in txt def test_channels_view_points_configuration_to_cli_onboarding(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") assert "opensquilla channels list" in txt assert "opensquilla onboard configure channels" in txt def test_channels_stats_do_not_report_attention_states_as_healthy(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") assert "all healthy" not in txt assert "need attention" in txt assert "restarting" in txt assert "exhausted" in txt def test_channels_view_filters_to_configured_channels(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") assert "configured !== false" in txt def test_channels_load_stops_if_view_is_destroyed_while_waiting_for_rpc(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") start = txt.index("async function _loadData()") end = txt.index(" function _renderStats", start) body = txt[start:end] assert "const rpc = _rpc;" in body assert "await rpc.waitForConnection();" in body assert "if (!_el || _rpc !== rpc) return;" in body def test_setup_view_loads_catalog_and_status(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "onboarding.catalog" in txt assert "onboarding.status" in txt assert "config.get" in txt assert "onboarding.provider.configure" in txt assert "onboarding.search.configure" in txt assert "onboarding.imageGeneration.configure" in txt assert "onboarding.audio.configure" in txt assert "imageGenerationProviders" in txt assert "audioProviders" in txt assert "onboarding.memory_embedding.configure" in txt assert "Fallback API key" in txt assert "data-memory-api-key-label" in txt assert "effectiveProvider" in txt assert "current.mode" in txt def test_setup_view_is_available_and_uses_canonical_cli_fallbacks(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "SETUP_UI_AVAILABLE" not in txt assert "opensquilla onboard" in txt assert "opensquilla onboard catalog providers" in txt assert "opensquilla providers configure" not in txt assert "onboarding.router.configure" in txt assert "onboarding.channel.probe" in txt assert "channels.status" in txt assert "Connected" in txt def test_setup_view_locks_image_model_image_support(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "const isImageModel = name === 'image_model';" in txt assert "isImageModel ? ' checked disabled' :" in txt assert "tier.supportsImage = true;" in txt assert "tier.image_only = true;" in txt def test_setup_finish_cli_commands_target_active_config_path(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderReadinessSummary", start) body = txt[start:end] assert "const configArg = _configCliArg(_status.configPath)" in body assert "function _configCliArg" in txt assert "function _shellArg" in txt assert "Guided CLI" in body assert "`opensquilla onboard --if-needed${configArg}`" in body assert "Check status" in body assert "`opensquilla onboard status${configArg}`" in body assert "Provider options" in body assert "`opensquilla onboard catalog providers${configArg}`" in body assert "Router tiers" in body assert "`opensquilla onboard catalog router${configArg}`" in body assert "Search options" in body assert "`opensquilla onboard catalog search${configArg}`" in body assert "Channel options" in body assert "`opensquilla onboard catalog channels${configArg}`" in body assert "Image options" in body assert "`opensquilla onboard catalog image${configArg}`" in body assert "Memory options" in body assert "`opensquilla onboard catalog memory${configArg}`" in body assert "Catalog overview" not in body assert "`opensquilla onboard catalog${configArg}`" not in body assert "Channel field guide" not in body assert "opensquilla channels describe " not in body assert "" not in body assert "const envRecoveryCommands = Array.isArray(_status.envRecoveryCommands)" in body assert "const fixCommands = _envFixCommands(envRecoveryCommands, configArg)" in body assert "const handoffCommands = [" in body assert "const recipeCommands = [" in body assert "_renderCliCommandGroup('Fix now', fixCommands)" in body assert "_renderCliCommandGroup('CLI handoff', handoffCommands)" in body assert "_renderCliCommandGroup('CLI recipes', recipeCommands)" in body def test_setup_finish_groups_recovery_commands_before_cli_reference(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderCliCommand", start) body = txt[start:end] assert "const fixCommands = _envFixCommands(envRecoveryCommands, configArg)" in body assert "const handoffCommands = [" in body assert "const recipeCommands = [" in body assert "Fix now" in body assert "CLI handoff" in body assert "CLI recipes" in body assert ( "_renderCliCommandGroup('Fix now', fixCommands)" in body ) assert ( "_renderCliCommandGroup('CLI handoff', handoffCommands)" in body ) assert ( "_renderCliCommandGroup('CLI recipes', recipeCommands)" in body ) assert body.index("_renderCliCommandGroup('Fix now'") < body.index( "_renderCliCommandGroup('CLI handoff'" ) assert body.index("_renderCliCommandGroup('CLI handoff'") < body.index( "_renderCliCommandGroup('CLI recipes'" ) assert "function _renderCliCommandGroup" in txt assert "setup-cli__group" in txt assert ".setup-cli__group" in css assert ".setup-cli__group-head" in css def test_setup_finish_prioritizes_cli_actions_before_configuration_details(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderCliCommand", start) body = txt[start:end] assert body.index('
') < body.index('
') assert body.index('
') < body.index("_renderReadinessSummary()") def test_setup_finish_pairs_env_recovery_with_gateway_restart_command(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderReadinessSummary", start) body = txt[start:end] assert "const fixCommands = _envFixCommands(envRecoveryCommands, configArg)" in body assert "function _envFixCommands" in txt assert "if (!envRecoveryCommands.length) return [];" in txt assert "label: 'Restart gateway after env fix'" in txt assert "command: `opensquilla gateway restart${configArg}`" in txt assert body.index("const envRecoveryCommands = Array.isArray") < body.index( "const fixCommands = _envFixCommands(envRecoveryCommands, configArg)" ) def test_setup_finish_cli_commands_are_provider_neutral(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderReadinessSummary", start) body = txt[start:end] assert "opensquilla onboard catalog providers" in body assert "opensquilla onboard catalog search" in body assert "opensquilla onboard catalog image" in body assert "opensquilla onboard catalog memory" in body assert "--search-provider " not in body assert "--image-provider " not in body assert "--memory-provider " not in body assert "--api-key-env " not in body assert "--search-provider brave" not in body assert "--image-provider openrouter" not in body assert "--memory-provider openai" not in body assert "OPENAI_API_KEY" not in body assert "BRAVE_SEARCH_API_KEY" not in body def test_setup_view_starts_on_most_relevant_step(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") render_start = txt.index("async function render(el)") render_end = txt.index(" async function _load()", render_start) render_body = txt[render_start:render_end] destroy_start = txt.index("function destroy()") destroy_body = txt[destroy_start:] assert "let _hasAutoSelectedStep = false" in txt assert "function _selectInitialStep()" in txt assert "function _initialStepFromStatus()" in txt assert "await _load();\n _selectInitialStep();" in render_body assert render_body.index("await _load();") < render_body.index("_selectInitialStep();") assert txt.index("const entry = sectionSteps.find") < txt.index( "if (_status.needsOnboarding === false) return 'finish';" ) assert "if (_status.needsOnboarding === false) return 'finish';" in txt assert "detail.actionRequired" in txt assert "['llm', 'provider']" in txt assert "['router', 'router']" in txt assert "['search', 'extras']" in txt assert "['image_generation', 'extras']" in txt assert "['audio', 'extras']" in txt assert "['memory_embedding', 'extras']" in txt assert "_step = 'provider';" in destroy_body assert "_hasAutoSelectedStep = false;" in destroy_body def test_setup_header_tracks_optional_action_required_sections(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") draw_start = txt.index("function _draw()") draw_end = txt.index(" function _renderOnboardingReasons()", draw_start) draw_body = txt[draw_start:draw_end] reasons_start = txt.index("function _onboardingReasons()") reasons_end = txt.index(" function _renderCurrentStep()", reasons_start) reasons_body = txt[reasons_start:reasons_end] assert "function _hasSetupAction()" in txt assert "const setupAction = _hasSetupAction();" in draw_body assert "${setupAction ? 'Action needed' : 'Ready to run'}" in draw_body assert "setup__status ${setupAction ? 'is-warn' : 'is-ok'}" in draw_body assert "${setupAction ? 'Action needed' : 'Ready'}" in draw_body assert "if (!_hasSetupAction()) return [];" in reasons_body assert "if (!detail.blocking && !detail.actionRequired)" in reasons_body def test_setup_finish_summarizes_provider_proxy_only_when_present(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderReadinessSummary", start) body = txt[start:end] assert ( "const providerProxy = configuredProvider " "? ((_config.llm || {}).proxy || '').trim() : ''" ) in body assert "providerProxy ?" in body assert "Proxy" in body def test_setup_finish_cli_commands_are_copyable(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") assert "function _renderCliCommand" in txt assert "const copyLabel = `Copy ${label} command`" in txt assert "data-setup-copy-command" in txt assert 'title="${_esc(copyLabel)}"' in txt assert 'aria-label="${_esc(copyLabel)}"' in txt assert 'title="Copy command"' not in txt assert 'aria-label="Copy command"' not in txt assert "navigator.clipboard.writeText" in txt assert "Copied command" in txt assert "setup-cli__copy" in txt assert "setup-cli__label" in txt assert "${icons.copy()}" in txt assert ".setup-cli__copy" in css assert ".setup-cli__label" in css def test_setup_finish_cli_commands_stack_labels_on_mobile(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") mobile = css.split("@media (max-width: 560px)", 1)[1] assert ".setup-cli__row" in mobile assert "grid-template-columns: minmax(0, 1fr) 34px" in mobile assert ".setup-cli__label" in mobile assert "grid-column: 1 / -1" in mobile def test_setup_view_keeps_channel_fields_in_config_shape(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "scope === 'channel' ? label.dataset.name : _camel" in txt def test_setup_view_renders_catalog_field_descriptions(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "field.description" in txt assert "setup-field-desc" in txt def test_setup_view_surfaces_catalog_requirements_before_fields(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _renderNeedList" in txt assert "setup-need-list" in txt assert "spec.whatYouNeed" in txt assert "searchSpec.whatYouNeed" in txt assert "_memoryNeedList(memorySpec" in txt assert "imageSpec.whatYouNeed" in txt assert "channelSpec.whatYouNeed" in txt def test_setup_view_ties_need_lists_to_selected_env_keys(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _credentialNeedList" in txt assert "_credentialNeedList(searchSpec.whatYouNeed, searchEnv || searchSpec.envKey)" in txt assert "_credentialNeedList(imageSpec.whatYouNeed, imageEnv || imageSpec.envKey)" in txt assert "envInput.value = spec.requiresApiKey ? (spec.envKey || '') : ''" in txt assert "_credentialNeedList(spec.whatYouNeed, envInput?.value || spec.envKey)" in txt def test_setup_provider_step_is_neutral_before_provider_choice(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") start = txt.index("function _renderProviderStep()") end = txt.index(" function _providerConfigFor", start) body = txt[start:end] sync_start = txt.index("function _drawProviderFields") sync_end = txt.index(" function _drawChannelFields", sync_start) sync_body = txt[sync_start:sync_end] save_start = txt.index("async function _saveProvider()") save_end = txt.index(" async function _saveRouter()", save_start) save_body = txt[save_start:save_end] assert "const selected = _effectiveProvider();" in body assert "Choose from ${providers.length} supported providers" in body assert ( '" ) in body assert "const spec = selected ? providers.find" in body assert "selected ? spec.whatYouNeed : ['Choose a provider to see required fields.']" in body assert "data-save-provider${selected ? '' : ' disabled'}" in body assert 'data-next="router"${selected ? \'\' : \' disabled\'}' in body assert "saveButton.disabled = !providerId" in sync_body assert 'const nextButton = _el.querySelector(\'[data-next="router"]\')' in sync_body assert "if (nextButton) nextButton.disabled = !providerId" in sync_body assert "if (!providerId)" in save_body assert "Choose a provider before saving." in save_body assert ".setup-btn:disabled" in css assert "cursor: not-allowed" in css def test_setup_view_declutters_memory_auto_requirements(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _memoryNeedList" in txt assert "_memoryNeedList(memorySpec, effectiveProvider, memoryEnv)" in txt assert "!/remote fallback credentials/i.test(item)" in txt def test_setup_view_collapses_search_advanced_options_by_default(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "const searchAdvancedOpen" in txt assert 'details class="setup-mini__advanced" data-search-advanced${searchAdvancedOpen}' in txt assert "Advanced search options" in txt assert "setup-mini__advanced-body" in txt assert "searchFallbackPolicy !== 'off'" in txt assert "setup_search_proxy" in txt def test_setup_view_collapses_provider_connection_options_by_default(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "const providerCoreFields" in txt assert "const providerAdvancedFields" in txt assert "const providerAdvancedOpen" in txt assert "_isProviderAdvancedField(field, spec)" in txt assert ( "_renderProviderAdvancedFields(providerAdvancedFields, values, providerAdvancedOpen)" in txt ) assert 'details class="setup-mini__advanced" data-provider-advanced${openAttr}' in txt assert "Advanced provider connection" in txt assert "setup-provider-fields" in txt assert "Provider connection" in txt assert "base_url" in txt assert "proxy" in txt def test_setup_provider_advanced_opens_for_required_or_custom_connection(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _providerAdvancedOpen" in txt assert "if (field.required) return true;" in txt assert "value !== defaultValue" in txt assert "return value.length > 0;" in txt def test_setup_view_moves_optional_router_model_into_provider_advanced_connection(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "_isProviderAdvancedField(field, spec)" in txt assert "field.name === 'model'" in txt assert "spec.routerSupported === true" in txt assert "field.required !== true" in txt assert ( "providerCoreFields = providerFields.filter(field => " "!_isProviderAdvancedField(field, spec))" ) in txt assert ( "providerAdvancedFields = providerFields.filter(field => " "_isProviderAdvancedField(field, spec))" ) in txt assert "if (defaultValue) return value !== defaultValue;" in txt def test_setup_view_keeps_required_provider_model_in_core_fields(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") model_start = txt.index("if (field.name === 'model')") model_clause = txt[model_start : txt.index("return false;", model_start)] assert "field.required !== true" in model_clause assert "spec.routerSupported === true" in model_clause def test_setup_provider_switch_redraws_core_and_advanced_fields_together(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _drawProviderFields") body = txt[start : txt.index(" function _drawChannelFields", start)] assert "const providerFields = spec.fields || []" in body assert "const providerCoreFields" in body assert "const providerAdvancedFields" in body assert "box.innerHTML = _renderProviderFields(providerCoreFields" in body assert "advanced.innerHTML = _renderProviderAdvancedFields(" in body assert "_renderProviderFields(spec," not in body def test_setup_view_warns_when_env_key_is_not_visible_to_gateway(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") assert "missing_env" in txt assert "not visible to this gateway process" in txt assert "Set it before starting or restarting the gateway" in txt assert "if (_providerEnvMissing())" in txt assert "function _providerEnvRecoveryCommand()" in txt assert "Array.isArray(_status.envRecoveryCommands)" in txt assert "return _envRecoveryCommand('llm')" in txt assert "_providerEnvRecoveryCommand()" in txt assert "setup-warning__command" in txt assert 'data-setup-copy-command="${safeCommand}"' in txt assert "Copy set provider key command" in txt assert ".setup-warning__command" in css assert ".setup-warning__command code" in css def test_setup_view_does_not_default_env_key_over_stored_provider_key(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "current.api_key ? '' : field.default" in txt def test_setup_provider_form_can_submit_api_key_env(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "api_key_env" in txt assert "_camel(label.dataset.name)" in txt assert "onboarding.provider.configure" in txt def test_setup_provider_controls_have_browser_field_names(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert 'name="setup_provider"' in txt assert "const fieldName = `setup_${scope}_${rawName}`" in txt assert 'for="${_esc(fieldId)}"' in txt assert 'id="${_esc(fieldId)}"' in txt assert 'name="${_esc(fieldName)}"' in txt def test_setup_provider_switch_refreshes_provider_defaults(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _providerConfigFor(providerId)" in txt assert "current.provider === providerId ? current : {}" in txt assert 'data-provider-summary' in txt assert "_drawProviderFields({ rememberDraft: true })" in txt def test_setup_all_wizard_controls_have_browser_field_names(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") for name in ( "setup_router_mode", "setup_router_default_tier", "setup_channel_type", "setup_search_provider", "setup_search_max_results", "setup_search_api_key", "setup_search_api_key_env", "setup_search_proxy", "setup_search_use_env_proxy", "setup_search_fallback_policy", "setup_search_diagnostics", "setup_memory_provider", "setup_memory_model", "setup_memory_api_key", "setup_memory_api_key_env", "setup_memory_base_url", "setup_memory_onnx_dir", "setup_image_provider", "setup_image_primary", "setup_image_api_key", "setup_image_api_key_env", "setup_image_base_url", "setup_image_enabled", ): assert f'name="{name}"' in txt assert "const tierFieldName = `setup_router_${name}_${field}`" in txt assert 'name="${_esc(tierFieldName)}"' in txt assert 'aria-label="${_esc(tierLabel)}' in txt def test_setup_view_bounds_search_max_results_control(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index('id="setup-search-max-results"') end = txt.index('data-search-field="max_results"', start) control = txt[start:end] assert 'type="number"' in control assert 'min="1"' in control assert 'step="1"' in control assert 'inputmode="numeric"' in control def test_setup_view_preserves_selected_channel_type_while_redrawing_fields(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "let _channelType" in txt assert "_channelType = type" in txt assert "channels.some(c => c.type === _channelType)" in txt def test_setup_view_rebinds_conditional_fields_after_dynamic_redraw(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _bindConditionalSelects" in txt assert "_bindConditionalSelects(_el)" in txt assert "_bindConditionalSelects(box || _el)" in txt def test_setup_view_is_loaded_and_registered_but_not_sidebar_primary(): app = APP.read_text(encoding="utf-8") web_routes = VUE_WEB_ROUTES.read_text(encoding="utf-8") # Legacy static onboarding UI still registers the Setup view at /setup. assert "_renderStandardView(SetupView, el)" in app assert "Router.register('/setup'" in app assert 'data-path="/setup"' not in app # The Vue console consolidated setup into SettingsView: /settings renders it, # and the legacy /setup deep link redirects into the settings overlay rather # than registering a primary sidebar destination. assert "SettingsView.vue" in web_routes assert "path: '/settings'" in web_routes assert "name: 'settings'" in web_routes assert "redirect: '/settings/auto'" in web_routes assert VUE_SETTINGS_VIEW.exists() def test_setup_view_marks_unsupported_providers_disabled(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "runtimeSupported" in txt def test_setup_view_validates_visible_required_channel_fields_before_save(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _saveChannel()") end = txt.index(" async function _saveMemory()", start) body = txt[start:end] assert 'data-required="${field.required ? \'true\' : \'false\'}"' in txt assert "function _validateScopedRequiredFields(scope)" in txt assert "function _canKeepExistingSecret(scope)" in txt assert "input.dataset.secret === 'true' && _canKeepExistingSecret(scope)" in txt assert "row.configured !== false" in txt assert "String(row.type || '') === String(type)" in txt assert "String(row.name || '') === String(name).trim()" in txt assert "_validateScopedRequiredFields('channel')" in body assert "if (missing)" in body assert "is required." in body assert "return;" in body def test_setup_view_treats_image_configure_as_capability_enable_action(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "field.default !== false" in txt assert "imageGenerationEnabled === false" in txt def test_setup_view_explains_image_generation_tool_visibility(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _imageGenerationStatusText") end = txt.index(" function _memoryEmbeddingStatusText", start) body = txt[start:end] assert "Image generation is hidden from agents" in body assert "Image generation will be available in new turns" in body assert "_status.imageGenerationSource === 'missing_env'" in body assert "_status.imageGenerationEnvKey" in body assert "image_generate" not in body assert "imageGenerationSource === 'llm_fallback'" in txt assert "same provider key" in txt def test_setup_view_uses_product_language_for_search_status_text(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _searchStatusText") end = txt.index(" function _imageGenerationStatusText", start) body = txt[start:end] assert "Web search is off until a provider is selected." in body assert "Web search is ready for new turns." in body assert "_status.searchSource === 'missing_env'" in body assert "_status.searchEnvKey" in body assert "Web search is selected but still needs a visible provider key." in body assert "web_search" not in body def test_setup_view_names_missing_env_key_for_memory_embedding_status_text(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _memoryEmbeddingStatusText") end = txt.index(" function _toastEnvReferenceSave", start) body = txt[start:end] assert "_status.memoryEmbeddingSource === 'missing_env'" in body assert "_status.memoryEmbeddingEnvKey" in body assert "Remote memory embeddings need a visible provider key before they can run." in body def test_setup_capability_cards_offer_copyable_env_recovery_commands(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderExtrasStep()") end = txt.index(" function _capabilitySaveButtonClass", start) body = txt[start:end] assert "function _capabilityEnvRecoveryCommand(section)" in txt assert "function _renderCapabilityEnvRecoveryCommand(section)" in txt assert "Array.isArray(_status.envRecoveryCommands)" in txt assert "entry.section === section" in txt assert "_renderCapabilityEnvRecoveryCommand('search')" in body assert "_renderCapabilityEnvRecoveryCommand('memory_embedding')" in body assert "_renderCapabilityEnvRecoveryCommand('image_generation')" in body assert "_renderCapabilityEnvRecoveryCommand('audio')" in body assert "Copy set search key command" in txt assert "Copy set memory key command" in txt assert "Copy set image key command" in txt assert "Copy set audio key command" in txt assert 'data-setup-copy-command="${safeCommand}"' in txt def test_setup_view_exposes_image_generation_env_key_config(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "imageProviders.find(p => p.providerId === imageProviderSelected)" in txt assert "imageProviderConfig.api_key_env" in txt assert 'data-image-field="api_key_env"' in txt assert "setup_image_api_key_env" in txt assert "imageSpec.envKey" in txt assert "_syncImageProviderDefaults" in txt assert "[data-image-provider]')?.addEventListener('change', _syncImageProviderDefaults)" in txt assert "primaryInput.value = spec.defaultModel || primaryInput.value" in txt def test_setup_view_exposes_audio_provider_config(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "audioProviders.find(p => p.providerId === audioProviderSelected)" in txt assert "audioProviderConfig.api_key_env" in txt assert 'data-audio-field="api_key_env"' in txt assert 'data-audio-field="tts_voice"' in txt assert 'data-audio-field="tts_model"' in txt assert 'data-audio-field="language_code"' in txt assert "setup_audio_api_key_env" in txt assert "audioSpec.envKey" in txt assert "_syncAudioProviderDefaults" in txt assert "[data-audio-provider]')?.addEventListener('change', _syncAudioProviderDefaults)" in txt assert "const res = await _rpc.call('onboarding.audio.configure', params)" in txt def test_setup_image_generation_hides_provider_fields_until_enabled(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderExtrasStep()") end = txt.index(" function _capabilitySaveButtonClass", start) body = txt[start:end] assert "const imageConfigHidden = imageEnabledDefault ? '' : ' hidden'" in body assert 'data-image-config-fields${imageConfigHidden}' in body assert "[data-image-enabled]')?.addEventListener('change', _syncImageProviderDefaults)" in txt sync_start = txt.index("function _syncImageProviderDefaults()") sync_end = txt.index(" function _bindConditionalSelects", sync_start) sync_body = txt[sync_start:sync_end] assert "const enabledInput = _el.querySelector('[data-image-enabled]')" in sync_body assert "const imageConfigFields = _el.querySelector('[data-image-config-fields]')" in sync_body assert "imageConfigFields.hidden = !imageEnabled" in sync_body def test_setup_view_exposes_image_generation_base_url_config(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "imageProviderConfig.base_url" in txt assert "imageSpec.defaultBaseUrl" in txt assert 'data-image-field="base_url"' in txt assert "setup_image_base_url" in txt assert "baseInput.value = spec.defaultBaseUrl || baseInput.value" in txt def test_setup_view_preserves_selected_image_generation_provider(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "imageProviderSelected" in txt assert "imageGenerationProvider" in txt assert "imageGenerationPrimary || '').split('/')[0]" in txt def test_setup_router_controls_use_user_facing_labels(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "SquillaRouter" in txt assert "OpenRouter mix" not in txt assert "Route c1" in txt assert "Route c2" in txt def test_setup_view_preserves_unsaved_form_values_across_step_navigation(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "const _drafts" in txt assert "function _rememberDraft" in txt assert "function _restoreDraft" in txt assert "function _setStep" in txt assert "data-next" in txt assert "_setStep(btn.dataset.next)" in txt def test_setup_view_reconciles_search_key_state_after_restoring_draft_provider(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _restoreDynamicDraftFields()") end = txt.index(" function _fieldKey", start) body = txt[start:end] assert "function _syncSearchProviderKeyControls" in txt assert "if (_step === 'extras' && _drafts.has('extras'))" in body assert "_syncSearchProviderKeyControls({ refreshEnv: false })" in body def test_setup_view_does_not_redraw_dirty_channel_form_during_status_poll(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "let _channelDirty" in txt assert "data-channel-dirty-root" in txt assert "if (_channelDirty) return;" in txt def test_setup_view_surfaces_action_needed_reasons(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _onboardingReasons" in txt assert "setup-reasons" in txt assert "Connect a model provider" in txt assert "detail.status === 'missing'" in txt assert "Provider action required" not in txt assert "sectionDetails" in txt assert "detail.blocking" in txt assert "(_status.channelCount || 0) === 0" not in txt def test_setup_stepper_surfaces_readiness_for_each_setup_area(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") draw_start = txt.index("function _draw()") draw_end = txt.index(" function _renderOnboardingReasons()", draw_start) draw_body = txt[draw_start:draw_end] assert "STEPS.map(_renderStepButton).join('')" in draw_body assert "function _renderStepButton" in txt assert "function _stepStatus" in txt assert "function _aggregateStepStatus" in txt assert "setup-stepper__state" in txt assert "setup-stepper__label" in txt assert "setup-stepper__num" in txt assert ( "_aggregateStepStatus(['search', 'image_generation', 'audio', " "'memory_embedding'])" ) in txt assert "detail.blocking || detail.actionRequired" in txt assert "detail.status === 'missing' || detail.status === 'degraded'" in txt assert "aria-label=\"${_esc(`${s.label}: ${status.label}`)}\"" in txt assert ".setup-stepper__state" in css assert ".setup-stepper__state.is-ok" in css assert ".setup-stepper__state.is-warn" in css assert ".setup-stepper__label" in css def test_setup_stepper_names_router_provider_prerequisite(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _stepStatus") body = txt[start : txt.index(" function _aggregateStepStatus", start)] assert "if (stepId === 'router' && !_effectiveProvider())" in body assert "Provider first" in body def test_setup_header_reasons_name_missing_env_keys_for_capabilities(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _onboardingReasons()") end = txt.index(" function _hasSetupAction()", start) body = txt[start:end] assert "function _setupActionReason" in txt assert "const missingEnvPrefix = 'env key not visible: '" in txt assert "return `${envKey} is not visible`" in txt assert "_setupActionReason(name, detail)" in body assert "Memory embedding setup needed" not in body def test_setup_provider_first_run_summary_does_not_headline_default_provider(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderProviderStep()") end = txt.index(" function _providerConfigFor", start) body = txt[start:end] assert "const selected = _effectiveProvider();" in body assert ( "const providerSummary = selected\n" " ? (spec.label || selected)\n" " : `Choose from ${providers.length} supported providers`" ) in body assert '

${_esc(providerSummary)}

' in body assert '

${_esc(selected || \'not configured\')}

' not in body def test_setup_provider_step_surfaces_squillarouter_tier_support(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderProviderStep()") end = txt.index(" function _providerConfigFor", start) body = txt[start:end] sync_start = txt.index("function _drawProviderFields") sync_end = txt.index(" function _drawChannelFields", sync_start) sync_body = txt[sync_start:sync_end] assert "function _providerRouterSupportText" in txt assert "function _providerRouterSupportTone" in txt assert "spec.routerSupported === true" in txt assert "'SquillaRouter ready'" in txt assert "'Direct only'" in txt assert "'available'" not in body assert "'direct model only'" not in body assert "data-provider-router-support" in body assert "data-provider-router-support-label" in body assert "setup-provider-meta__badge" in body assert "SquillaRouter tiers" in body assert "_providerRouterSupportText(selected ? spec : null)" in body assert "_providerRouterSupportTone(selected ? spec : null)" in body assert "routerSupport.textContent = _providerRouterSupportText(spec);" in sync_body assert "routerSupport.className = `setup-provider-meta__badge" in sync_body assert "_providerRouterSupportTone(spec)" in sync_body def test_setup_provider_router_support_badge_has_distinct_tones(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") assert ".setup-provider-meta__badge" in css assert ".setup-provider-meta__badge.is-ready" in css assert ".setup-provider-meta__badge.is-direct" in css assert ".setup-provider-meta__badge.is-neutral" in css def test_setup_provider_switch_summary_uses_provider_label(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _drawProviderFields") end = txt.index(" function _drawChannelFields", start) body = txt[start:end] assert "summary.textContent = spec.label || providerId || 'not configured';" in body def test_setup_router_step_uses_effective_provider_without_hardcoded_fallback(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderRouterStep()") end = txt.index(" function _tierRow", start) body = txt[start:end] assert "const provider = _effectiveProvider();" in body assert "const canSaveRouter = provider && provider === _configuredProvider();" in body assert "const routerSummary = provider" in body assert "'Choose a provider first'" in body assert "profiles.find(p => p.profileId === 'openrouter')" not in body assert "const tiers = provider ?" in body assert "data-router-provider-needed" in body assert "data-router-provider-unsaved" in body assert "data-save-router${saveDisabled}" in body save_start = txt.index("async function _saveRouter()") save_end = txt.index(" async function _saveChannel()", save_start) save_body = txt[save_start:save_end] assert "const provider = _effectiveProvider();" in save_body assert "const configuredProvider = _configuredProvider();" in save_body assert "Choose a provider before saving router tiers." in save_body assert "Save the provider before saving router tiers." in save_body def test_setup_effective_provider_accepts_runtime_config_but_not_bare_defaults(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _configuredProvider()") end = txt.index(" function _renderProviderFields", start) body = txt[start:end] assert "if (_status.hasConfig !== false) return provider;" in body assert "if (_status.llmConfigured === true) return provider;" in body assert "['explicit', 'env', 'not_required'].includes(_status.llmSource)" in body assert "providerDraft['provider:selected']" in body assert "return (includeDraft ? _draftProvider() : '') || _configuredProvider();" in body def test_setup_view_exposes_search_in_capability_center(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "Capability Center" in txt assert "label: 'Capabilities'" in txt assert "label: 'Extras'" not in txt assert "function _renderCapabilityBadge" in txt assert "setup-badge" in txt assert "data-search-provider" in txt assert "data-save-search" in txt assert "_syncSearchProviderEnvHint" in txt def test_setup_capability_center_names_each_capability_action(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderExtrasStep()") end = txt.index(" function _capabilitySaveButtonClass", start) body = txt[start:end] assert "Web search · Memory recall · Image generation" in body assert "search / memory / image" not in body assert "Save web search" in body assert "Save memory embedding" in body assert "Save image generation" in body assert "Save Memory" not in body assert "Save Image" not in body def test_setup_capability_save_buttons_prioritize_action_required_card(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _capabilitySaveButtonClass" in txt start = txt.index("function _capabilitySaveButtonClass") end = txt.index(" function _renderCapabilityBadge", start) body = txt[start:end] assert "detail.blocking || detail.actionRequired" in body assert "'setup-btn setup-btn--primary'" in body assert "'setup-btn'" in body assert 'class="${_capabilitySaveButtonClass(\'search\')}"' in txt assert 'class="${_capabilitySaveButtonClass(\'memory_embedding\')}"' in txt assert 'class="${_capabilitySaveButtonClass(\'image_generation\')}"' in txt def test_setup_view_exposes_all_search_configuration_controls(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") for name in ( "setup_search_proxy", "setup_search_use_env_proxy", "setup_search_fallback_policy", "setup_search_diagnostics", ): assert f'name="{name}"' in txt assert "_config.search_proxy" in txt assert "_config.search_use_env_proxy" in txt assert "_config.search_fallback_policy" in txt assert "_config.search_diagnostics" in txt assert 'data-search-field="proxy"' in txt assert 'data-search-field="use_env_proxy"' in txt assert 'data-search-field="fallback_policy"' in txt assert 'data-search-field="diagnostics"' in txt def test_setup_view_treats_search_provider_keys_as_conditional(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "searchSpec.requiresApiKey === true" in txt assert "searchRequiresKey ? '' : ' disabled'" in txt assert "not required for this provider" in txt assert "const searchKeyHidden = searchRequiresKey ? '' : ' hidden'" in txt assert 'data-search-key-fields${searchKeyHidden}' in txt assert "keyInput.disabled = !requiresKey" in txt assert "envInput.disabled = !requiresKey" in txt assert "keyFields.hidden = !requiresKey" in txt def test_setup_view_treats_memory_remote_fields_as_provider_conditional(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "memorySpec.requiresApiKey === true" in txt assert "memoryApiKeyEnabled" in txt assert "memoryRemoteControlEnabled" in txt assert "function _syncMemoryProviderControls" in txt assert ( "[data-memory-provider]')?.addEventListener('change', " "_syncMemoryProviderControls)" ) in txt assert "apiKeyInput.disabled = !apiKeyEnabled" in txt assert "envInput.disabled = !apiKeyEnabled" in txt assert "baseInput.disabled = !remoteControlEnabled" in txt assert "modelInput.disabled = !remoteControlEnabled" in txt assert "remoteOptions.hidden = !hasRemoteOptions" in txt assert "remoteOptions.open = providerId !== 'auto' && hasRemoteOptions" in txt assert 'data-memory-field="api_key_env"' in txt def test_setup_memory_embedding_exposes_local_onnx_dir_without_cluttering_auto(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderExtrasStep()") end = txt.index(" function _capabilitySaveButtonClass", start) body = txt[start:end] assert "const memoryLocal = current.local || {}" in body assert "const memoryLocalControlEnabled = effectiveProvider === 'local'" in body assert "const memoryRemoteOptionsSummary" in body assert "Remote fallback options" in body assert "Connection options" in body assert ( "data-memory-remote-options" "${memoryRemoteOptionsOpen}${memoryRemoteOptionsHidden}" ) in body assert 'data-memory-local-field${memoryLocalHidden}' in body assert 'name="setup_memory_onnx_dir"' in body assert 'data-memory-field="onnx_dir"' in body assert "memoryLocal.onnx_dir || ''" in body def test_setup_view_surfaces_env_reference_save_feedback(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") memory_start = txt.index("async function _saveMemory()") memory_end = txt.index(" async function _saveSearch()", memory_start) memory_body = txt[memory_start:memory_end] image_start = txt.index("async function _saveImage()") image_end = txt.index(" async function _saveAudio()", image_start) image_body = txt[image_start:image_end] audio_start = txt.index("async function _saveAudio()") audio_end = txt.index(" async function _loadChannelStatus()", audio_start) audio_body = txt[audio_start:audio_end] assert "function _toastEnvReferenceSave" in txt assert ( "const res = await _rpc.call('onboarding.memory_embedding.configure', params)" in memory_body ) assert "_toastEnvReferenceSave(" in memory_body assert "'Memory embedding'" in memory_body assert "remote.api_key_env" in memory_body assert "restartRequired" in memory_body assert ( "const res = await _rpc.call('onboarding.imageGeneration.configure', params)" in image_body ) assert "_toastEnvReferenceSave(" in image_body assert "'Image generation'" in image_body assert "entry.api_key_source" in image_body assert ( "const res = await _rpc.call('onboarding.audio.configure', params)" in audio_body ) assert "_toastEnvReferenceSave(" in audio_body assert "'Voice audio'" in audio_body assert "entry.api_key_source" in audio_body def test_setup_view_explains_memory_embedding_provider_modes(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _memoryEmbeddingStatusText" in txt assert 'data-memory-status-text' in txt assert "Local-first memory search" in txt assert "Uses local BGE embeddings" in txt assert "Uses your Ollama server" in txt assert "Keyword search stays available; embeddings are disabled." in txt assert "savedProvider" in txt assert "provider === savedProvider" in txt assert "statusText.textContent = _memoryEmbeddingStatusText(providerId)" in txt def test_setup_view_does_not_submit_disabled_memory_fields(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("async function _saveMemory()") end = txt.index(" async function _saveSearch()", start) body = txt[start:end] assert "if (input.disabled) return;" in body def test_setup_view_saves_search_checkboxes_as_booleans(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("async function _saveSearch()") end = txt.index(" async function _saveImage()", start) body = txt[start:end] assert "input.type === 'checkbox'" in body assert "params[key] = input.checked" in body def test_setup_finish_groups_required_and_optional_readiness(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _renderReadinessGroup" in txt assert "Required setup" in txt assert "Optional capabilities" in txt assert "setup-readiness__group" in txt def test_setup_finish_readiness_rows_render_detail_text(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderReadinessGroup") end = txt.index(" function _readinessTone", start) body = txt[start:end] assert "detail.detail" in body assert "setup-readiness__detail" in body def test_setup_finish_readiness_rows_offer_direct_config_actions(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") start = txt.index("function _renderReadinessGroup") end = txt.index(" function _readinessTone", start) body = txt[start:end] assert "function _setupStepForSection" in txt assert "function _readinessActionLabel" in txt assert "const step = _setupStepForSection(name, detail)" in body assert "const action = _renderReadinessAction(step, detail, name)" in body assert "function _renderReadinessAction" in txt assert "const actionAriaLabel = _readinessActionAriaLabel(detail, name)" in body assert 'class="setup-readiness__action"' in body assert "aria-label=\"${_esc(actionAriaLabel)}\"" in body assert "title=\"${_esc(actionAriaLabel)}\"" in body assert "data-step=\"${_esc(step)}\"" in body assert "_readinessActionLabel(detail, name)" in body assert "function _readinessActionAriaLabel" in txt assert ".setup-readiness__action" in css assert "grid-template-columns: minmax(0, 1fr) auto auto auto" in css def test_setup_finish_readiness_names_router_provider_prerequisite(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") assert "function _routerNeedsProvider" in txt assert "uses SquillaRouter after provider setup" in txt start = txt.index("function _setupStepForSection") end = txt.index(" function _readinessActionLabel", start) setup_body = txt[start:end] assert "if (_routerNeedsProvider(detail, name)) return 'provider'" in setup_body start = txt.index("function _readinessActionLabel") end = txt.index(" function _renderReadinessAction", start) action_body = txt[start:end] assert "if (_routerNeedsProvider(detail, name)) return 'Choose provider'" in action_body start = txt.index("function _readinessActionAriaLabel") aria_body = txt[start : txt.index(" function _readinessTone", start)] assert "return `Choose provider for ${label}`" in aria_body start = txt.index("function _readinessStatusLabel") status_body = txt[start : txt.index(" function _fieldHtml", start)] assert "if (_routerNeedsProvider(detail, name)) return 'Provider first'" in status_body def test_setup_finish_summary_stays_neutral_before_provider_is_configured(): txt = (VIEWS / "setup.js").read_text(encoding="utf-8") start = txt.index("function _renderFinishStep()") end = txt.index(" function _renderCliCommand", start) body = txt[start:end] assert "const configuredProvider = _configuredProvider();" in body assert "const providerSummary = configuredProvider || 'not configured'" in body assert ( "const modelSummary = configuredProvider" "\n ? ((_config.llm || {}).model || 'SquillaRouter defaults')" "\n : 'not configured'" ) in body assert ( "const routerSummary = configuredProvider" "\n ? (router.enabled === false ? 'disabled' : 'SquillaRouter')" "\n : 'choose a provider first'" ) in body assert "router.tier_profile || 'openrouter-mix'" not in body assert "${_esc(providerSummary)}" in body assert "${_esc(modelSummary)}" in body assert "${_esc(routerSummary)}" in body def test_setup_panel_avoids_dense_background_rule_lines(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") panel_block = css.split(".setup-panel {", 1)[1].split("}", 1)[0] assert "repeating-linear-gradient" not in panel_block def test_setup_capability_cards_keep_controls_top_aligned(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") mini_block = css.split(".setup-mini {", 1)[1].split("}", 1)[0] assert "align-content: start" in mini_block def test_setup_hidden_controls_remain_hidden_after_label_layout_rules(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") assert ".setup [hidden]" in css hidden_block = css.split(".setup [hidden]", 1)[1].split("}", 1)[0] assert "display: none !important" in hidden_block def test_setup_search_advanced_details_are_styled_as_secondary_controls(): css = (ROOT / "static/css/views/setup.css").read_text(encoding="utf-8") assert ".setup-mini__advanced > summary" in css assert ".setup-mini__advanced-body" in css assert "details.setup-mini__advanced[open] > summary::after" in css def test_config_view_exposes_memory_tab_and_restart_notice(): txt = (VIEWS / "config.js").read_text(encoding="utf-8") assert "label: 'Memory'" in txt assert "memory.embedding.provider" in txt assert "Gateway restart required for the change to take effect" in txt def test_config_view_links_to_guided_setup(): txt = (VIEWS / "config.js").read_text(encoding="utf-8") assert "Guided setup" in txt assert "Router.navigate('/setup')" in txt def test_channels_view_remains_status_only_but_links_guided_setup(): txt = (VIEWS / "channels.js").read_text(encoding="utf-8") assert "Runtime status" in txt assert "Guided setup" in txt assert "Router.navigate('/setup')" in txt assert "onboarding.channel.upsert" not in txt assert "channels.restart" not in txt def test_example_config_does_not_advertise_local_embedding_model_override(): txt = (ROOT.parents[2] / "opensquilla.toml.example").read_text(encoding="utf-8") local_section = txt.split("# [memory.embedding.local]", 1)[1].split( "# [memory.embedding.remote]", 1, )[0] assert "model =" not in local_section assert "onnx_dir" in local_section