mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
472 lines
17 KiB
C
472 lines
17 KiB
C
/*
|
|
* Tardygrada — Executor Implementation
|
|
*
|
|
* Walks the instruction list, spawns agents on the VM.
|
|
* Then starts the MCP server so the world can connect.
|
|
*/
|
|
|
|
#include "exec.h"
|
|
#include "vm/util.h"
|
|
#include "terraform.h"
|
|
#include "../verify/pipeline.h"
|
|
#include "../coordinate/bridge.h"
|
|
#include <sys/mman.h>
|
|
#include <sys/wait.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
static void exec_print(const char *s)
|
|
{
|
|
tardy_write(STDERR_FILENO, s, strlen(s));
|
|
}
|
|
|
|
int tardy_exec(tardy_vm_t *vm, const tardy_program_t *prog)
|
|
{
|
|
if (!vm || !prog)
|
|
return -1;
|
|
|
|
tardy_uuid_t current_agent = vm->root_id;
|
|
|
|
for (int i = 0; i < prog->count; i++) {
|
|
const tardy_instruction_t *inst = &prog->instructions[i];
|
|
|
|
switch (inst->opcode) {
|
|
case OP_SPAWN_AGENT: {
|
|
/* Create a named agent in root context */
|
|
int64_t zero = 0;
|
|
tardy_uuid_t id = tardy_vm_spawn(vm, vm->root_id,
|
|
inst->name,
|
|
TARDY_TYPE_AGENT,
|
|
inst->trust,
|
|
&zero, sizeof(int64_t));
|
|
tardy_agent_t *agent = tardy_vm_find(vm, id);
|
|
if (agent)
|
|
current_agent = id;
|
|
|
|
exec_print("[tardygrada] agent ");
|
|
exec_print(inst->name);
|
|
exec_print(" spawned\n");
|
|
break;
|
|
}
|
|
|
|
case OP_SPAWN_VALUE: {
|
|
/* Create a value agent in current agent's context */
|
|
switch (inst->type) {
|
|
case TARDY_TYPE_INT: {
|
|
int64_t val = inst->int_val;
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_INT, inst->trust,
|
|
&val, sizeof(int64_t));
|
|
break;
|
|
}
|
|
case TARDY_TYPE_FLOAT: {
|
|
double val = inst->float_val;
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_FLOAT, inst->trust,
|
|
&val, sizeof(double));
|
|
break;
|
|
}
|
|
case TARDY_TYPE_STR: {
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, inst->trust,
|
|
inst->str_val, strlen(inst->str_val) + 1);
|
|
break;
|
|
}
|
|
case TARDY_TYPE_BOOL: {
|
|
int64_t val = inst->bool_val ? 1 : 0;
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_BOOL, inst->trust,
|
|
&val, sizeof(int64_t));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
exec_print("[tardygrada] ");
|
|
if (inst->trust >= TARDY_TRUST_DEFAULT)
|
|
exec_print("let ");
|
|
exec_print(inst->name);
|
|
exec_print(" = ...");
|
|
if (inst->trust == TARDY_TRUST_VERIFIED)
|
|
exec_print(" @verified");
|
|
else if (inst->trust == TARDY_TRUST_HARDENED)
|
|
exec_print(" @hardened");
|
|
else if (inst->trust == TARDY_TRUST_SOVEREIGN)
|
|
exec_print(" @sovereign");
|
|
exec_print("\n");
|
|
break;
|
|
}
|
|
|
|
case OP_RECEIVE: {
|
|
exec_print("[tardygrada] receive(\"");
|
|
exec_print(inst->str_val);
|
|
exec_print("\")");
|
|
if (inst->grounded) {
|
|
exec_print(" grounded_in(");
|
|
exec_print(inst->ontology);
|
|
exec_print(")");
|
|
}
|
|
exec_print(" -> pending\n");
|
|
|
|
/* Spawn empty mutable agent (will be filled via MCP submit_claim) */
|
|
const char *empty = "";
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, TARDY_TRUST_MUTABLE,
|
|
empty, 1);
|
|
break;
|
|
}
|
|
|
|
case OP_EXEC: {
|
|
exec_print("[tardygrada] exec(\"");
|
|
exec_print(inst->str_val);
|
|
exec_print("\")\n");
|
|
|
|
/* Fork and exec the command, capture stdout */
|
|
int pipefd[2];
|
|
if (pipe(pipefd) < 0) {
|
|
exec_print("[tardygrada] pipe failed\n");
|
|
const char *err = "exec: pipe failed";
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, TARDY_TRUST_MUTABLE,
|
|
err, strlen(err) + 1);
|
|
break;
|
|
}
|
|
|
|
pid_t pid = fork();
|
|
if (pid < 0) {
|
|
close(pipefd[0]);
|
|
close(pipefd[1]);
|
|
const char *err = "exec: fork failed";
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, TARDY_TRUST_MUTABLE,
|
|
err, strlen(err) + 1);
|
|
break;
|
|
}
|
|
|
|
if (pid == 0) {
|
|
/* Child: redirect stdout to pipe, exec shell */
|
|
close(pipefd[0]);
|
|
dup2(pipefd[1], STDOUT_FILENO);
|
|
close(pipefd[1]);
|
|
/* Redirect stderr to /dev/null */
|
|
int devnull = open("/dev/null", O_WRONLY);
|
|
if (devnull >= 0) { dup2(devnull, STDERR_FILENO); close(devnull); }
|
|
execl("/bin/sh", "sh", "-c", inst->str_val, (char *)NULL);
|
|
_exit(127);
|
|
}
|
|
|
|
/* Parent: read output from pipe */
|
|
close(pipefd[1]);
|
|
char output[4096];
|
|
int total = 0;
|
|
ssize_t n;
|
|
while ((n = read(pipefd[0], output + total,
|
|
sizeof(output) - (size_t)total - 1)) > 0)
|
|
total += (int)n;
|
|
output[total] = '\0';
|
|
close(pipefd[0]);
|
|
|
|
int wstatus;
|
|
waitpid(pid, &wstatus, 0);
|
|
int exit_code = WIFEXITED(wstatus) ? WEXITSTATUS(wstatus) : -1;
|
|
|
|
/* Trim trailing newline */
|
|
while (total > 0 && (output[total - 1] == '\n' ||
|
|
output[total - 1] == '\r'))
|
|
output[--total] = '\0';
|
|
|
|
/* Log output preview */
|
|
exec_print("[tardygrada] -> \"");
|
|
{
|
|
size_t preview_len = (total > 0 && total < 80) ? (size_t)total : 80;
|
|
if (preview_len > (size_t)total && total > 0) preview_len = (size_t)total;
|
|
char preview[81];
|
|
memcpy(preview, output, preview_len);
|
|
preview[preview_len] = '\0';
|
|
exec_print(preview);
|
|
if (total > 80) exec_print("...");
|
|
}
|
|
exec_print("\" (exit ");
|
|
{
|
|
char ec[8];
|
|
ec[0] = '0' + (char)(exit_code % 10);
|
|
ec[1] = '\0';
|
|
exec_print(ec);
|
|
}
|
|
exec_print(")\n");
|
|
|
|
if (exit_code != 0 || total == 0) {
|
|
/* Command failed — spawn as mutable with error info */
|
|
char err_msg[256];
|
|
int elen = snprintf(err_msg, sizeof(err_msg),
|
|
"exec failed (exit %d): %.200s",
|
|
exit_code, output);
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, TARDY_TRUST_MUTABLE,
|
|
err_msg, (size_t)elen + 1);
|
|
} else {
|
|
/* Command succeeded — spawn with output */
|
|
tardy_trust_t trust = inst->grounded ?
|
|
(inst->trust >= TARDY_TRUST_DEFAULT ?
|
|
inst->trust : TARDY_TRUST_MUTABLE) :
|
|
TARDY_TRUST_MUTABLE;
|
|
tardy_vm_spawn(vm, current_agent, inst->name,
|
|
TARDY_TYPE_STR, trust,
|
|
output, (size_t)total + 1);
|
|
}
|
|
|
|
/* Record in conversation */
|
|
tardy_agent_t *spawned = tardy_vm_find_by_name(
|
|
vm, current_agent, inst->name);
|
|
if (spawned) {
|
|
char conv[512];
|
|
snprintf(conv, sizeof(conv), "exec: %.400s", inst->str_val);
|
|
tardy_vm_converse(vm, spawned->id, "system", conv);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OP_FORK:
|
|
tardy_fork(vm, current_agent, inst->str_val,
|
|
inst->name[0] ? inst->name : NULL);
|
|
break;
|
|
|
|
case OP_FREEZE: {
|
|
exec_print("[tardygrada] freeze ");
|
|
exec_print(inst->name);
|
|
if (inst->trust == TARDY_TRUST_VERIFIED) exec_print(" @verified");
|
|
else if (inst->trust == TARDY_TRUST_HARDENED) exec_print(" @hardened");
|
|
else if (inst->trust == TARDY_TRUST_SOVEREIGN) exec_print(" @sovereign");
|
|
exec_print("\n");
|
|
|
|
tardy_agent_t *target = tardy_vm_find_by_name(vm, current_agent, inst->name);
|
|
if (target) {
|
|
tardy_uuid_t frozen = tardy_vm_freeze(vm, target->id, inst->trust);
|
|
if (frozen.hi == 0 && frozen.lo == 0) {
|
|
exec_print("[tardygrada] freeze failed (already immutable?)\n");
|
|
}
|
|
} else {
|
|
exec_print("[tardygrada] agent not found: ");
|
|
exec_print(inst->name);
|
|
exec_print("\n");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case OP_SET_SEMANTICS: {
|
|
exec_print("[tardygrada] @semantics(");
|
|
exec_print(inst->sem_key);
|
|
exec_print(": ");
|
|
exec_print(inst->sem_value);
|
|
exec_print(")\n");
|
|
|
|
/* Apply semantics override to current agent */
|
|
const tardy_semantics_t *current_sem =
|
|
tardy_vm_get_semantics(vm, current_agent);
|
|
tardy_semantics_t updated = *current_sem;
|
|
|
|
/* Parse key and set value */
|
|
if (strcmp(inst->sem_key, "truth.min_confidence") == 0) {
|
|
float f = 0.0f;
|
|
const char *s = inst->sem_value;
|
|
int i = 0;
|
|
for (; s[i] && s[i] != '.'; i++) f = f * 10.0f + (s[i] - '0');
|
|
if (s[i] == '.') {
|
|
i++;
|
|
float frac = 0.1f;
|
|
for (; s[i]; i++) { f += (s[i] - '0') * frac; frac *= 0.1f; }
|
|
}
|
|
updated.truth.min_confidence = f;
|
|
} else if (strcmp(inst->sem_key, "truth.min_consensus_agents") == 0) {
|
|
updated.truth.min_consensus_agents = (int)inst->int_val;
|
|
if (updated.truth.min_consensus_agents == 0) {
|
|
/* Parse from string */
|
|
int v = 0;
|
|
const char *s = inst->sem_value;
|
|
for (int i = 0; s[i]; i++) v = v * 10 + (s[i] - '0');
|
|
updated.truth.min_consensus_agents = v;
|
|
}
|
|
} else if (strcmp(inst->sem_key, "pipeline.min_passing_layers") == 0) {
|
|
int v = 0;
|
|
const char *s = inst->sem_value;
|
|
for (int i = 0; s[i]; i++) v = v * 10 + (s[i] - '0');
|
|
updated.pipeline.min_passing_layers = v;
|
|
}
|
|
|
|
tardy_vm_set_semantics(vm, current_agent, &updated);
|
|
break;
|
|
}
|
|
|
|
case OP_COORDINATE: {
|
|
exec_print("[tardygrada] coordinate {");
|
|
exec_print(inst->coord_agents);
|
|
exec_print("} on(\"");
|
|
exec_print(inst->coord_task);
|
|
exec_print("\")\n");
|
|
|
|
/* Parse comma-separated agent names */
|
|
char names[256];
|
|
strncpy(names, inst->coord_agents, sizeof(names) - 1);
|
|
names[sizeof(names) - 1] = '\0';
|
|
|
|
tardy_uuid_t agent_ids[16];
|
|
int agent_count = 0;
|
|
char *tok = names;
|
|
char *next;
|
|
while (tok && agent_count < 16) {
|
|
next = strchr(tok, ',');
|
|
if (next) *next = '\0';
|
|
/* Trim whitespace */
|
|
while (*tok == ' ') tok++;
|
|
char *end = tok + strlen(tok) - 1;
|
|
while (end > tok && *end == ' ') *end-- = '\0';
|
|
|
|
if (*tok) {
|
|
tardy_agent_t *a = tardy_vm_find_by_name(vm, current_agent, tok);
|
|
if (a) {
|
|
agent_ids[agent_count++] = a->id;
|
|
} else {
|
|
exec_print("[tardygrada] agent not found: ");
|
|
exec_print(tok);
|
|
exec_print("\n");
|
|
}
|
|
}
|
|
tok = next ? next + 1 : NULL;
|
|
}
|
|
|
|
if (agent_count < 2) {
|
|
exec_print("[tardygrada] need at least 2 agents for coordination\n");
|
|
break;
|
|
}
|
|
|
|
/* Try brain-in-the-fish coordination engine first */
|
|
tardy_bitf_conn_t bitf;
|
|
int bitf_ok = tardy_bitf_connect(&bitf, TARDY_BITF_SOCKET_PATH);
|
|
|
|
if (bitf_ok == 0) {
|
|
exec_print("[tardygrada] brain-in-the-fish connected\n");
|
|
|
|
/* Collect agent name strings */
|
|
char names2[256];
|
|
strncpy(names2, inst->coord_agents, sizeof(names2) - 1);
|
|
names2[sizeof(names2) - 1] = '\0';
|
|
const char *agent_strs[16];
|
|
int asc = 0;
|
|
char *t2 = names2;
|
|
char *n2;
|
|
while (t2 && asc < 16) {
|
|
n2 = strchr(t2, ',');
|
|
if (n2) *n2 = '\0';
|
|
while (*t2 == ' ') t2++;
|
|
if (*t2) agent_strs[asc++] = t2;
|
|
t2 = n2 ? n2 + 1 : NULL;
|
|
}
|
|
|
|
tardy_bitf_result_t result;
|
|
tardy_bitf_coordinate(&bitf, inst->coord_task,
|
|
agent_strs, asc, &result);
|
|
tardy_bitf_disconnect(&bitf);
|
|
|
|
if (result.success) {
|
|
char msg[128];
|
|
snprintf(msg, sizeof(msg),
|
|
"[tardygrada] consensus: confidence=%.0f%% rounds=%d\n",
|
|
result.confidence * 100, result.rounds);
|
|
exec_print(msg);
|
|
} else {
|
|
exec_print("[tardygrada] coordination failed: ");
|
|
exec_print(result.error);
|
|
exec_print("\n");
|
|
}
|
|
} else {
|
|
/* Fallback: send task to agent inboxes */
|
|
for (int ci = 0; ci < agent_count; ci++) {
|
|
tardy_vm_send(vm, current_agent, agent_ids[ci],
|
|
inst->coord_task,
|
|
strlen(inst->coord_task) + 1,
|
|
TARDY_TYPE_STR);
|
|
}
|
|
|
|
exec_print("[tardygrada] dispatched to ");
|
|
char cntstr[8];
|
|
cntstr[0] = '0' + (char)agent_count;
|
|
cntstr[1] = '\0';
|
|
exec_print(cntstr);
|
|
exec_print(" agents (bitf offline)\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OP_ADD_INVARIANT: {
|
|
exec_print("[tardygrada] invariant(");
|
|
/* Print invariant type */
|
|
switch (inst->invariant_type) {
|
|
case 0: exec_print("type_check"); break;
|
|
case 1: exec_print("range"); break;
|
|
case 2: exec_print("non_empty"); break;
|
|
case 3: exec_print("trust_min"); break;
|
|
default: exec_print("unknown"); break;
|
|
}
|
|
exec_print(")\n");
|
|
|
|
/* Add invariant to current agent's constitution */
|
|
tardy_agent_t *agent = tardy_vm_find(vm, current_agent);
|
|
if (agent) {
|
|
tardy_invariant_t inv = {0};
|
|
inv.type = (tardy_invariant_type_t)inst->invariant_type;
|
|
inv.min_val = inst->inv_min;
|
|
inv.max_val = inst->inv_max;
|
|
inv.trust_arg = inst->inv_trust;
|
|
tardy_constitution_add(&agent->constitution, inv);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case OP_HALT:
|
|
exec_print("[tardygrada] program loaded\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tardy_exec_file(const char *path)
|
|
{
|
|
/* Compile */
|
|
tardy_program_t prog;
|
|
if (tardy_compile_file(&prog, path) != 0) {
|
|
exec_print("[tardygrada] compile error: ");
|
|
exec_print(prog.error);
|
|
exec_print("\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Create VM */
|
|
tardy_vm_t *vm = (tardy_vm_t *)mmap(NULL, sizeof(tardy_vm_t),
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (vm == MAP_FAILED)
|
|
return 1;
|
|
|
|
tardy_vm_init(vm, NULL);
|
|
|
|
/* Execute program */
|
|
tardy_exec(vm, &prog);
|
|
|
|
/* Start MCP server */
|
|
exec_print("[tardygrada] MCP server starting on stdio\n");
|
|
tardy_mcp_server_t srv;
|
|
tardy_mcp_init(&srv, vm);
|
|
tardy_mcp_run(&srv);
|
|
|
|
/* Cleanup */
|
|
tardy_vm_shutdown(vm);
|
|
munmap(vm, sizeof(tardy_vm_t));
|
|
return 0;
|
|
}
|