commit 3f64e350370dd21067666d57867a764e16479365 from: Isaac Meerleo date: Fri Jul 17 21:31:34 2026 UTC Add automatic Compaction settings commit - 8e964caf96f4c4f928cb51a7f4fd99288ec87914 commit + 3f64e350370dd21067666d57867a764e16479365 blob - e9067ff4fafbb22cbc7d3f953d6bddb9c041a41f blob + 015c7389169c6956ee20f00cc12e128beb8a7b75 --- regress/conf/conf_test.c +++ regress/conf/conf_test.c @@ -132,6 +132,9 @@ test_defaults(void) CHECK(c->initial_provider_slot == 0); CHECK(c->max_tokens == 4096); CHECK(c->context_limit == 0); + CHECK(c->auto_compact == 1); + CHECK(c->compact_reserve_tokens == 16384); + CHECK(c->compact_keep_tokens == 20000); CHECK(c->allow_write == 1); CHECK(c->allow_subprocess_net == 0); CHECK(c->web_search == 1); @@ -160,6 +163,9 @@ test_globals(void) "provider \"openai\"\n" "max_tokens 8192\n" "context_limit 100000\n" + "auto_compact no\n" + "compact_reserve_tokens 12345\n" + "compact_keep_tokens 23456\n" "allow_write no\n" "web_search no\n" "notify no\n" @@ -176,6 +182,9 @@ test_globals(void) CHECK(strcmp(conf_api_port(c), "8443") == 0); CHECK(c->max_tokens == 8192); CHECK(c->context_limit == 100000); + CHECK(c->auto_compact == 0); + CHECK(c->compact_reserve_tokens == 12345); + CHECK(c->compact_keep_tokens == 23456); CHECK(c->allow_write == 0); CHECK(c->web_search == 0); CHECK(c->notify == 0); @@ -558,10 +567,24 @@ test_macros(void) static void test_numbers(void) { + struct fugu_conf *c; + CHECK(parse_fails("max_tokens 0\n")); CHECK(parse_fails("max_tokens -5\n")); CHECK(parse_fails("max_tokens 999999999999999999999999\n")); CHECK(parse_fails("context_limit 0\n")); + CHECK(parse_fails("compact_reserve_tokens 0\n")); + CHECK(parse_fails("compact_reserve_tokens -1\n")); + CHECK(parse_fails("compact_reserve_tokens 1000000001\n")); + CHECK(parse_fails("compact_keep_tokens 0\n")); + CHECK(parse_fails("compact_keep_tokens -1\n")); + CHECK(parse_fails("compact_keep_tokens 1000000001\n")); + CHECK(parse_ok( + "compact_reserve_tokens 1\n" + "compact_keep_tokens 1000000000\n", &alice, &c)); + CHECK(c->compact_reserve_tokens == 1); + CHECK(c->compact_keep_tokens == 1000000000); + conf_free(c); CHECK(parse_fails("max_subagents -1\n")); CHECK(parse_fails("max_subagents 1000\n")); CHECK(parse_fails("max_bg_jobs -1\n")); @@ -701,6 +724,29 @@ test_include(void) } static void +test_dump_compaction(void) +{ + struct fugu_conf *c; + FILE *f; + char *buf = NULL; + size_t sz = 0; + + CHECK(parse_ok( + "auto_compact no\n" + "compact_reserve_tokens 123\n" + "compact_keep_tokens 456\n", &alice, &c)); + if ((f = open_memstream(&buf, &sz)) == NULL) + err(1, "open_memstream"); + conf_dump(c, f); + fclose(f); + CHECK(strstr(buf, "auto_compact no\n") != NULL); + CHECK(strstr(buf, "compact_reserve_tokens 123\n") != NULL); + CHECK(strstr(buf, "compact_keep_tokens 456\n") != NULL); + free(buf); + conf_free(c); +} + +static void test_dump_redacts(void) { struct fugu_conf *c; @@ -816,6 +862,7 @@ main(void) test_model_bounds(); test_hostile(); test_include(); + test_dump_compaction(); test_dump_redacts(); test_wipe_delegated_secrets(); test_lifetimes(); blob - 6c0eb932abd0c346232a70ae4cdd3c73f791f51d blob + 5e66360b3f782e643849f899753939f640399269 --- src/fugu/conf.c +++ src/fugu/conf.c @@ -40,6 +40,9 @@ conf_new(void) c->model = xstrdup("claude-sonnet-4-6"); c->provider_type = PROVIDER_ANTHROPIC; c->max_tokens = 4096; + c->auto_compact = 1; + c->compact_reserve_tokens = FUGU_COMPACT_RESERVE_TOKENS_DEFAULT; + c->compact_keep_tokens = FUGU_COMPACT_KEEP_TOKENS_DEFAULT; c->allow_write = 1; c->web_search = 1; c->search_provider = xstrdup("kagi"); @@ -274,6 +277,11 @@ conf_dump(const struct fugu_conf *c, FILE *f) if (c->context_limit > 0) fprintf(f, "context_limit %lld\n", (long long)c->context_limit); + fprintf(f, "auto_compact %s\n", yesno(c->auto_compact)); + fprintf(f, "compact_reserve_tokens %lld\n", + (long long)c->compact_reserve_tokens); + fprintf(f, "compact_keep_tokens %lld\n", + (long long)c->compact_keep_tokens); fprintf(f, "allow_write %s\n", yesno(c->allow_write)); fprintf(f, "allow_subprocess_net %s\n", yesno(c->allow_subprocess_net)); blob - 4f704363a3ed8dae87743361ec043cbd9f0813cd blob + ad1a542cfbdd0add698e93840eafde82b407b89d --- src/fugu/conf.h +++ src/fugu/conf.h @@ -23,6 +23,8 @@ #include #define FUGU_CONF_PATH "/etc/fugu.conf" +#define FUGU_COMPACT_RESERVE_TOKENS_DEFAULT INT64_C(16384) +#define FUGU_COMPACT_KEEP_TOKENS_DEFAULT INT64_C(20000) /* Unambiguous subagent_provider spelling for the implicit provider. */ #define FUGU_IMPLICIT_PROVIDER_REF "@default" @@ -63,6 +65,9 @@ struct fugu_conf { char *system; /* NULL: built-in prompt */ int64_t max_tokens; int64_t context_limit; /* 0: unset */ + int auto_compact; + int64_t compact_reserve_tokens; + int64_t compact_keep_tokens; int allow_write; int allow_subprocess_net; int web_search; blob - 1b7a16b8769e9b408730b8ed5e4c7c729edf5313 blob + bbc3a96f14f004077b95fe4bca03b4954f3b0adf --- src/fugu/fugu.conf.5 +++ src/fugu/fugu.conf.5 @@ -234,10 +234,35 @@ Markdown structure is retained and unsupported glyphs .Sq ? . The default is .Ic no . +.It Cm auto_compact Ic yes | no +Automatically Compact the Lead Projection before a Generation when its +estimated size exceeds the Effective window less +.Cm compact_reserve_tokens . +When enabled, a recognized Provider context-overflow rejection may also +Compact and retry the rejected Generation once. +With +.Ic no , +neither automatic path runs; +.Cm /compact +remains available. +The default is +.Ic yes . +.It Cm compact_keep_tokens Ar tokens +Set the target size of the recent Projection suffix retained by automatic and +manual Compaction. +The value must be between 1 and 1000000000. +The default is 20000. +.It Cm compact_reserve_tokens Ar tokens +Reserve this much of the Effective window when deciding whether to Compact +before a Lead Generation. +The value must be between 1 and 1000000000. +The default is 16384. .It Cm context_limit Ar tokens Set an advisory projection budget and the effective window displayed by .Cm /context and the curses status bar. +When set, it is also the first-priority Effective-window override used by +automatic Compaction. The value must be between 1 and 1000000000. By default it is unset, and provider metadata or a compiled model table is used when available. blob - 21ec4235f66e401447251a9e19e7c6e0509a3ee9 blob + dc06ddff4712f16bda5f125ac86d2bd40df46300 --- src/fugu/parse.y +++ src/fugu/parse.y @@ -131,7 +131,8 @@ typedef struct { %} %token ALLOWSUBPROCESSNET ALLOWWRITE ANTHROPICKEY ANTHROPICKEYFILE APIHOST -%token APIKEY APIKEYFILE APIPATH APIPORT ASCII CONTEXTLIMIT ERROR GROUP +%token APIKEY APIKEYFILE APIPATH APIPORT ASCII AUTOCOMPACT +%token COMPACTKEEPTOKENS COMPACTRESERVETOKENS CONTEXTLIMIT ERROR GROUP %token HTTPALLOW HTTPBLOCK INCLUDE KAGITOKEN KAGITOKENFILE MATCH MAXBGJOBS %token MAXSUBAGENTS MAXTOKENS MODEL NO NOTIFY OAUTHTOKEN %token PROJECTCONTEXT PROTECT @@ -222,6 +223,23 @@ main : MODEL STRING { } set_number(&conf->context_limit, $2); } + | AUTOCOMPACT yesno { + set_bool(&conf->auto_compact, $2); + } + | COMPACTRESERVETOKENS NUMBER { + if ($2 < 1 || $2 > 1000000000) { + yyerror("compact_reserve_tokens out of range"); + YYERROR; + } + set_number(&conf->compact_reserve_tokens, $2); + } + | COMPACTKEEPTOKENS NUMBER { + if ($2 < 1 || $2 > 1000000000) { + yyerror("compact_keep_tokens out of range"); + YYERROR; + } + set_number(&conf->compact_keep_tokens, $2); + } | ALLOWWRITE yesno { set_bool(&conf->allow_write, $2); } @@ -588,6 +606,9 @@ lookup(char *s) { "api_path", APIPATH }, { "api_port", APIPORT }, { "ascii", ASCII }, + { "auto_compact", AUTOCOMPACT }, + { "compact_keep_tokens", COMPACTKEEPTOKENS }, + { "compact_reserve_tokens", COMPACTRESERVETOKENS }, { "context_limit", CONTEXTLIMIT }, { "group", GROUP }, { "http_allow", HTTPALLOW },