v0.2.6 - Fix DM freeze by removing adopted-skills mutex reentrancy in trigger context assembly
This commit is contained in:
@@ -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
|
||||||
|
|||||||
206
context.log.md
206
context.log.md
@@ -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
|
||||||
|
|||||||
24
src/agent.c
24
src/agent.c
@@ -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.";
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user