summaryrefslogtreecommitdiffstats
path: root/llamachat/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'llamachat/config.py')
-rw-r--r--llamachat/config.py46
1 files changed, 46 insertions, 0 deletions
diff --git a/llamachat/config.py b/llamachat/config.py
index dec2ba6..d7682f0 100644
--- a/llamachat/config.py
+++ b/llamachat/config.py
@@ -37,6 +37,14 @@ DEFAULTS = {
# Named prompt selected for new conversations. Empty means the global
# default.md, and "none" means no system prompt at all.
"default_prompt": "",
+ # Web search through a SearXNG instance. Off unless both the flag is set
+ # and a URL is given, so an upgrade never starts talking to the network.
+ "search_enabled": False,
+ "search_url": "",
+ "search_results": 5,
+ "search_snippet_chars": 300,
+ "search_timeout": 10,
+ "max_searches": 2,
}
# The global prompt lives here; every other .md beside it is a named preset.
@@ -67,6 +75,12 @@ class Config:
default_prompt: str
prompts_dir: Path
state_path: Path
+ search_enabled: bool
+ search_url: str
+ search_results: int
+ search_snippet_chars: int
+ search_timeout: int
+ max_searches: int
def _runtime_dir() -> Path:
@@ -94,6 +108,11 @@ def load(path: Path = CONFIG_PATH) -> Config:
socket = values["socket"] or (_runtime_dir() / "llamachat.sock")
db = values["db"] or (_data_dir() / "history.db")
+ # A flag with no URL behind it is not enabled, it is misconfigured.
+ # Resolving that here means nothing downstream has to test both.
+ search_url = str(values["search_url"]).rstrip("/")
+ search_enabled = bool(values["search_enabled"]) and bool(search_url)
+
return Config(
base_url=str(values["base_url"]).rstrip("/"),
presets_path=Path(values["presets"]).expanduser(),
@@ -108,6 +127,12 @@ def load(path: Path = CONFIG_PATH) -> Config:
# Window layout, remembered between runs. Not user-editable config,
# so it sits beside it rather than inside config.toml.
state_path=path.parent / "state.ini",
+ search_enabled=search_enabled,
+ search_url=search_url,
+ search_results=int(values["search_results"]),
+ search_snippet_chars=int(values["search_snippet_chars"]),
+ search_timeout=int(values["search_timeout"]),
+ max_searches=int(values["max_searches"]),
)
@@ -143,6 +168,27 @@ def write_default(path: Path = CONFIG_PATH) -> Path:
'# chars-per-token estimate used to convert ctx-size into characters.\n'
f'attach_ctx_fraction = {DEFAULTS["attach_ctx_fraction"]}\n'
f'chars_per_token = {DEFAULTS["chars_per_token"]}\n'
+ '\n'
+ '# Web search through SearXNG. The model decides when to search; it\n'
+ '# is offered a web_search tool and calls it when a question needs\n'
+ '# current information. Both search_enabled and search_url are\n'
+ '# required: a flag with no URL stays off.\n'
+ '#\n'
+ '# The instance must have its JSON API enabled (format=json), which\n'
+ '# many installs turn off by default.\n'
+ '#\n'
+ '# Search results are untrusted text entering the model context.\n'
+ '# Only title, url and snippet are kept, snippets are truncated, and\n'
+ '# result links are shown but never fetched automatically.\n'
+ f'search_enabled = {str(DEFAULTS["search_enabled"]).lower()}\n'
+ f'search_url = "{DEFAULTS["search_url"]}"\n'
+ '\n'
+ '# Results per query, characters kept from each snippet, seconds\n'
+ '# before a query is abandoned, and searches allowed per turn.\n'
+ f'search_results = {DEFAULTS["search_results"]}\n'
+ f'search_snippet_chars = {DEFAULTS["search_snippet_chars"]}\n'
+ f'search_timeout = {DEFAULTS["search_timeout"]}\n'
+ f'max_searches = {DEFAULTS["max_searches"]}\n'
)
return path