====== llm_tools: chat tool registry ======

''llm_tools'' is the function-calling registry for the [[module:chat_llm|chat
engine]].  When the model decides it needs live data to answer — the local
sub-board list, a BBS directory lookup, BBS-era history — it emits a tool
call; the registry runs the matching tool and feeds the result back to the
model.  Tools are how the Guru answers from **fact** instead of from training
guesses.

The registry lives in ''exec/llm_tools.js''; each tool is a separate file
under ''exec/llm_tools/''.

===== How it works =====

On load, ''llm_tools.js'' reads every ''exec/llm_tools/*.js'' file in
alphabetical order and ''load()''s it.  Each tool file ends by calling
''llm_tool_register(...)'' to publish itself.  The engine then offers the
registered tools to the model on each turn and dispatches any tool calls the
model makes.

Adding a tool is **drop-in**: add a file, restart — no change to the engine,
no recompile.  A file that fails to load is warned-and-skipped, so one broken
tool never disables the rest.

===== Bundled tools =====

^ Tool ^ Purpose ^
| ''this_bbs'' | Queries the **local** host BBS: today's live counters and lifetime totals (''stats''), message groups/subs, file libraries/dirs, door sections/doors, and recent messages on a sub.  Honors each caller's access level — it only lists what that caller could see. |
| ''bbs_directory'' | Queries the Synchronet BBS directory (sbbslist).  ''lookup'' returns one BBS by name/sysop/hostname plus a live finger probe and reliability summary; ''list'' returns a filtered/sorted list (by software, network, sysop, recency) and a total count. |
| ''external_archives'' | A curated index of BBS-era history and culture (textfiles.com, bbsdocumentary.com, the BBS Timeline).  The model is told to call it **before** answering history questions, because training-data answers about door games, lawsuits, and old software are often wrong. |
| ''relay_message'' | Stores a message for deferred delivery to a named recipient the next time they speak.  Validates the recipient against the channel roster, chat history, and user base; primarily useful to the [[module:chat_llm_irc|IRC adapter]], which delivers queued messages. |

===== Customizing the external_archives index =====

The ''external_archives'' tool answers from a hand-curated data file,
''ctrl/llm_external_archives.json'' — not a live web search.  It's
sysop-customizable guru data (it lives in ''ctrl/'' alongside
[[config:chat_llm.ini]] and the persona files), so you can extend or prune it
to control what BBS-era history the Guru points callers at; no recompile, and
it's re-read on each lookup.

It has two parts: a ''sources'' map describing each archive site, and an
''entries'' list.  Each entry is matched substring-style against the caller's
query (its ''tags'' + ''summary'' + ''url''):

<code javascript>
{
  "version": 1,
  "sources": {
    "textfiles": { "site": "textfiles.com", "curator": "Jason Scott",
                   "blurb": "Massive archive of BBS-era text files..." }
  },
  "entries": [
    {
      "id":      "tf-bbs",
      "src":     "textfiles",
      "tags":    ["bbs", "bulletin board", "history", "sysop"],
      "url":     "https://textfiles.com/bbs/",
      "summary": "textfiles.com's BBS section: history articles, sysop
                  newsletters, phone-number lists, BBS software docs."
    }
  ]
}
</code>

Keep it small (~50 entries) — it's a lookup tool, not a RAG corpus (for
indexing your own content at scale, see [[module:llm_index]]).  Prefer
canonical landing pages over deep links that may rot, and give each entry
generous ''tags'' so the model finds it.

===== Security model =====

Tools run with the BBS's privileges, so the registry enforces a strict
read-only contract.  **Read this before writing a tool:**

  * **Read-only only.** No side-effecting methods on host objects (no saving, writing, or deleting) — property access and read-only enumeration only.
  * **No path / eval / shell pass-through.** A tool receives only the arguments the model emitted, constrained by the tool's declared JSON Schema.
  * **Caller chat text is never forwarded into a tool.** Arguments come solely from the model's structured tool-call payload, not from raw user input.
  * **Secret tripwire.** A shared helper audits every returned object and throws if a field name looks like a credential (''password'', ''api_key'', ''token'', ''secret'', etc.), to catch accidental leaks.

===== Writing a tool =====

Create ''exec/llm_tools/<name>.js''.  Define an executor and register it:

<code javascript>
function my_tool(args, env) {
    // args: the model's structured arguments (validated against def below)
    // env:  per-call context (e.g. the speaker) supplied by the engine
    // Return an object (auto-JSON-encoded) or a string. READ-ONLY work only.
    return { ok: true, answer: "..." };
}

llm_tool_register({
    name: "my_tool",
    execute: my_tool,
    def: {                          // the model-facing tool specification
        type: "function",
        "function": {
            name: "my_tool",
            description: "What this tool does and exactly when to call it.",
            parameters: {
                type: "object",
                properties: {
                    topic: { type: "string", description: "..." }
                },
                required: ["topic"]
            }
        }
    }
});
</code>

Notes:

  * The ''description'' is the model's only guide to **when** to call the tool — be specific, list trigger phrases, and say when **not** to call it.  The bundled tools' descriptions are good models.
  * Files whose names begin with ''_'' load first, so put helpers shared by several tools in a ''_''-prefixed file (the bundled ''_common.js'' is the example).
  * Returning ''{ error: "..." }'' lets the model recover gracefully and tell the caller what went wrong.

===== See Also =====

  * [[module:chat_llm]] — the chat engine that calls these tools
  * [[module:llm_index]] — RAG retrieval (complementary to tools)
  * [[module:chat_llm_irc]] — delivers ''relay_message'' queues
  * [[config:chat_llm.ini]] — engine configuration

{{tag>chat guru llm chat_llm tools ai}}
