{
  "tool_id": "lumi_ai_web_search",
  "tool_namespace": "web_search",
  "name": "lumi_ai_web_search",
  "display_name": "Lumi AI Web Search",
  "version": "0.1.0",
  "description": "Self-contained, policy-controlled public web search and safe URL extraction for Lumi Assistant. The default provider requires no API key or external service setup.",
  "scope": {
    "label": "Assistant public web lookup",
    "required_role": "user"
  },
  "permissions": {
    "required_role": "user",
    "permission": "lumi_ai_web_search.use"
  },
  "capabilities": [
    "No-key public web search through the tool-contained Lumi search broker",
    "Safe explicit URL fetch and readable-text extraction",
    "Condensed URL summarization",
    "Whitelist or blacklist URL policy with wildcard rules",
    "Context-aware output budgets, caching, rate limits, diagnostics, and audits"
  ],
  "registered_capabilities": [
    {
      "tool_id": "web_search.search",
      "enabled_setting": "enable_search",
      "description": "Search the public web for current or external information."
    },
    {
      "tool_id": "web_search.fetch_url",
      "enabled_setting": "enable_fetch_url",
      "description": "Fetch and extract readable information from an explicit public URL."
    },
    {
      "tool_id": "web_search.summarize_url",
      "enabled_setting": "enable_summarize_url",
      "description": "Fetch an explicit public URL and return compact structured content for summarization."
    }
  ],
  "limitations": [
    "Search sources may rate-limit, block automated requests, or change markup",
    "No JavaScript execution or browser automation is enabled by default",
    "Private, local, link-local, metadata, credential-bearing, and non-HTTP targets are always blocked",
    "Search quality and freshness depend on public source availability"
  ],
  "tool_type": "web_search",
  "owning_plugin": "lumi_ai_web_search",
  "default_enabled": true,
  "entrypoints": {
    "backend": "index.js"
  },
  "frontend_assets": [
    "public"
  ],
  "views": [
    "views/settings-modal.ejs"
  ],
  "settings_ui": {
    "view": "views/settings-modal.ejs",
    "scripts": [
      "settings-modal.js"
    ],
    "styles": [
      "settings-modal.css"
    ]
  },
  "settings_migrator": "backend/settings.js",
  "diagnostic_settings": [
    "provider",
    "policy_mode",
    "allowed_origins",
    "enable_search",
    "enable_fetch_url",
    "enable_summarize_url"
  ],
  "status_file": "data/status.json",
  "dependencies": [],
  "minimum_lumi_version": "0.1.0",
  "minimum_lumi_ai_version": "0.8.1",
  "required_plugins": [
    "core",
    "lumi_ai"
  ],
  "required_platforms": [],
  "risk_level": "low",
  "confirmation_required": false,
  "data_paths": [
    "data/settings.json",
    "data/status.json",
    "data/audit.jsonl",
    "data/cache"
  ],
  "preserve_on_update": [
    "data"
  ],
  "update_notes": "Adds a self-contained no-key search broker plus independent search, fetch URL, and summarize URL capabilities.",
  "author": "Lumi",
  "homepage": "https://git.rolfsvaag.no/Rolfsvaag_Datateknikk/Lumi",
  "repository_path": "plugins/lumi_ai_web_search",
  "settings_schema": {
    "provider": {
      "type": "enum",
      "label": "Provider",
      "description": "The default Lumi search broker is contained in this plugin and requires no API key or separate service.",
      "options": [
        "lumi_search_broker",
        "external_json"
      ],
      "default": "lumi_search_broker"
    },
    "enable_search": {
      "type": "boolean",
      "label": "Enable web search",
      "default": true
    },
    "enable_fetch_url": {
      "type": "boolean",
      "label": "Enable explicit URL fetch",
      "default": true
    },
    "enable_summarize_url": {
      "type": "boolean",
      "label": "Enable URL summarization",
      "default": true
    },
    "enable_headless_browser_fallback": {
      "type": "boolean",
      "label": "Headless browser fallback",
      "description": "Reserved for a future Lumi-managed restricted browser runtime. HTTP mode works without it.",
      "default": false
    },
    "policy_mode": {
      "type": "enum",
      "label": "URL policy",
      "description": "Blacklist allows safe public URLs except matching rules. Whitelist permits only matching rules.",
      "options": [
        "blacklist",
        "whitelist"
      ],
      "default": "blacklist"
    },
    "url_rules": {
      "type": "string_list",
      "label": "URL policy rules",
      "description": "One domain, subdomain, URL, path prefix, or * wildcard pattern per line.",
      "default": [],
      "rows": 6
    },
    "max_results": {
      "type": "integer",
      "label": "Maximum results",
      "default": 5,
      "minimum": 1,
      "maximum": 10
    },
    "search_timeout_ms": {
      "type": "integer",
      "label": "Search timeout (ms)",
      "default": 8000,
      "minimum": 1000,
      "maximum": 30000
    },
    "fetch_timeout_ms": {
      "type": "integer",
      "label": "Page fetch timeout (ms)",
      "default": 10000,
      "minimum": 1000,
      "maximum": 30000
    },
    "max_fetch_bytes": {
      "type": "integer",
      "label": "Maximum fetched bytes",
      "default": 1048576,
      "minimum": 65536,
      "maximum": 4194304
    },
    "max_extracted_chars": {
      "type": "integer",
      "label": "Maximum extracted characters",
      "default": 12000,
      "minimum": 1000,
      "maximum": 50000
    },
    "max_redirects": {
      "type": "integer",
      "label": "Maximum redirects",
      "default": 3,
      "minimum": 0,
      "maximum": 8
    },
    "cache_ttl_seconds": {
      "type": "integer",
      "label": "Cache TTL (seconds)",
      "default": 900,
      "minimum": 0,
      "maximum": 86400
    },
    "safe_search_level": {
      "type": "enum",
      "label": "Safe search",
      "options": [
        "off",
        "moderate",
        "strict"
      ],
      "default": "moderate"
    },
    "allowed_origins": {
      "type": "multi_select",
      "label": "Allowed origins",
      "options": [
        "webui",
        "discord",
        "twitch",
        "youtube",
        "kick",
        "other"
      ],
      "default": [
        "webui",
        "discord",
        "twitch"
      ]
    },
    "show_source_links_webui": {
      "type": "boolean",
      "label": "Show source links in WebUI",
      "default": true
    },
    "show_source_links_discord": {
      "type": "boolean",
      "label": "Show source links in Discord",
      "default": true
    },
    "show_source_links_twitch": {
      "type": "boolean",
      "label": "Show source links in Twitch",
      "default": false
    },
    "webui_output_chars": {
      "type": "integer",
      "label": "WebUI output budget",
      "default": 2500,
      "minimum": 300,
      "maximum": 12000
    },
    "discord_output_chars": {
      "type": "integer",
      "label": "Discord output budget",
      "default": 1200,
      "minimum": 200,
      "maximum": 4000
    },
    "twitch_output_chars": {
      "type": "integer",
      "label": "Twitch output budget",
      "default": 450,
      "minimum": 120,
      "maximum": 1000
    },
    "youtube_output_chars": {
      "type": "integer",
      "label": "YouTube output budget",
      "default": 1200,
      "minimum": 120,
      "maximum": 3000
    },
    "kick_output_chars": {
      "type": "integer",
      "label": "Kick output budget",
      "default": 450,
      "minimum": 120,
      "maximum": 1000
    },
    "other_output_chars": {
      "type": "integer",
      "label": "Other output budget",
      "default": 700,
      "minimum": 120,
      "maximum": 3000
    },
    "per_user_per_minute": {
      "type": "integer",
      "label": "Requests per user/minute",
      "default": 6,
      "minimum": 1,
      "maximum": 60
    },
    "per_origin_per_minute": {
      "type": "integer",
      "label": "Requests per origin/minute",
      "default": 30,
      "minimum": 1,
      "maximum": 300
    },
    "per_server_per_minute": {
      "type": "integer",
      "label": "Requests per server/minute",
      "default": 20,
      "minimum": 1,
      "maximum": 300
    },
    "external_provider_adapter": {
      "type": "enum",
      "label": "Advanced external adapter",
      "options": [
        "searxng_json",
        "generic_json"
      ],
      "default": "searxng_json"
    },
    "external_provider_endpoint": {
      "type": "string",
      "label": "Advanced external endpoint",
      "description": "Optional. Not required by the default Lumi search broker.",
      "default": ""
    },
    "external_provider_api_key": {
      "type": "string",
      "label": "Advanced external API key",
      "default": "",
      "secret": true
    },
    "external_provider_api_key_header": {
      "type": "enum",
      "label": "External API key header",
      "options": [
        "X-API-Key",
        "Authorization"
      ],
      "default": "X-API-Key"
    },
    "external_provider_api_key_prefix": {
      "type": "string",
      "label": "External API key prefix",
      "default": ""
    },
    "external_provider_query_parameter": {
      "type": "string",
      "label": "External query parameter",
      "default": "q"
    }
  }
}
