Spaces:
Running
Running
File size: 8,695 Bytes
bdf5f4a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | /* context_store.c — Universal pattern-triggered context injection.
*
* The regex-triggered skill loading pattern generalizes: ANY context
* (skills, tool docs, error recovery, codebase summaries, few-shot examples)
* is a (trigger, text) pair. The store matches all triggers against the
* current input and returns matching entries in priority order.
*
* This replaces static Pri0 with a dynamic lookup: instead of stuffing the
* system prompt with all possible instructions, only inject what matches
* the current request. Information capacity goes from "fits in system
* prompt" to "fits on disk."
*
* Triggers support: exact match, substring, regex (via callback if linked
* with PCRE2; otherwise substring fallback), and keyword intersection.
*
* Compile:
* cc -O3 -std=c11 -fPIC -shared context_store.c -o libcontext_store.so
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#define MAX_ENTRIES 128
#define MAX_TEXT_LEN 2048
#define MAX_TRIG_LEN 256
#define MATCH_EXACT 0
#define MATCH_SUBSTR 1
#define MATCH_KEYWORD 2
typedef struct {
char id[32];
char trigger[MAX_TRIG_LEN];
char text[MAX_TEXT_LEN];
int match_type; /* MATCH_EXACT, MATCH_SUBSTR, MATCH_KEYWORD */
int priority; /* 0=highest (error recovery), 9=lowest (general knowledge) */
int cooldown; /* skip this entry for N more calls after a hit */
} entry_t;
static entry_t g_store[MAX_ENTRIES];
static int g_count = 0;
static int g_hit_counts[MAX_ENTRIES]; /* for cooldown tracking */
/* ---- Public API ---- */
/* Add or update an entry. Returns index or -1 if store full. */
int store_add(const char *id, const char *trigger, const char *text,
int match_type, int priority) {
/* Update existing */
for (int i = 0; i < g_count; i++) {
if (strcmp(g_store[i].id, id) == 0) {
strncpy(g_store[i].trigger, trigger, MAX_TRIG_LEN-1);
strncpy(g_store[i].text, text, MAX_TEXT_LEN-1);
g_store[i].match_type = match_type;
g_store[i].priority = priority;
return i;
}
}
if (g_count >= MAX_ENTRIES) return -1;
int i = g_count++;
strncpy(g_store[i].id, id, 31);
strncpy(g_store[i].trigger, trigger, MAX_TRIG_LEN-1);
strncpy(g_store[i].text, text, MAX_TEXT_LEN-1);
g_store[i].match_type = match_type;
g_store[i].priority = priority;
g_store[i].cooldown = 0;
g_hit_counts[i] = 0;
return i;
}
void store_remove(const char *id) {
for (int i = 0; i < g_count; i++) {
if (strcmp(g_store[i].id, id) == 0) {
/* Shift remaining entries down */
memmove(&g_store[i], &g_store[i+1], (g_count - i - 1) * sizeof(entry_t));
memmove(&g_hit_counts[i], &g_hit_counts[i+1], (g_count - i - 1) * sizeof(int));
g_count--;
return;
}
}
}
/* Case-insensitive substring match */
static int ci_substr(const char *haystack, const char *needle) {
if (!*needle) return 1;
while (*haystack) {
const char *h = haystack, *n = needle;
while (*h && *n && tolower(*h) == tolower(*n)) { h++; n++; }
if (!*n) return 1;
haystack++;
}
return 0;
}
/* Check if a word from needle appears in haystack */
static int keyword_match(const char *haystack, const char *trigger) {
char word[64];
const char *p = trigger;
while (*p) {
while (*p == ' ' || *p == ',') p++;
if (!*p) break;
int len = 0;
while (p[len] && p[len] != ' ' && p[len] != ',' && len < 63) len++;
memcpy(word, p, len); word[len] = '\0';
p += len;
/* Check if this word appears in haystack */
const char *h = haystack;
while (*h) {
while (*h == ' ') h++;
const char *w = word;
const char *s = h;
while (*s && *w && tolower(*s) == tolower(*w)) { s++; w++; }
if (!*w && (!*s || *s == ' ' || *s == '\n')) return 1;
while (*h && *h != ' ') h++;
}
}
return 0;
}
/* Match an entry against input. Returns 1 if match. */
static int entry_matches(const entry_t *e, const char *input) {
switch (e->match_type) {
case MATCH_EXACT: return strcmp(input, e->trigger) == 0;
case MATCH_SUBSTR: return ci_substr(input, e->trigger);
case MATCH_KEYWORD: return keyword_match(input, e->trigger);
default: return 0;
}
}
/* Query the store. Returns matching entries in priority order as a
* concatenated string. max_tokens limits total output (est. 4 chars/tok).
* excluded_ids is a | separated list of ids to skip (already active).
* Copies result to buf (caller-owned, at least bufsz bytes). */
int store_query(const char *input, int max_tokens, const char *excluded_ids,
char *buf, int bufsz) {
int budget = max_tokens * 4;
int total = 0;
int included = 0;
buf[0] = '\0';
/* Collect matching indices, sorted by priority */
int matches[MAX_ENTRIES];
int nm = 0;
for (int i = 0; i < g_count; i++) {
if (g_store[i].cooldown > 0) { g_store[i].cooldown--; continue; }
if (!entry_matches(&g_store[i], input)) continue;
/* Check exclusion */
if (excluded_ids && *excluded_ids) {
char ex_copy[512];
strncpy(ex_copy, excluded_ids, 511);
char *tok = strtok(ex_copy, "|");
int skip = 0;
while (tok) {
if (strcmp(tok, g_store[i].id) == 0) { skip = 1; break; }
tok = strtok(NULL, "|");
}
if (skip) continue;
}
/* Insert sorted by priority */
int j;
for (j = nm; j > 0 && g_store[matches[j-1]].priority > g_store[i].priority; j--)
matches[j] = matches[j-1];
matches[j] = i;
nm++;
}
/* Write matching entries */
for (int m = 0; m < nm; m++) {
int i = matches[m];
int len = strlen(g_store[i].text);
if (total + len + 2 > budget && included > 0) break;
int to_write = len;
if (total + to_write + 2 > budget) to_write = budget - total - 2;
if (to_write <= 0) break;
if (included > 0) { buf[total++] = '\n'; buf[total] = '\0'; }
memcpy(buf + total, g_store[i].text, to_write);
total += to_write;
buf[total] = '\0';
included++;
/* Set cooldown to prevent re-triggering */
g_store[i].cooldown = 3;
g_hit_counts[i]++;
}
return included;
}
/* Get store stats */
int store_count(void) { return g_count; }
/* Seed the store with default entries. Call once at startup. */
void store_init_defaults(void) {
store_add("default-terminate",
"quit exit stop shutdown",
"To exit: type /exit or say 'quit'.",
MATCH_KEYWORD, 9);
store_add("error-oom",
"out of memory OOM killed memory error allocation failed",
"MEMORY FULL. Free RAM by: closing unused programs, reducing batch size, or using a smaller model. Current model: Hermes 3B Q4.",
MATCH_KEYWORD, 0);
store_add("error-timeout",
"timed out timeout hang frozen stuck",
"TIMEOUT DETECTED. The last operation took too long. Try: --no-mmap for faster loading, reduce max_tokens, or simplify the request.",
MATCH_KEYWORD, 0);
store_add("error-syntax",
"syntax error compilation error parse error unexpected token",
"SYNTAX ERROR. Check: missing semicolons, unmatched braces, wrong variable types. Compile with -Wall to see all warnings.",
MATCH_KEYWORD, 1);
store_add("tool-terminal",
"terminal shell bash command cmd execute run",
"TERMINAL: use terminal('command') tool. Always quote paths with spaces. Set timeout for long operations. Check exit code before proceeding.",
MATCH_KEYWORD, 3);
store_add("tool-file",
"file read write save open edit",
"FILES: use read_file(path) and write_file(path,content). Never write outside the project directory. Check file exists before reading.",
MATCH_KEYWORD, 3);
store_add("tool-git",
"git commit push pull branch merge rebase",
"GIT: use terminal with git commands. NEVER force push to main. Create feature branches. Commit messages should be descriptive.",
MATCH_KEYWORD, 3);
store_add("pattern-search",
"search find grep locate look for",
"SEARCH: use search_files(pattern) for content, or terminal('find ...') for filenames. Be specific in patterns to reduce noise.",
MATCH_KEYWORD, 4);
} |