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.
## Current Status — v0.2.25
## Current Status — v0.2.26
**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
- 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;
}
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) {
if (!g_cfg) {
return -1;
@@ -2165,7 +2171,10 @@ int agent_build_admin_messages_json(const char* current_user_message,
(sender_tier == DIDACTYL_SENDER_WOT ? "wot" : "stranger"));
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");
g_tools_ctx.template_current_user_message = prev_current_user_message;
cJSON_Delete(dm_event);
if (!composed_context) {
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"));
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");
g_tools_ctx.template_current_user_message = prev_current_user_message;
cJSON_Delete(dm_event);
if (!dm_context) {
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);
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_invalidate_adopted_skills_cache(void);
void agent_cleanup(void);
#endif

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 25
#define DIDACTYL_VERSION "v0.2.25"
#define DIDACTYL_VERSION_PATCH 26
#define DIDACTYL_VERSION "v0.2.26"
// Agent metadata
#define DIDACTYL_NAME "Didactyl"

View File

@@ -14,6 +14,7 @@
#include "trigger_manager.h"
#include "nostr_block_list.h"
#include "cashu_wallet.h"
#include "agent.h"
#define NIP17_MAX_RELAYS 32
#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);
self_skill_cache_upsert_event_locked(event);
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) {

View File

@@ -11,6 +11,7 @@
#include "../debug.h"
#include "../nostr_handler.h"
#include "../trigger_manager.h"
#include "../agent.h"
static char* json_error_local(const char* msg) {
cJSON* root = cJSON_CreateObject();
@@ -1769,6 +1770,21 @@ char* execute_skill_edit(tools_context_t* ctx, const char* args_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) {
cJSON* args = parse_args_local(args_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) {
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) {
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_remove(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_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_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_fn = cJSON_CreateObject();
cJSON* t26_params = cJSON_CreateObject();