emerging.systems / src /context_store.c
compunerd's picture
Port full dashboard engine: phoenix_dashboard + agent_core + hyper_vocab_memory + bqsm_assist
bdf5f4a verified
Raw
History Blame Contribute Delete
8.7 kB
/* 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);
}