Compare commits

...
4 Commits
10 changed files with 43 additions and 23 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.32
## Current Status — v0.2.36
**Active build — this project is barely working. Experiment at your own risk.**
> Last release update: v0.2.32Made user-settings recall resilient and backfill missing didactyl admin_pubkey/dm_protocol on republish
> Last release update: v0.2.36Block model_get/model_set/model_list inside skill_run with explicit policy gate
- Connects to configured relays with auto-reconnect and relay state transition logging
- Publishes configured startup events per relay as each relay becomes connected
+1 -5
View File
@@ -14,17 +14,13 @@
"pubkey": "npub1REPLACE_WITH_ADMIN_PUBKEY"
},
// ─── DM Protocol ───────────────────────────────────────────────────
// Supported values: "nip04", "nip17", or "both".
"dm_protocol": "nip04",
// ─── Encrypted Startup Config Events ───────────────────────────────
// These are published as NIP-44 encrypted kind 30078 self-events on first run.
"encrypted_events": [
{
"kind": 30078,
"d_tag": "user-settings",
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"openai\",\"api_key\":\"sk-REPLACE_WITH_API_KEY\",\"model\":\"gpt-4o-mini\",\"base_url\":\"https://api.openai.com/v1\",\"max_tokens\":512,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1REPLACE_WITH_ADMIN_PUBKEY\",\"dm_protocol\":\"nip04\",\"max_turns\":40}}"
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"openai\",\"api_key\":\"sk-REPLACE_WITH_API_KEY\",\"model\":\"gpt-4o-mini\",\"base_url\":\"https://api.openai.com/v1\",\"max_tokens\":512,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1REPLACE_WITH_ADMIN_PUBKEY\",\"dm_protocol\":\"both\",\"max_turns\":40}}"
}
],
+1 -5
View File
@@ -11,10 +11,6 @@
"pubkey": "npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06"
},
// ─── DM Protocol ──────────────────────────────────────────────────
// Supported values: "nip04", "nip17", or "both".
"dm_protocol": "nip04",
// ─── HTTP Admin API ───────────────────────────────────────────────
// Local API for model/context inspection and runtime controls.
"api": {
@@ -29,7 +25,7 @@
{
"kind": 30078,
"d_tag": "user-settings",
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"ppq\",\"api_key\":\"sk-LshAWvFC0KOFgrUYiP6NmT\",\"model\":\"claude-opus-4.6\",\"base_url\":\"https://api.ppq.ai\",\"max_tokens\":200000,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06\",\"dm_protocol\":\"nip04\",\"max_turns\":40}}"
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"ppq\",\"api_key\":\"sk-LshAWvFC0KOFgrUYiP6NmT\",\"model\":\"claude-opus-4.6\",\"base_url\":\"https://api.ppq.ai\",\"max_tokens\":200000,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06\",\"dm_protocol\":\"both\",\"max_turns\":40}}"
}
],
+1 -4
View File
@@ -9,9 +9,6 @@
"admin": {
"pubkey": "npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06"
},
// ─── DM Protocol ──────────────────────────────────────────────────
// Supported values: "nip04", "nip17", or "both".
"dm_protocol": "nip04",
// ─── HTTP Admin API ───────────────────────────────────────────────
// Local API for model/context inspection and runtime controls.
"api": {
@@ -25,7 +22,7 @@
{
"kind": 30078,
"d_tag": "user-settings",
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"ppq\",\"api_key\":\"sk-L9kd0LkZaoeaua0qqosnHy\",\"model\":\"claude-haiku-4.5\",\"base_url\":\"https://api.ppq.ai\",\"max_tokens\":512,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06\",\"dm_protocol\":\"nip04\",\"max_turns\":40}}"
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"ppq\",\"api_key\":\"sk-L9kd0LkZaoeaua0qqosnHy\",\"model\":\"claude-haiku-4.5\",\"base_url\":\"https://api.ppq.ai\",\"max_tokens\":512,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1rmz9gu6de0m0u4ysrn39crrud099ahvfgs6pvasl4hpjr5ud7yus54xv06\",\"dm_protocol\":\"both\",\"max_turns\":40}}"
}
],
// ─── Startup Events ───────────────────────────────────────────────
+1 -1
View File
@@ -1297,7 +1297,7 @@ int main(int argc, char** argv) {
DEBUG_INFO("[didactyl] startup phase: existing-agent mode; skipping startup-event reconcile on subsequent run");
}
if (bootstrap_mode || first_run) {
if (bootstrap_mode || first_run || user_settings_backfill_needed) {
if (persist_runtime_config_to_nostr(&cfg,
(llm_recalled_from_nostr && !user_settings_backfill_needed) ? 0 : 1) != 0) {
DEBUG_WARN("[didactyl] startup phase: failed to persist encrypted runtime config to Nostr");
+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 32
#define DIDACTYL_VERSION "v0.2.32"
#define DIDACTYL_VERSION_PATCH 36
#define DIDACTYL_VERSION "v0.2.36"
// Agent metadata
#define DIDACTYL_NAME "Didactyl"
+3 -1
View File
@@ -2848,6 +2848,9 @@ int nostr_handler_subscribe_dms(dm_callback_t callback, void* user_data) {
const int need_kind4 = (g_cfg->dm_protocol == DM_PROTOCOL_NIP04 || g_cfg->dm_protocol == DM_PROTOCOL_BOTH) ? 1 : 0;
const int need_kind1059 = (g_cfg->dm_protocol == DM_PROTOCOL_NIP17 || g_cfg->dm_protocol == DM_PROTOCOL_BOTH) ? 1 : 0;
DEBUG_INFO("[didactyl] DM subscribe: dm_protocol=%d need_kind4=%d need_kind1059=%d g_start_time=%ld",
(int)g_cfg->dm_protocol, need_kind4, need_kind1059, (long)g_start_time);
if (!need_kind4 && !need_kind1059) {
DEBUG_WARN("[didactyl] DM subscription skipped: no protocol selected");
return -1;
@@ -2898,7 +2901,6 @@ int nostr_handler_subscribe_dms(dm_callback_t callback, void* user_data) {
cJSON_AddItemToObject(filter1059, "kinds", kinds1059);
cJSON_AddItemToArray(p_values1059, cJSON_CreateString(g_cfg->keys.public_key_hex));
cJSON_AddItemToObject(filter1059, "#p", p_values1059);
cJSON_AddNumberToObject(filter1059, "since", (double)g_start_time);
cJSON_AddNumberToObject(filter1059, "limit", 400);
}
+18 -1
View File
@@ -606,6 +606,21 @@ static int maybe_append_loaded_skill_instructions_local(cJSON* messages,
return rc;
}
static int is_tool_blocked_in_skill_run_local(const char* tool_name) {
if (!tool_name || tool_name[0] == '\0') return 1;
static const char* blocked_tools[] = {
"model_get", "model_set", "model_list",
NULL
};
for (int i = 0; blocked_tools[i] != NULL; i++) {
if (strcmp(tool_name, blocked_tools[i]) == 0) return 1;
}
return 0;
}
static int is_tool_sandbox_safe_local(const char* tool_name) {
if (!tool_name || tool_name[0] == '\0') return 0;
@@ -2283,7 +2298,9 @@ char* execute_skill_run(tools_context_t* ctx, const char* args_json) {
llm_tool_call_t* tc = &resp.tool_calls[i];
char* tool_result = NULL;
if (sandbox_enabled && !is_tool_sandbox_safe_local(tc->name)) {
if (is_tool_blocked_in_skill_run_local(tc->name)) {
tool_result = strdup("{\"success\":false,\"error\":\"tool blocked by skill_run policy\"}");
} else if (sandbox_enabled && !is_tool_sandbox_safe_local(tc->name)) {
tool_result = strdup("{\"success\":false,\"error\":\"tool blocked by skill_run sandbox\"}");
} else {
tool_result = tools_execute(ctx, tc->name, tc->arguments_json);
+7 -1
View File
@@ -7,7 +7,6 @@
"admin": {
"pubkey": "npub1REPLACE_WITH_TEST_ADMIN_PUBKEY"
},
"dm_protocol": "nip04",
"llm": {
"provider": "https://api.ppq.ai",
"api_key": "sk-SBI2Pga0J6n8jpPorHbRHC",
@@ -21,6 +20,13 @@
"port": 8485,
"bind_address": "127.0.0.1"
},
"encrypted_events": [
{
"kind": 30078,
"d_tag": "user-settings",
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"https://api.ppq.ai\",\"api_key\":\"sk-SBI2Pga0J6n8jpPorHbRHC\",\"model\":\"claude-haiku-4.5\",\"base_url\":\"https://api.ppq.ai\",\"max_tokens\":10000,\"temperature\":0.7},\"didactyl\":{\"admin_pubkey\":\"npub1REPLACE_WITH_TEST_ADMIN_PUBKEY\",\"dm_protocol\":\"both\",\"max_turns\":40}}"
}
],
"startup_events": [
{
"kind": 0,
+7 -1
View File
@@ -8,7 +8,6 @@
"admin": {
"pubkey": "npub1REPLACE_WITH_TEST_ADMIN_PUBKEY"
},
"dm_protocol": "nip04",
"llm": {
"provider": "openai",
"api_key": "sk-REPLACE_WITH_API_KEY",
@@ -22,6 +21,13 @@
"port": 8485,
"bind_address": "127.0.0.1"
},
"encrypted_events": [
{
"kind": 30078,
"d_tag": "user-settings",
"content": "{\"v\":2,\"updatedAt\":0,\"global_llm\":{\"provider\":\"openai\",\"api_key\":\"sk-REPLACE_WITH_API_KEY\",\"model\":\"claude-haiku-4.5\",\"base_url\":\"https://api.anthropic.com/v1\",\"max_tokens\":512,\"temperature\":0.3},\"didactyl\":{\"admin_pubkey\":\"npub1REPLACE_WITH_TEST_ADMIN_PUBKEY\",\"dm_protocol\":\"both\",\"max_turns\":40}}"
}
],
"startup_events": [
{
"kind": 0,