• exec/chat_llm.js exec/llm

    From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Saturday, May 30, 2026 03:17:00
    https://gitlab.synchro.net/main/sbbs/-/commit/d5ec41abbeda3bd12385870a
    Modified Files:
    exec/chat_llm.js exec/llm_tools/bbs_directory.js
    Log Message:
    chat_llm: fix guru BBS-directory routing, OS filtering, and IRC venue

    Four guru-quality fixes surfaced by live IRC testing:

    - classify_intent: route "which/what BBS does <sysop> run?" to
    bbs_directory(list, sysop:X). Previously unrouted, so the 7B
    fabricated BBS names ("DoveNetNode", "BinkleyTerm").

    - classify_intent + bbs_directory: recognize OS-filter queries ("how
    many BBSes run FreeBSD?") via _looks_like_os and filter on the
    per-BBS OS parsed from the autoverify finger result (the same source
    load/sbbslist_html.js uses for its OS chart). Was mis-binding the OS
    as a software filter and fabricating counts; now FreeBSD=3, Win32=80,
    Linux=115, macOS=0.

    - bbs_directory: when a filtered list (sysop/os/software/network)
    yields zero matches, return an explicit no-match note telling the
    model not to invent a BBS. The 7B fabricated names from an empty
    bbses[] otherwise ("which BBS does mro run?" -> invented BBSes).

    - build_messages: IRC grounding now names the channel and states it is
    a shared Synchronet IRC channel, NOT the host BBS -- stops the guru
    greeting channel users with "what brings you to <BBS>?" and treating
    them as BBS callers.

    Regression: 29/32 (the 3 fails are pre-existing flaky FAQ citation
    checks); all bbs_directory/routing tests pass.

    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Monday, August 10, 2026 03:17:00
    https://gitlab.synchro.net/main/sbbs/-/commit/36cf709445ed412d4de99c06
    Modified Files:
    exec/chat_llm.js exec/llm_index/dokuwiki.js
    Log Message:
    chat_llm: strip emoji as UTF-8 bytes, and bridge query vocabulary

    sanitize_reply() has never removed a supplementary-plane emoji. It
    matched UTF-16 surrogate pairs, and strings in this engine hold BYTES:
    U+1F310 is the four characters F0 9F 8C 90, so there is no code unit in
    the D83C-D83E range for the pattern to find. A literal emoji in a .js
    source file arrives the same way, which is why the pattern also could
    not be checked against one. Every emoji the model emitted went to the
    channel despite both the system prompt forbidding them and this
    backstop appearing to exist.

    Matching is done on the UTF-8 byte sequences instead. The E2 ranges
    are kept narrow deliberately: box drawing (U+2500, E2 94) and arrows
    (U+2190, E2 86) are ordinary text and must survive. The surrogate
    patterns are retained after them for an engine that decodes to UTF-16;
    they are inert here.

    Retrieval still could not reach a page whose vocabulary differs from
    the question's. BM25 matches literal terms, so "the name of the mail
    server recycle file" never reaches the semaphore-files page -- the documentation calls it a semaphore file, the question does not, and a
    section about a text string named "Recycle Servers" wins the literal
    match instead. A query_synonyms map adds bridging terms at retrieval
    time. Terms are ADDED, never substituted, so an unhelpful synonym
    costs ranking rather than correctness, and expansion is applied only to retrieval -- is_casual_input() also tokenizes queries, and judges small
    talk by how many content words it finds, so expanding there would make
    a greeting look substantive. Keys are single words: a multi-word key
    is split, and each word carries the expansion independently.

    Wiki subsections now carry a lead-in from their parent section.
    Splitting a page can separate an answer from the qualifier that makes
    it usable -- the recycle section says to touch ctrl/recycle while the ".<service>" suffix yielding recycle.mail is stated one level up, so
    chunked alone that section holds no "mail" token and a question naming
    the mail server cannot retrieve it.

    The appended "See <url> for the official docs" citation is now scored
    by rarity among the retrieved candidates rather than plain overlap: a
    word carried by most of the retrieved chunks says nothing about which
    one the answer came from. It is also suppressed when the supporting
    chunk is not near the top of the ranking, because when two chunks
    support a reply about equally the pick is a guess, and a confidently
    wrong "official docs" link stapled to a correct answer reads as the bot
    not knowing its own documentation. index_url_append_rank tunes how
    strict that is, and 0 disables the append entirely.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net