diff options
Diffstat (limited to 'src/compact.h')
| -rw-r--r-- | src/compact.h | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/compact.h b/src/compact.h new file mode 100644 index 0000000..c34a17d --- /dev/null +++ b/src/compact.h @@ -0,0 +1,124 @@ +#ifndef LLSH_COMPACT_H +#define LLSH_COMPACT_H + +#include "message.h" +#include "util.h" + +/* Mirrors compact.rs: pure helpers for the two-tier context compaction. + * Side-effect free (no I/O) so it is unit-testable; the file reads and the + * model call live in the session. */ + +#define CLEARED_PLACEHOLDER \ + "[tool output cleared to save context; re-run the tool if you need it]" + +/* Re-injected file caps: per-file chars, number of files, total budget. */ +#define PER_FILE_CAP 50000UL +#define MAX_FILES 5UL +#define FILES_CAP 100000UL + +/* System preamble for the tool-less one-shot summarizer. */ +const char *compact_summarizer_preamble(void); + +/* The resolved compaction knobs, carried by a session. */ +typedef struct { + unsigned long context_limit; /* 0 disables compaction entirely */ + double compact_threshold; /* fraction; 0.0 disables the tier */ + double clear_threshold; /* fraction; 0.0 disables the tier */ +} compact_config; + +/* Populate from a config (see config.h). */ +void compact_config_from(unsigned long context_limit, double compact_threshold, + double clear_threshold, compact_config *out); + +/* Token budget at which the summarization tier fires. + * Returns true (and sets *out) when enabled, false when disabled. */ +bool compact_at(const compact_config *c, unsigned long *out); +bool clear_at(const compact_config *c, unsigned long *out); + +/* Which compaction action actually ran. */ +typedef enum { + TIER_CLEARED, /* tier 1: stale tool results replaced in place */ + TIER_SUMMARIZED, /* tier 2: prefix summarized, recent files re-injected */ + TIER_FALLBACK_CLEAR /* tier 2 requested but summarization failed */ +} compact_tier; + +/* What a compaction pass did, for a status line and tests. */ +typedef struct { + compact_tier tier; + unsigned long tokens_before; + unsigned long tokens_after; + size_t cleared_tool_results; /* 0 when a summarization ran */ + size_t files_reinjected; /* 0 unless a summarization ran */ +} compact_report; + +/* Rough token count: total bytes / 4 (div_ceil). */ +unsigned long compact_estimate_tokens(const message *msgs, size_t n); + +/* Index of the last pure-text user message, or n when there is none. */ +size_t compact_keep_boundary(const message *msgs, size_t n); + +/* Replace content of stale tool results (strictly before boundary) with the + * placeholder. Idempotent. Returns results cleared on this pass. */ +size_t compact_clear_old_tool_results(message *msgs, size_t n, size_t boundary); + +/* Flatten a message slice into a plain-text transcript. Caller frees. */ +char *compact_transcript(const message *msgs, size_t n); + +/* Render the conversation as a Markdown transcript. Caller frees. */ +char *compact_transcript_markdown(const message *msgs, size_t n); + +/* Extract file paths listed under a `## Files` heading (case-insensitive; + * accepts `-` or `*` bullets). Caller frees the strlist. */ +void compact_recent_file_paths(const char *summary, strlist *out); + +/* Build the post-compaction history: one user message carrying the summary + * and any re-injected files, followed by the kept tail (copied). + * Heap-allocated: caller frees with history_free(h); free(h); */ +history *compact_compose_history(const char *summary, + const char **file_paths, + const char **file_contents, size_t nfiles, + const message *tail, size_t ntail); + +/* ------------------------------------------------------------------ */ +/* SelfCompact-style rubric probe (arXiv:2606.23525) */ +/* ------------------------------------------------------------------ */ + +/* Fire-gate thresholds from the paper. max_summaries 0 = unlimited. */ +#define RUBRIC_MIN_ITERATION 3UL +#define RUBRIC_MIN_TOKENS 40000UL +#define RUBRIC_MIN_ROUNDS_SINCE_PROBE 2UL +#define RUBRIC_DEFAULT_MAX_SUMMARIES 1UL + +/* Verdict of a rubric probe. Each field: 1 = Y, 0 = N. */ +typedef struct { + int c1; /* CLOSED-UNIT: last assistant message is a closed unit */ + int c2; /* SUMMARIZABLE: value fits 3-5 citable facts */ + int c3; /* PROGRESS: something advanced since last compression */ + int n1; /* STUCK: recent tool calls yield nothing new */ +} compact_rubric; + +/* System preamble for the rubric judge (kept out of the summarizer's + * "write a summary" role). */ +const char *compact_rubric_preamble(void); + +/* The probe prompt (the paper's search rubric, adapted to tool calls). */ +const char *compact_rubric_prompt(void); + +/* Parse the four `C1/C2/C3/N1: Y|N -- <evidence>` lines. A Y without + * evidence on its line is downgraded to N (the paper's rule). `out` must + * be non-NULL; 0 on success, -1 with owned *err when a verdict is missing + * or malformed. */ +int compact_rubric_parse(const char *answer, compact_rubric *out, char **err); + +/* Fire only when C1 and C2 and C3 are all Y and N1 is N. */ +bool compact_rubric_fire(const compact_rubric *r); + +/* Gate check: iteration (tool rounds) >= 3, prompt >= 40k tokens, + * summaries so far < cap (0 = unlimited), and >= 2 tool rounds since the + * last probe. */ +bool compact_rubric_due(unsigned long iteration, unsigned long prompt_tokens, + unsigned long summaries_so_far, + unsigned long max_summaries, + unsigned long rounds_since_probe); + +#endif |