Keep searchable text only in knowledgebases

Every bot file was chunked into bot_file_chunks and embedded into
bot_file_vectors, and uploads kept their extracted text in
media.text_content, which together took most of the database. Bot
files are no longer indexed: bots find them by name or path with
list_files and read them with read_file, and search_files, ingest_file
and the files modal's re-read button are gone. Attachments keep no
text; a reply reads a document from the file. Only knowledgebase
documents keep text.

The schema drops both tables and the ingest columns. At boot,
dropStoredFileText removes what older versions stored (file jobs,
upload text) and vacuums once much of the database is free. The
media:prune-text script it replaces is removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-28 04:44:46 +01:00
co-authored by Claude Opus 5.5
parent 2896e76256
commit ac3ebc43d4
55 changed files with 271 additions and 1712 deletions
+12 -4
View File
@@ -661,8 +661,9 @@ export const AppData = {
*/
BotFileImportMaxBytes: 20 * 1024 * 1024,
/**
* Ingesting a bot file: how much text one chunk holds, how much of the
* previous chunk it repeats, and the largest file it reads at all.
* Ingesting a knowledgebase document: how much text one chunk holds,
* how much of the previous chunk it repeats, and the largest file it
* reads at all (also the largest attachment a reply reads).
*/
ChunkTargetChars: 1200,
ChunkOverlapChars: 200,
@@ -681,12 +682,19 @@ export const AppData = {
EmbeddingBatchSize: 32,
EmbeddingMaxInputChars: 8000,
/**
* How many chunks a file search returns, and how many more it asks
* the vector index for before filtering to the run's scopes.
* How many chunks a knowledgebase search returns, and how many more it
* asks the vector index for before filtering to the run's ones.
*/
RagTopChunks: 8,
RagOverFetch: 4,
RagMaxK: 60,
/**
* The database is vacuumed at boot once this share of its pages, and
* at least this many bytes, sit free (after a big delete, such as the
* bot file index being dropped).
*/
DbVacuumMinFreeRatio: 0.2,
DbVacuumMinFreeBytes: 4 * 1024 * 1024,
/**
* Knowledgebases: the most one document holds (an upload, or text
* written in), how much of a pasted text a form takes, how many
+5 -5
View File
@@ -60,18 +60,18 @@ export const botFilesNote = ({ bot_id }: { bot_id: number | string }) => `# Your
You have a folder of your own, kept with the app (not on a computer), and it stays between runs and conversations.
- list_files shows what's in it; read_file opens one (by its [file:ID] ref or path); write_file saves a text file, make_pdf a PDF, generate_image an image. Move and delete with move_file and delete_file when something is out of date, so the folder stays useful.
- Text files are chunked and searchable as soon as they're saved. search_files finds the passages that answer a question, by meaning when an embedding model is set and by words otherwise. Search your files before saying you don't know something they may hold, and when the user asks about a document they gave you.
- Uploaded files land in the same folder, under uploads/ (uploads/2026-10/logo.png), so what the user sent you earlier is searchable later too.
- Files are found by name or path, never by what's in them: list_files with "search" matches names and paths, then read_file reads the one you want. Look for a file and read it before saying you don't know something it may hold, and when the user asks about a document they gave you. Searching by content is what knowledgebases are for; your files aren't indexed.
- Uploaded files land in the same folder, under uploads/ (uploads/2026-10/logo.png), so what the user sent you earlier is there to list and read later too.
- A picture can be set from a file: set_picture makes a file your own avatar, and update_workspace sets a workspace's. Both take the [file:ID] ref, so a logo the user sent you is usually ready to go: list_files for it, then set it. An SVG or another kind of file is turned into a PNG first. Its picture is free to change and never removes your file.
- A file and a folder are two different refs, and you never guess which one from the name:
- A file you saved is a [file:ID] ref (from write_file, list_files, search_files or import_file). The user sees a chip that opens the file.
- A file you saved is a [file:ID] ref (from write_file, list_files or import_file). The user sees a chip that opens the file.
- A folder is a folder ref, e.g. ${ownFolderRef({ bot_id })}: the user sees a chip that opens that folder in Files, and nothing is downloaded. Use the volume of the folder you mean ("bot" for your own, "workspace" for a workspace's shared one).
- Never write a path as plain text and expect the user to find it; never write a [file:ID] ref for something that is a folder.
- Write refs as they are, never in backticks or a code block: inside code they show as plain text, not a chip.
- A file you only described is not saved. Save it first, then say it's saved.
- Save what the user will want before the long tail of a run. A step limit ends a run where it stands: write the report first with write_file (or copy it off the computer with import_file), then carry on verifying.
- One copy of a thing is enough. Before you write or import something, list_files (or search_files) for it: if it's already there, update it (write_file over the same path) instead of saving a second copy under a new name. Never split a file into parts unless the user asked for parts.
- Your files don't disappear. If you can't find something, list_files or search_files before saying anything is missing, and never claim the folder is empty without having just listed it.
- One copy of a thing is enough. Before you write or import something, list_files for it: if it's already there, update it (write_file over the same path) instead of saving a second copy under a new name. Never split a file into parts unless the user asked for parts.
- Your files don't disappear. If you can't find something, list_files (with and without "search") before saying anything is missing, and never claim the folder is empty without having just listed it.
- Report what the tools actually returned. Don't invent limits, sizes or caps you haven't seen in a tool result: if an import or a write failed, say what the tool said.`;
/**