v0.2.6 - Fix DM freeze by removing adopted-skills mutex reentrancy in trigger context assembly

This commit is contained in:
Your Name
2026-03-22 12:28:54 -04:00
parent b625e0a70a
commit b06c267db4
4 changed files with 229 additions and 9 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.5 ## Current Status — v0.2.6
**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.5 — Fix increment_and_push upstream auto-setup and finalize SIGINT shutdown fix > Last release update: v0.2.6 — Fix DM freeze by removing adopted-skills mutex reentrancy in trigger context assembly
- 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

@@ -1,3 +1,209 @@
```text
Context Log - not seen by model
timestamp=2026-03-22 12:19:28
phase=direct_tool_exec
sender=1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139
model=claude-opus-4.6
context_bytes=13723
approx_tokens=3430
```
slash=/help
result_json=AVAILABLE TOOLS
- admin_identity — Build admin identity context block from cached runtime metadata
- agent_identity — Build agent identity context block with pubkey and npub
- agent_version — Return current Didactyl version and metadata from build macros
- blossom_delete — Delete a blob from Blossom
- blossom_download — Download a blob from Blossom to a local file
- blossom_head — Fetch blob metadata from Blossom
- blossom_list — List blobs for a pubkey on Blossom
- blossom_upload — Upload a local file to a Blossom server
- cashu_wallet_balance — Return current wallet balances aggregated by mint and unit
- cashu_wallet_check_proofs — Check current wallet proofs state against mint
- cashu_wallet_info — Fetch mint info for a specific mint_url or the default configured mint
- cashu_wallet_melt_pay — Pay a previously quoted melt by quote_id
- cashu_wallet_melt_quote — Request a melt quote for a Lightning payment request
- cashu_wallet_mint_check — Check a previously requested mint quote status
- cashu_wallet_mint_claim — Claim minted proofs for a paid quote_id and add them to wallet state
- cashu_wallet_mint_quote — Request a mint quote for a target amount
- cashu_wallet_mints_get — Get currently configured wallet and public mints
- cashu_wallet_mints_set — Set wallet mints (NIP-60), public mints (NIP-61), or both
- cashu_wallet_receive_token — Receive an ecash token string (cashuA/cashuB), swap to fresh proofs, and store it in wallet state
- cashu_wallet_send_token — Create an outbound ecash token from wallet proofs for an exact amount
- config_recall — Fetch and decrypt agent config kind 30078 by d_tag
- config_store — Encrypt and publish agent config as kind 30078 for a given d_tag
- local_file_read — Read a local file as text from the configured working directory
- local_file_write — Write text content to a local file in the configured working directory
- local_http_fetch — Fetch HTTP(S) resources with optional method, headers, timeout, and body
- local_shell_exec — Execute a shell command and return stdout/stderr
- memory_recall — Recall encrypted agent memory (kind 30078, d=memory)
- memory_save — Prepend a new entry to encrypted agent memory (kind 30078, d=memory) and truncate oldest content if needed
- model_get — Get current active LLM runtime configuration (excluding API key)
- model_list — List available model IDs using provider OpenAI-compatible /models endpoint
- model_set — Update active LLM configuration and persist it to Nostr kind 30078 (d=llm_config)
- my_contacts — Alias for nostr_agent_contacts: return this agent's kind 3 contacts context
- my_kind0_profile — Alias for nostr_agent_profile: return this agent's kind 0 profile context
- my_notes — Alias for nostr_agent_notes: return this agent's recent kind 1 notes context
- my_npub — Alias for nostr_npub: return this agent's pubkey encoded as npub bech32
- my_pubkey — Alias for nostr_pubkey: return this agent's pubkey in hex format
- my_relays — Alias for nostr_agent_relays: return this agent's kind 10002 relay context
- nostr_admin_contacts — Build admin contacts context block from cached kind 3 contact list
- nostr_admin_notes — Build admin notes context block from cached kind 1 notes
- nostr_admin_profile — Build admin profile context block from cached kind 0 metadata
- nostr_admin_relays — Build admin relay context block from cached kind 10002 data
- nostr_agent_contacts — Build agent contacts context block from cached kind 3 contact list
- nostr_agent_notes — Build agent notes context block from cached kind 1 notes
- nostr_agent_profile — Build agent profile context block from cached kind 0 metadata
- nostr_agent_relays — Build agent relay context block from cached kind 10002 data
- nostr_block_edit — Add or remove blocked tuples in kind-10000 block list; entries are private (encrypted) by default
- nostr_block_list — View blocked pubkeys, event IDs, or hashtags from the local encrypted kind-10000 block list cache
- nostr_decode — Decode a Nostr bech32/nostr: URI into components
- nostr_decrypt — Decrypt NIP-44 ciphertext from a sender
- nostr_delete — Request deletion of one or more previously published events (NIP-09 kind 5)
- nostr_dm_send — Send a NIP-04 encrypted DM
- nostr_dm_send_nip17 — Send a private DM using NIP-17 gift wrap protocol
- nostr_encode — Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)
- nostr_encrypt — Encrypt plaintext using NIP-44 for a recipient
- nostr_file_md_to_longform_post — Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename
- nostr_list_manage — Add/remove tag tuples in replaceable list events (NIP-51 style)
- nostr_my_events — Query recent events authored by this agent and return kind, event_id, timestamp, d_tag, and cache presence
- nostr_nip05_lookup — Look up or verify a NIP-05 identifier (user@domain)
- nostr_npub — Return this agent's pubkey encoded as npub bech32
- nostr_post — Publish a Nostr event to connected relays
- nostr_post_readme — Publish README.md as kind 30023 with deterministic d tag readme.md
- nostr_profile_get — Look up a Nostr profile (kind 0 metadata) by pubkey
- nostr_pubkey — Return this agent's pubkey in hex format
- nostr_query — Query events from relays using a Nostr filter
- nostr_react — React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)
- nostr_relay_info — Fetch NIP-11 relay information document
- nostr_relay_status — Get connection status and statistics for all relays
- nostr_subscription_set — Update one managed runtime subscription by name (toggle enabled and/or replace filter)
- nostr_subscription_status — List currently managed runtime Nostr subscriptions and filters
- skill_adopt — Adopt a skill by adding its address to kind 10123 adoption list
- skill_create — Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it
- skill_edit — Edit an existing self skill by d tag and republish it as kind 31123/31124
- skill_list — List available skills discovered online (agent + admin), with adoption status and optional filters
- skill_remove — Remove a skill address from kind 10123 adoption list
- skill_search — Search public skills by query/author and optionally rank by adoption popularity
- task_list — Build current task list context block from agent task memory on Nostr
- task_manage — Manage agent short-term task memory stored on Nostr kind 30078 (d=tasks): list/add/update/remove/clear/replace
- tool_list — List available tools with name, description, and JSON parameter schema
- trigger_list — List active triggered skills and their runtime status
AVAILABLE SKILLS
- (none)
ADOPTED SKILLS
- default_admin_dm
result_markdown=AVAILABLE TOOLS
- admin_identity — Build admin identity context block from cached runtime metadata
- agent_identity — Build agent identity context block with pubkey and npub
- agent_version — Return current Didactyl version and metadata from build macros
- blossom_delete — Delete a blob from Blossom
- blossom_download — Download a blob from Blossom to a local file
- blossom_head — Fetch blob metadata from Blossom
- blossom_list — List blobs for a pubkey on Blossom
- blossom_upload — Upload a local file to a Blossom server
- cashu_wallet_balance — Return current wallet balances aggregated by mint and unit
- cashu_wallet_check_proofs — Check current wallet proofs state against mint
- cashu_wallet_info — Fetch mint info for a specific mint_url or the default configured mint
- cashu_wallet_melt_pay — Pay a previously quoted melt by quote_id
- cashu_wallet_melt_quote — Request a melt quote for a Lightning payment request
- cashu_wallet_mint_check — Check a previously requested mint quote status
- cashu_wallet_mint_claim — Claim minted proofs for a paid quote_id and add them to wallet state
- cashu_wallet_mint_quote — Request a mint quote for a target amount
- cashu_wallet_mints_get — Get currently configured wallet and public mints
- cashu_wallet_mints_set — Set wallet mints (NIP-60), public mints (NIP-61), or both
- cashu_wallet_receive_token — Receive an ecash token string (cashuA/cashuB), swap to fresh proofs, and store it in wallet state
- cashu_wallet_send_token — Create an outbound ecash token from wallet proofs for an exact amount
- config_recall — Fetch and decrypt agent config kind 30078 by d_tag
- config_store — Encrypt and publish agent config as kind 30078 for a given d_tag
- local_file_read — Read a local file as text from the configured working directory
- local_file_write — Write text content to a local file in the configured working directory
- local_http_fetch — Fetch HTTP(S) resources with optional method, headers, timeout, and body
- local_shell_exec — Execute a shell command and return stdout/stderr
- memory_recall — Recall encrypted agent memory (kind 30078, d=memory)
- memory_save — Prepend a new entry to encrypted agent memory (kind 30078, d=memory) and truncate oldest content if needed
- model_get — Get current active LLM runtime configuration (excluding API key)
- model_list — List available model IDs using provider OpenAI-compatible /models endpoint
- model_set — Update active LLM configuration and persist it to Nostr kind 30078 (d=llm_config)
- my_contacts — Alias for nostr_agent_contacts: return this agent's kind 3 contacts context
- my_kind0_profile — Alias for nostr_agent_profile: return this agent's kind 0 profile context
- my_notes — Alias for nostr_agent_notes: return this agent's recent kind 1 notes context
- my_npub — Alias for nostr_npub: return this agent's pubkey encoded as npub bech32
- my_pubkey — Alias for nostr_pubkey: return this agent's pubkey in hex format
- my_relays — Alias for nostr_agent_relays: return this agent's kind 10002 relay context
- nostr_admin_contacts — Build admin contacts context block from cached kind 3 contact list
- nostr_admin_notes — Build admin notes context block from cached kind 1 notes
- nostr_admin_profile — Build admin profile context block from cached kind 0 metadata
- nostr_admin_relays — Build admin relay context block from cached kind 10002 data
- nostr_agent_contacts — Build agent contacts context block from cached kind 3 contact list
- nostr_agent_notes — Build agent notes context block from cached kind 1 notes
- nostr_agent_profile — Build agent profile context block from cached kind 0 metadata
- nostr_agent_relays — Build agent relay context block from cached kind 10002 data
- nostr_block_edit — Add or remove blocked tuples in kind-10000 block list; entries are private (encrypted) by default
- nostr_block_list — View blocked pubkeys, event IDs, or hashtags from the local encrypted kind-10000 block list cache
- nostr_decode — Decode a Nostr bech32/nostr: URI into components
- nostr_decrypt — Decrypt NIP-44 ciphertext from a sender
- nostr_delete — Request deletion of one or more previously published events (NIP-09 kind 5)
- nostr_dm_send — Send a NIP-04 encrypted DM
- nostr_dm_send_nip17 — Send a private DM using NIP-17 gift wrap protocol
- nostr_encode — Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)
- nostr_encrypt — Encrypt plaintext using NIP-44 for a recipient
- nostr_file_md_to_longform_post — Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename
- nostr_list_manage — Add/remove tag tuples in replaceable list events (NIP-51 style)
- nostr_my_events — Query recent events authored by this agent and return kind, event_id, timestamp, d_tag, and cache presence
- nostr_nip05_lookup — Look up or verify a NIP-05 identifier (user@domain)
- nostr_npub — Return this agent's pubkey encoded as npub bech32
- nostr_post — Publish a Nostr event to connected relays
- nostr_post_readme — Publish README.md as kind 30023 with deterministic d tag readme.md
- nostr_profile_get — Look up a Nostr profile (kind 0 metadata) by pubkey
- nostr_pubkey — Return this agent's pubkey in hex format
- nostr_query — Query events from relays using a Nostr filter
- nostr_react — React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)
- nostr_relay_info — Fetch NIP-11 relay information document
- nostr_relay_status — Get connection status and statistics for all relays
- nostr_subscription_set — Update one managed runtime subscription by name (toggle enabled and/or replace filter)
- nostr_subscription_status — List currently managed runtime Nostr subscriptions and filters
- skill_adopt — Adopt a skill by adding its address to kind 10123 adoption list
- skill_create — Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it
- skill_edit — Edit an existing self skill by d tag and republish it as kind 31123/31124
- skill_list — List available skills discovered online (agent + admin), with adoption status and optional filters
- skill_remove — Remove a skill address from kind 10123 adoption list
- skill_search — Search public skills by query/author and optionally rank by adoption popularity
- task_list — Build current task list context block from agent task memory on Nostr
- task_manage — Manage agent short-term task memory stored on Nostr kind 30078 (d=tasks): list/add/update/remove/clear/replace
- tool_list — List available tools with name, description, and JSON parameter schema
- trigger_list — List active triggered skills and their runtime status
AVAILABLE SKILLS
- (none)
ADOPTED SKILLS
- default_admin_dm
---
```text
Context Log - not seen by model
timestamp=2026-03-22 12:19:16
phase=direct_tool_exec
sender=1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139
model=claude-opus-4.6
context_bytes=129
approx_tokens=32
```
slash=/tools
result_json={"success":false,"error":"unknown tool"}
result_markdown=- **success:** false
- **error:** unknown tool
---
```text ```text
Context Log - not seen by model Context Log - not seen by model
timestamp=2026-03-22 12:11:32 timestamp=2026-03-22 12:11:32

