Working mode: --mode coding|general (CST_MODE, settings.json, /mode, WebUI run settings). general swaps the default framing for a general assistant one -- workflow, safety notes, tool wording (run_shell, the subagents) -- and /status shows it; minimal (the paper profile) stays byte-frozen. The prompt state carries the mode so a switch leaves a system note in history. Clipboard: clipboard_read / clipboard_write tools (16 MiB cap read, default 64 KiB window; writing is a WRITE permission with a preview) on pbcopy / wl-copy / xclip / pbpaste / wl-paste / xclip and the Win32 clipboard. In the TUI, /attach paste falls back to clipboard text when there is no image on it. PDF: a dependency-free text extractor (src/pdf_text.c): inflate, Flate/ASCIIHex/ASCII85, PNG/TIFF predictors, layout-independent object scan, object streams, page tree walk with inherited resources, content lexer (Tj/TJ/'/" and the Td/TD/T*/Tm spacing heuristics), per-font ToUnicode CMaps and inline images skipped. Encrypted files and pages with no text layer are refused with the reason. Attachments: /attach (a path or files dropped on the terminal) now take images, PDFs and text. A PDF is stored as its text layer with the mime still saying application/pdf and its page count; anything else has to be UTF-8 text. Documents travel inline as text parts, so CST_NO_IMAGES and text-only models no longer drop them, while images keep their old path. Tests: test_pdf_text (plain, bare and zlib-framed Flate, inline image, CID + ToUnicode, object stream, error paths), documents in test_attach, inlined documents in test_llm_body, mode in test_config.
92 lines
4.3 KiB
C
92 lines
4.3 KiB
C
#ifndef CST_ATTACH_H
|
|
#define CST_ATTACH_H
|
|
|
|
#include "cst_agent.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* --- attachments ---------------------------------------------------------
|
|
* An attachment is a validated copy of a file, stored beside the session so
|
|
* what a model is shown stays what was picked. Images are stored as they are
|
|
* and encoded into the request when it is built; a PDF is reduced to its text
|
|
* layer and a text file is stored as is, both of which travel inline as text
|
|
* (so a text-only model still gets them). Only the metadata goes in the
|
|
* JSONL. */
|
|
|
|
/* Supported: PNG, JPEG, GIF, WebP, BMP (static images), PDF, UTF-8 text. */
|
|
#define CST_ATTACH_MAX_BYTES (16 * 1024 * 1024) /* one picked file */
|
|
#define CST_ATTACH_MAX_TOTAL (32 * 1024 * 1024) /* per request */
|
|
#define CST_ATTACH_MAX_COUNT 8 /* per message */
|
|
/* Text stored and inlined per document (a PDF also caps its text here). */
|
|
#define CST_ATTACH_TEXT_MAX (4 * 1024 * 1024)
|
|
|
|
/* Images go on the wire as image parts; everything else is inlined as text. */
|
|
int cst_attach_is_image(const cst_attachment_t *a);
|
|
int cst_attach_is_text(const cst_attachment_t *a);
|
|
|
|
/* Magic-byte test: 0 and a canonical mime when data holds a supported
|
|
* image, -1 otherwise (an extension alone never decides). */
|
|
int cst_attach_sniff(const void *data, size_t n, char *mime, size_t mime_sz);
|
|
/* Pixel size from the header when it is readable; 0 for unknown. */
|
|
int cst_attach_dimensions(const void *data, size_t n, int *w, int *h);
|
|
|
|
/* A stored file name as store() makes it ("<id>.<ext>"); rejects anything
|
|
* that could leave the attachment directory. */
|
|
int cst_attach_rel_ok(const char *rel);
|
|
/* Directory holding this session's stored images (created on demand). */
|
|
int cst_attach_dir(const char *session_path, char *out, size_t out_sz);
|
|
/* Absolute path of a stored image (0 / -1). */
|
|
int cst_attach_full_path(const char *session_path, const cst_attachment_t *a,
|
|
char *out, size_t out_sz);
|
|
|
|
/* Read src_path and copy it into the session's attachment directory: an image
|
|
* as it is, a PDF as its extracted text, anything else only when it is text.
|
|
* Returns a malloc'd entry the caller owns (cst_attach_free), or NULL with
|
|
* err filled. */
|
|
cst_attachment_t *cst_attach_import_file(const char *session_path,
|
|
const char *src_path, char *err,
|
|
size_t err_sz);
|
|
/* Store already-read image bytes (clipboard, downloads); name is
|
|
* display-only. */
|
|
cst_attachment_t *cst_attach_import_bytes(const char *session_path,
|
|
const char *name, const char *data,
|
|
size_t n, char *err, size_t err_sz);
|
|
|
|
/* Validate and read back a stored payload, or NULL when it is gone. */
|
|
char *cst_attach_read(const char *session_path, const cst_attachment_t *a,
|
|
size_t *out_len, char *err, size_t err_sz);
|
|
/* "data:image/png;base64,...." for the wire; images only, NULL otherwise. */
|
|
char *cst_attach_data_url(const char *session_path, const cst_attachment_t *a);
|
|
/* "1920x1080 png 412 KB" / "pdf 1.2 MB, 12 pages" one-liner for prompts. */
|
|
void cst_attach_describe(const cst_attachment_t *a, char *out, size_t out_sz);
|
|
|
|
void cst_attach_free(cst_attachment_t *a);
|
|
/* Free a list of n entries allocated as separate blocks. */
|
|
void cst_attachments_free(cst_attachment_t *list, int n);
|
|
/* Deep copy (NULL on OOM or when n <= 0). */
|
|
cst_attachment_t *cst_attachments_dup(const cst_attachment_t *list, int n);
|
|
/* Append src to *list (grows with realloc). 0 / -1. */
|
|
int cst_attachments_push(cst_attachment_t **list, int *n, int *cap,
|
|
const cst_attachment_t *src);
|
|
|
|
/* JSON array of n attachments for the session JSONL (malloc'd), or NULL. */
|
|
char *cst_attachments_to_json(const cst_attachment_t *list, int n);
|
|
/* Parse a JSON array; caller frees with cst_attachments_free. */
|
|
cst_attachment_t *cst_attachments_from_json(const void *array_json, int *n_out);
|
|
|
|
/* Base64 of n bytes (malloc'd, no line breaks). */
|
|
char *cst_base64_encode(const void *data, size_t n);
|
|
/* Standard or URL-safe base64 (whitespace ignored) to bytes; malloc'd,
|
|
* NULL on a bad character. */
|
|
char *cst_base64_decode(const char *s, size_t n, size_t *out_len);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|