forked from WHC/Hermit
v0.8.6: general mode, clipboard text, PDF text extraction
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.
This commit is contained in:
+25
-8
@@ -26,6 +26,8 @@ static void usage(const char *argv0) {
|
||||
" (last used)\n"
|
||||
" -m, --model NAME model (last used for the provider)\n"
|
||||
" -e, --effort LEVEL low | medium | high | max (last used)\n"
|
||||
" -M, --mode NAME coding (default, code framed) | general\n"
|
||||
" (documents, data, research; last used)\n"
|
||||
" -w, --workspace DIR project directory (default: current)\n"
|
||||
" -c, --continue reopen the last session (default)\n"
|
||||
" -N, --new start a new session\n"
|
||||
@@ -59,13 +61,13 @@ static void usage(const char *argv0) {
|
||||
"API keys: the TUI asks for a missing key and saves it per provider\n"
|
||||
" in the config dir (credentials, mode 0600); /key changes it.\n"
|
||||
" Fallbacks: <provider env> (DEEPSEEK_API_KEY, ...), CST_API_KEY.\n"
|
||||
"Settings: provider, models and effort are remembered in\n"
|
||||
"Settings: provider, models, effort and mode are remembered in\n"
|
||||
" settings.json next to the credentials.\n"
|
||||
"Env: CST_PROVIDER CST_MODEL CST_EFFORT CST_PROTOCOL CST_TOOLS\n"
|
||||
" CST_CONFIRM CST_MAX_STEPS CST_TOOL_OUT_CAP CST_CTX_WINDOW\n"
|
||||
" CST_CTX_TOKENS CST_AUTO_COMPACT=0 CST_SHELL_TIMEOUT\n"
|
||||
" CST_METRICS=0 CST_RECORD_SSE CST_REPLAY_SSE CST_MODELS\n"
|
||||
" CST_APPROVAL=ask|auto|yolo CST_AUTO_APPROVE=1 (=yolo)\n"
|
||||
"Env: CST_PROVIDER CST_MODEL CST_EFFORT CST_MODE CST_PROTOCOL\n"
|
||||
" CST_TOOLS CST_CONFIRM CST_MAX_STEPS CST_TOOL_OUT_CAP\n"
|
||||
" CST_CTX_WINDOW CST_CTX_TOKENS CST_AUTO_COMPACT=0\n"
|
||||
" CST_SHELL_TIMEOUT CST_METRICS=0 CST_RECORD_SSE CST_REPLAY_SSE\n"
|
||||
" CST_MODELS CST_APPROVAL=ask|auto|yolo CST_AUTO_APPROVE=1 (=yolo)\n"
|
||||
" CST_SANDBOX=off CST_SHELL CST_NO_PROJECT_NOTES=1 NO_COLOR\n"
|
||||
"TUI: type /help inside for commands and keys\n",
|
||||
argv0);
|
||||
@@ -374,6 +376,7 @@ int main(int argc, char **argv) {
|
||||
{"approval", required_argument, 0, 'A'},
|
||||
{"confirm", required_argument, 0, 'C'},
|
||||
{"effort", required_argument, 0, 'e'},
|
||||
{"mode", required_argument, 0, 'M'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"list-models", optional_argument, 0, 0x100},
|
||||
@@ -385,8 +388,8 @@ int main(int argc, char **argv) {
|
||||
{"web-open", no_argument, 0, 0x106},
|
||||
{0, 0, 0, 0}};
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "w:s:b:k:m:P:r:n:T:Hp:dahVNcR:LyA:C:e:", opts, NULL)) !=
|
||||
-1) {
|
||||
while ((c = getopt_long(argc, argv, "w:s:b:k:m:P:r:n:T:Hp:dahVNcR:LyA:C:e:M:",
|
||||
opts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'w':
|
||||
snprintf(cfg.workspace_root, sizeof(cfg.workspace_root), "%s", optarg);
|
||||
@@ -478,6 +481,14 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
snprintf(cfg.effort, sizeof(cfg.effort), "%s", optarg);
|
||||
break;
|
||||
case 'M':
|
||||
if (!cst_mode_valid(optarg)) {
|
||||
fprintf(stderr, "bad --mode %s (coding | general)\n", optarg);
|
||||
curl_global_cleanup();
|
||||
return 1;
|
||||
}
|
||||
snprintf(cfg.mode, sizeof(cfg.mode), "%s", optarg);
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
curl_global_cleanup();
|
||||
@@ -557,6 +568,12 @@ int main(int argc, char **argv) {
|
||||
snprintf(cfg.effort, sizeof(cfg.effort), "%s",
|
||||
cst_effort_valid(e) ? e : CST_DEFAULT_EFFORT);
|
||||
}
|
||||
if (!cfg.mode[0]) {
|
||||
const char *m = getenv("CST_MODE");
|
||||
if (!cst_mode_valid(m))
|
||||
m = saved.mode;
|
||||
snprintf(cfg.mode, sizeof(cfg.mode), "%s", cst_mode_name(m));
|
||||
}
|
||||
if (!cfg.api_base[0]) {
|
||||
const char *env_base = getenv("CST_API_BASE");
|
||||
if (!env_base || !env_base[0])
|
||||
|
||||
Reference in New Issue
Block a user