summaryrefslogtreecommitdiffstats
path: root/src/compact.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/compact.h')
-rw-r--r--src/compact.h124
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