v0.2.26 - Add immediate adopted-skill cache invalidation on skill events plus new skill_refresh tool and /skill_refresh support

This commit is contained in:
Didactyl User
2026-04-06 06:08:25 -04:00
parent 6ad668b693
commit 656d251a2a
9 changed files with 55 additions and 4 deletions

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. 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.25 ## Current Status — v0.2.26
**Active build — this project is barely working. Experiment at your own risk.** **Active build — this project is barely working. Experiment at your own risk.**
> Last release update: v0.2.25Fix private skill interoperability: NIP-44 encode/decode for kind 31124 with runtime tag normalization > Last release update: v0.2.26Add immediate adopted-skill cache invalidation on skill events plus new skill_refresh tool and /skill_refresh support
- Connects to configured relays with auto-reconnect and relay state transition logging - Connects to configured relays with auto-reconnect and relay state transition logging
- Publishes configured startup events per relay as each relay becomes connected - Publishes configured startup events per relay as each relay becomes connected

View File

@@ -1579,6 +1579,12 @@ static void clear_adopted_skills_cache_locked(void) {
g_adopted_skills_count = 0; g_adopted_skills_count = 0;
} }
void agent_invalidate_adopted_skills_cache(void) {
pthread_mutex_lock(&g_adopted_skills_mutex);
g_adopted_skills_last_refresh_at = 0;
pthread_mutex_unlock(&g_adopted_skills_mutex);
}
static int refresh_adopted_skills_cache_if_needed(void) { static int refresh_adopted_skills_cache_if_needed(void) {
if (!g_cfg) { if (!g_cfg) {
return -1; return -1;
@@ -2165,7 +2171,10 @@ int agent_build_admin_messages_json(const char* current_user_message,
(sender_tier == DIDACTYL_SENDER_WOT ? "wot" : "stranger")); (sender_tier == DIDACTYL_SENDER_WOT ? "wot" : "stranger"));
cJSON_AddNumberToObject(dm_event, "created_at", (double)time(NULL)); cJSON_AddNumberToObject(dm_event, "created_at", (double)time(NULL));
const char* prev_current_user_message = g_tools_ctx.template_current_user_message;
g_tools_ctx.template_current_user_message = current_user_message ? current_user_message : "";
char* composed_context = build_context_from_triggers(TRIGGER_TYPE_DM, NULL, dm_event, "api"); char* composed_context = build_context_from_triggers(TRIGGER_TYPE_DM, NULL, dm_event, "api");
g_tools_ctx.template_current_user_message = prev_current_user_message;
cJSON_Delete(dm_event); cJSON_Delete(dm_event);
if (!composed_context) { if (!composed_context) {
composed_context = strdup("You are an AI agent. Respond to the message."); composed_context = strdup("You are an AI agent. Respond to the message.");
@@ -2256,7 +2265,10 @@ void agent_on_message(const char* sender_pubkey_hex,
(tier == DIDACTYL_SENDER_WOT ? "wot" : "stranger")); (tier == DIDACTYL_SENDER_WOT ? "wot" : "stranger"));
cJSON_AddNumberToObject(dm_event, "created_at", (double)time(NULL)); cJSON_AddNumberToObject(dm_event, "created_at", (double)time(NULL));
const char* prev_current_user_message = g_tools_ctx.template_current_user_message;
g_tools_ctx.template_current_user_message = message ? message : "";
char* dm_context = build_context_from_triggers(TRIGGER_TYPE_DM, NULL, dm_event, "dm"); char* dm_context = build_context_from_triggers(TRIGGER_TYPE_DM, NULL, dm_event, "dm");
g_tools_ctx.template_current_user_message = prev_current_user_message;
cJSON_Delete(dm_event); cJSON_Delete(dm_event);
if (!dm_context) { if (!dm_context) {
dm_context = strdup("You are an AI agent. Respond to the message."); dm_context = strdup("You are an AI agent. Respond to the message.");

View File

@@ -25,6 +25,7 @@ tools_context_t* agent_tools_context(void);
const char* agent_classify_message_part(cJSON* msg, int idx); const char* agent_classify_message_part(cJSON* msg, int idx);
int agent_set_context_debug_mode(const char* mode); int agent_set_context_debug_mode(const char* mode);
void agent_append_context_log(const char* sender_pubkey_hex, const char* phase, const char* context_payload); void agent_append_context_log(const char* sender_pubkey_hex, const char* phase, const char* context_payload);
void agent_invalidate_adopted_skills_cache(void);
void agent_cleanup(void); void agent_cleanup(void);
#endif #endif

View File

@@ -12,8 +12,8 @@
// Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros // Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros
#define DIDACTYL_VERSION_MAJOR 0 #define DIDACTYL_VERSION_MAJOR 0
#define DIDACTYL_VERSION_MINOR 2 #define DIDACTYL_VERSION_MINOR 2
#define DIDACTYL_VERSION_PATCH 25 #define DIDACTYL_VERSION_PATCH 26
#define DIDACTYL_VERSION "v0.2.25" #define DIDACTYL_VERSION "v0.2.26"
// Agent metadata // Agent metadata
#define DIDACTYL_NAME "Didactyl" #define DIDACTYL_NAME "Didactyl"

View File

@@ -14,6 +14,7 @@
#include "trigger_manager.h" #include "trigger_manager.h"
#include "nostr_block_list.h" #include "nostr_block_list.h"
#include "cashu_wallet.h" #include "cashu_wallet.h"
#include "agent.h"
#define NIP17_MAX_RELAYS 32 #define NIP17_MAX_RELAYS 32
#define NIP17_MAX_GIFT_WRAPS 8 #define NIP17_MAX_GIFT_WRAPS 8
@@ -2445,6 +2446,8 @@ static void on_self_skill_event(cJSON* event, const char* relay_url, void* user_
pthread_mutex_lock(&g_self_skill_mutex); pthread_mutex_lock(&g_self_skill_mutex);
self_skill_cache_upsert_event_locked(event); self_skill_cache_upsert_event_locked(event);
pthread_mutex_unlock(&g_self_skill_mutex); pthread_mutex_unlock(&g_self_skill_mutex);
agent_invalidate_adopted_skills_cache();
} }
static void on_wallet_event(cJSON* event, const char* relay_url, void* user_data) { static void on_wallet_event(cJSON* event, const char* relay_url, void* user_data) {

View File

@@ -11,6 +11,7 @@
#include "../debug.h" #include "../debug.h"
#include "../nostr_handler.h" #include "../nostr_handler.h"
#include "../trigger_manager.h" #include "../trigger_manager.h"
#include "../agent.h"
static char* json_error_local(const char* msg) { static char* json_error_local(const char* msg) {
cJSON* root = cJSON_CreateObject(); cJSON* root = cJSON_CreateObject();
@@ -1769,6 +1770,21 @@ char* execute_skill_edit(tools_context_t* ctx, const char* args_json) {
return json; return json;
} }
char* execute_skill_refresh(tools_context_t* ctx, const char* args_json) {
(void)args_json;
if (!ctx || !ctx->cfg) return json_error_local("tool context unavailable");
agent_invalidate_adopted_skills_cache();
cJSON* out = cJSON_CreateObject();
if (!out) return NULL;
cJSON_AddBoolToObject(out, "success", 1);
cJSON_AddStringToObject(out, "message", "adopted skills cache invalidated; next context build will reload skills");
char* json = cJSON_PrintUnformatted(out);
cJSON_Delete(out);
return json;
}
char* execute_skill_search(const char* args_json) { char* execute_skill_search(const char* args_json) {
cJSON* args = parse_args_local(args_json); cJSON* args = parse_args_local(args_json);
if (!args) return json_error_local("invalid arguments JSON"); if (!args) return json_error_local("invalid arguments JSON");

View File

@@ -152,6 +152,9 @@ char* tools_execute_legacy(tools_context_t* ctx, const char* tool_name, const ch
if (strcmp(tool_name, "skill_edit") == 0) { if (strcmp(tool_name, "skill_edit") == 0) {
return execute_skill_edit(ctx, args_json); return execute_skill_edit(ctx, args_json);
} }
if (strcmp(tool_name, "skill_refresh") == 0) {
return execute_skill_refresh(ctx, args_json);
}
if (strcmp(tool_name, "trigger_list") == 0) { if (strcmp(tool_name, "trigger_list") == 0) {
return execute_trigger_list(ctx, args_json); return execute_trigger_list(ctx, args_json);
} }

View File

@@ -63,6 +63,7 @@ char* execute_skill_set(tools_context_t* ctx, const char* args_json);
char* execute_skill_adopt(tools_context_t* ctx, const char* args_json); char* execute_skill_adopt(tools_context_t* ctx, const char* args_json);
char* execute_skill_remove(tools_context_t* ctx, const char* args_json); char* execute_skill_remove(tools_context_t* ctx, const char* args_json);
char* execute_skill_edit(tools_context_t* ctx, const char* args_json); char* execute_skill_edit(tools_context_t* ctx, const char* args_json);
char* execute_skill_refresh(tools_context_t* ctx, const char* args_json);
char* execute_skill_search(const char* args_json); char* execute_skill_search(const char* args_json);
char* execute_memory_save(tools_context_t* ctx, const char* args_json); char* execute_memory_save(tools_context_t* ctx, const char* args_json);

View File

@@ -1077,6 +1077,21 @@ char* tools_build_openai_schema_json_legacy(const tools_context_t* ctx) {
cJSON_AddItemToObject(t25b, "function", t25b_fn); cJSON_AddItemToObject(t25b, "function", t25b_fn);
cJSON_AddItemToArray(tools, t25b); cJSON_AddItemToArray(tools, t25b);
cJSON* t25c = cJSON_CreateObject();
cJSON* t25c_fn = cJSON_CreateObject();
cJSON* t25c_params = cJSON_CreateObject();
cJSON* t25c_props = cJSON_CreateObject();
cJSON_AddStringToObject(t25c, "type", "function");
cJSON_AddStringToObject(t25c_fn, "name", "skill_refresh");
cJSON_AddStringToObject(t25c_fn, "description", "Invalidate adopted skills cache so next context build reloads latest skill events from cache/relays");
cJSON_AddStringToObject(t25c_params, "type", "object");
cJSON_AddItemToObject(t25c_params, "properties", t25c_props);
cJSON_AddItemToObject(t25c_fn, "parameters", t25c_params);
cJSON_AddItemToObject(t25c, "function", t25c_fn);
cJSON_AddItemToArray(tools, t25c);
cJSON* t26 = cJSON_CreateObject(); cJSON* t26 = cJSON_CreateObject();
cJSON* t26_fn = cJSON_CreateObject(); cJSON* t26_fn = cJSON_CreateObject();
cJSON* t26_params = cJSON_CreateObject(); cJSON* t26_params = cJSON_CreateObject();