Compare commits

...
5 Commits
8 changed files with 174 additions and 21422 deletions
+2 -2
View File
@@ -54,11 +54,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e
Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.
## Current Status — v0.2.2
## Current Status — v0.2.7
**Active build — this project is barely working. Experiment at your own risk.**
> Last release update: v0.2.2Re-apply v0.2.0 migration after history rewrite rollback
> Last release update: v0.2.7Fix default_admin_dm inline variable resolution for my_kind0_profile and my_npub
- Connects to configured relays with auto-reconnect and relay state transition logging
- Publishes configured startup events per relay as each relay becomes connected
+98 -21291
View File
File diff suppressed because it is too large Load Diff
+22 -4
View File
@@ -299,11 +299,29 @@ git_commit_and_push_no_tag() {
# Push changes
print_status "Pushing to remote repository..."
if git push > /dev/null 2>&1; then
print_success "Pushed changes"
local current_branch
current_branch=$(git branch --show-current 2>/dev/null || echo "")
if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" > /dev/null 2>&1; then
if git push > /dev/null 2>&1; then
print_success "Pushed changes"
else
print_error "Failed to push changes"
exit 1
fi
else
print_error "Failed to push changes"
exit 1
if [[ -z "$current_branch" ]]; then
print_error "Unable to determine current branch for push"
exit 1
fi
print_warning "No upstream configured for branch '$current_branch'; setting upstream to origin/$current_branch"
if git push -u origin "$current_branch" > /dev/null 2>&1; then
print_success "Pushed changes and configured upstream"
else
print_error "Failed to push changes while configuring upstream"
exit 1
fi
fi
# Push only the new tag to avoid conflicts with existing tags
+25 -117
View File
@@ -15,6 +15,7 @@
#include "nostr_handler.h"
#include "trigger_manager.h"
#include "tools/tools.h"
#include "prompt_template.h"
#include "cjson/cJSON.h"
#include "debug.h"
#include "../../nostr_core_lib/nostr_core/nostr_core.h"
@@ -1126,7 +1127,7 @@ static const char* get_context_part_name_copy(int idx) {
return tls_name[0] ? tls_name : NULL;
}
static void template_emit_hook(const char* section_name, int message_index, void* user_data) {
static __attribute__((unused)) void template_emit_hook(const char* section_name, int message_index, void* user_data) {
(void)user_data;
set_context_part_name(message_index, section_name ? section_name : "context_part");
}
@@ -1250,7 +1251,7 @@ void agent_append_context_log(const char* sender_pubkey_hex, const char* phase,
}
static char* build_sender_verification_text(didactyl_sender_tier_t sender_tier) {
static __attribute__((unused)) char* build_sender_verification_text(didactyl_sender_tier_t sender_tier) {
if (sender_tier == DIDACTYL_SENDER_ADMIN) {
return strdup("This message has been cryptographically verified as coming from your administrator.");
}
@@ -1450,114 +1451,7 @@ static const char* template_skill_lookup_callback(void* user_data, const char* d
}
static char* resolve_skill_references_local(const char* input) {
if (!input) {
return strdup("");
}
size_t cap = strlen(input) + 128U;
size_t used = 0U;
char* out = (char*)malloc(cap);
if (!out) return NULL;
out[0] = '\0';
const char* p = input;
while (*p) {
const char* open = strstr(p, "{{");
if (!open) {
size_t tail = strlen(p);
if (used + tail + 1U > cap) {
size_t next = cap;
while (used + tail + 1U > next) next *= 2U;
char* grown = (char*)realloc(out, next);
if (!grown) {
free(out);
return NULL;
}
out = grown;
cap = next;
}
memcpy(out + used, p, tail);
used += tail;
out[used] = '\0';
break;
}
size_t prefix_len = (size_t)(open - p);
if (used + prefix_len + 1U > cap) {
size_t next = cap;
while (used + prefix_len + 1U > next) next *= 2U;
char* grown = (char*)realloc(out, next);
if (!grown) {
free(out);
return NULL;
}
out = grown;
cap = next;
}
memcpy(out + used, p, prefix_len);
used += prefix_len;
out[used] = '\0';
const char* close = strstr(open + 2, "}}");
if (!close) {
size_t rem = strlen(open);
if (used + rem + 1U > cap) {
size_t next = cap;
while (used + rem + 1U > next) next *= 2U;
char* grown = (char*)realloc(out, next);
if (!grown) {
free(out);
return NULL;
}
out = grown;
cap = next;
}
memcpy(out + used, open, rem);
used += rem;
out[used] = '\0';
break;
}
size_t var_len = (size_t)(close - (open + 2));
char var[128];
if (var_len >= sizeof(var)) var_len = sizeof(var) - 1U;
memcpy(var, open + 2, var_len);
var[var_len] = '\0';
char* start = var;
while (*start && isspace((unsigned char)*start)) start++;
char* end = start + strlen(start);
while (end > start && isspace((unsigned char)end[-1])) {
end[-1] = '\0';
end--;
}
const char* repl = "";
pthread_mutex_lock(&g_adopted_skills_mutex);
const char* found = adopted_skill_content_lookup_by_d_tag_locked(start);
repl = found ? found : "";
pthread_mutex_unlock(&g_adopted_skills_mutex);
size_t repl_len = strlen(repl);
if (used + repl_len + 1U > cap) {
size_t next = cap;
while (used + repl_len + 1U > next) next *= 2U;
char* grown = (char*)realloc(out, next);
if (!grown) {
free(out);
return NULL;
}
out = grown;
cap = next;
}
memcpy(out + used, repl, repl_len);
used += repl_len;
out[used] = '\0';
p = close + 2;
}
return out;
return prompt_template_resolve_inline_variables(input ? input : "", &g_tools_ctx);
}
static char* build_context_from_triggers(trigger_type_t trigger_type,
@@ -1596,8 +1490,12 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
}
}
char* matched_skill_contents[AGENT_ADOPTED_SKILLS_MAX];
int matched_skill_count = 0;
memset(matched_skill_contents, 0, sizeof(matched_skill_contents));
pthread_mutex_lock(&g_adopted_skills_mutex);
for (int i = 0; i < g_adopted_skills_count; i++) {
for (int i = 0; i < g_adopted_skills_count && matched_skill_count < AGENT_ADOPTED_SKILLS_MAX; i++) {
const agent_adopted_skill_t* s = &g_adopted_skills[i];
if (!s->has_trigger || s->trigger_type != trigger_type) {
continue;
@@ -1606,8 +1504,16 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
continue;
}
char* expanded = resolve_skill_references_local(s->content ? s->content : "");
const char* skill_text = expanded ? expanded : (s->content ? s->content : "");
matched_skill_contents[matched_skill_count] = strdup(s->content ? s->content : "");
if (matched_skill_contents[matched_skill_count]) {
matched_skill_count++;
}
}
pthread_mutex_unlock(&g_adopted_skills_mutex);
for (int i = 0; i < matched_skill_count; i++) {
char* expanded = resolve_skill_references_local(matched_skill_contents[i] ? matched_skill_contents[i] : "");
const char* skill_text = expanded ? expanded : (matched_skill_contents[i] ? matched_skill_contents[i] : "");
size_t need = strlen("\n\n---\n\n") + strlen(skill_text) + 1U;
if (used + need >= cap) {
@@ -1616,7 +1522,9 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
char* grown = (char*)realloc(out, next);
if (!grown) {
free(expanded);
pthread_mutex_unlock(&g_adopted_skills_mutex);
for (int j = i; j < matched_skill_count; j++) {
free(matched_skill_contents[j]);
}
free(out);
return NULL;
}
@@ -1635,8 +1543,8 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
matched++;
free(expanded);
free(matched_skill_contents[i]);
}
pthread_mutex_unlock(&g_adopted_skills_mutex);
if (matched == 0) {
const char* fallback = "You are an AI agent. Respond to the message.";
@@ -1968,7 +1876,7 @@ static char* flatten_skill_content_to_text(const char* skill_content) {
return out;
}
static int append_adopted_skills_context(cJSON* messages) {
static __attribute__((unused)) int append_adopted_skills_context(cJSON* messages) {
if (!messages || !g_cfg) {
return -1;
}
@@ -2078,7 +1986,7 @@ static int append_adopted_skills_context(cJSON* messages) {
return rc;
}
static cJSON* build_recent_admin_dm_history_messages(const char* current_message) {
static __attribute__((unused)) cJSON* build_recent_admin_dm_history_messages(const char* current_message) {
cJSON* messages = cJSON_CreateArray();
if (!messages) {
return NULL;
+23 -4
View File
@@ -56,8 +56,15 @@ static void on_self_skill_eose_load_triggers(int event_count, void* user_data) {
}
}
static volatile sig_atomic_t g_sigint_count = 0;
static void signal_handler(int signum) {
(void)signum;
if (signum == SIGINT) {
g_sigint_count++;
if (g_sigint_count >= 2) {
_exit(130);
}
}
g_running = 0;
}
@@ -1442,9 +1449,21 @@ int main(int argc, char** argv) {
}
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGPIPE, SIG_IGN);
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
(void)sigaction(SIGINT, &sa, NULL);
(void)sigaction(SIGTERM, &sa, NULL);
struct sigaction sa_pipe;
memset(&sa_pipe, 0, sizeof(sa_pipe));
sa_pipe.sa_handler = SIG_IGN;
sigemptyset(&sa_pipe.sa_mask);
sa_pipe.sa_flags = 0;
(void)sigaction(SIGPIPE, &sa_pipe, NULL);
int http_api_started = 0;
if (cfg.api.enabled) {
+2 -2
View File
@@ -12,8 +12,8 @@
// Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros
#define DIDACTYL_VERSION_MAJOR 0
#define DIDACTYL_VERSION_MINOR 2
#define DIDACTYL_VERSION_PATCH 2
#define DIDACTYL_VERSION "v0.2.2"
#define DIDACTYL_VERSION_PATCH 7
#define DIDACTYL_VERSION "v0.2.7"
// Agent metadata
#define DIDACTYL_NAME "Didactyl"
+1 -1
View File
@@ -999,7 +999,7 @@ static int parse_enabled_flag_local(const char* enabled_s) {
return (strcmp(enabled_s, "false") == 0 || strcmp(enabled_s, "0") == 0) ? 0 : 1;
}
static int parse_skill_address_local(const char* addr, int* out_kind, char out_pubkey_hex[65], char out_d_tag[65]) {
static __attribute__((unused)) int parse_skill_address_local(const char* addr, int* out_kind, char out_pubkey_hex[65], char out_d_tag[65]) {
if (!addr || !out_kind || !out_pubkey_hex || !out_d_tag) {
return -1;
}
+1 -1
View File
@@ -490,7 +490,7 @@ static cJSON* find_tag_value_string(cJSON* tags, const char* key) {
return NULL;
}
static int parse_address_tag(const char* addr, int* out_kind, char out_pubkey[65], char out_d_tag[65]) {
static __attribute__((unused)) int parse_address_tag(const char* addr, int* out_kind, char out_pubkey[65], char out_d_tag[65]) {
if (!addr || !out_kind || !out_pubkey || !out_d_tag) {
return -1;
}