View File

@@ -1596,8 +1596,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); 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]; const agent_adopted_skill_t* s = &g_adopted_skills[i];
if (!s->has_trigger || s->trigger_type != trigger_type) { if (!s->has_trigger || s->trigger_type != trigger_type) {
continue; continue;
@@ -1606,8 +1610,16 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
continue; continue;
} }
char* expanded = resolve_skill_references_local(s->content ? s->content : ""); matched_skill_contents[matched_skill_count] = strdup(s->content ? s->content : "");
const char* skill_text = expanded ? expanded : (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; size_t need = strlen("\n\n---\n\n") + strlen(skill_text) + 1U;
if (used + need >= cap) { if (used + need >= cap) {
@@ -1616,7 +1628,9 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
char* grown = (char*)realloc(out, next); char* grown = (char*)realloc(out, next);
if (!grown) { if (!grown) {
free(expanded); 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); free(out);
return NULL; return NULL;
} }
@@ -1635,8 +1649,8 @@ static char* build_context_from_triggers(trigger_type_t trigger_type,
matched++; matched++;
free(expanded); free(expanded);
free(matched_skill_contents[i]);
} }
pthread_mutex_unlock(&g_adopted_skills_mutex);
if (matched == 0) { if (matched == 0) {
const char* fallback = "You are an AI agent. Respond to the message."; const char* fallback = "You are an AI agent. Respond to the message.";

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 5 #define DIDACTYL_VERSION_PATCH 6
#define DIDACTYL_VERSION "v0.2.5" #define DIDACTYL_VERSION "v0.2.6"
// Agent metadata // Agent metadata
#define DIDACTYL_NAME "Didactyl" #define DIDACTYL_NAME "Didactyl"