v0.0.59 - Use tool-capable multi-turn execution for triggered skills

This commit is contained in:
Your Name
2026-03-09 18:31:15 -04:00
parent f7dd1f98c6
commit c93972019c
4 changed files with 135 additions and 15 deletions

View File

@@ -53,11 +53,11 @@ Skills support context modes (`inject`, `full`, `override`) and per-skill LLM fa
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.0.58
## Current Status — v0.0.59
**Active build — this project is barely working. Experiment at your own risk.**
> Last release update: v0.0.58Disable pool dedup on trigger subscriptions to restore kind-1 firing
> Last release update: v0.0.59Use tool-capable multi-turn execution for triggered skills
- 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

@@ -1,3 +1,46 @@
```text
Context Log - not seen by model
timestamp=2026-03-09 18:15:43
phase=llm_trigger
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=386
approx_tokens=96
```
Triggering event JSON:
{"created_at":1773094543,"content":"Today is a great day.","tags":[],"kind":1,"pubkey":"8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e","id":"e0fd645ab098a026b0afec57bc281aa1357e535cf13e6adeb4380f354af3ae25","sig":"7afb6c1c472c514a475f45b1eba2325d59cfea609ee4704b9e0b8df62d8323d0a17e8ea339f0cb5ead33ed21699294b89112a6e67fa3a5c1d1fa6c0e37de0000"}
---
```text
Context Log - not seen by model
timestamp=2026-03-09 18:15:28
phase=direct_tool_exec
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=683
approx_tokens=170
```
slash=/trigger_list
result_json={"success":true,"count":1,"active":1,"triggers":[{"skill_slug":"cheerleader","filter_json":"{\"kinds\":[1],\"authors\":[\"8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e\"]}","action":"llm","enabled":true,"subscribed":true,"last_fired":0,"last_seen_created_at":0}]}
result_markdown=- **success:** true
- **count:** 1
- **active:** 1
- **triggers:**
-
- **skill_slug:** cheerleader
- **filter_json:** {"kinds":[1],"authors":["8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e"]}
- **action:** llm
- **enabled:** true
- **subscribed:** true
- **last_fired:** 0
- **last_seen_created_at:** 0
---
```text
Context Log - not seen by model
timestamp=2026-03-09 17:21:46

View File

@@ -1962,20 +1962,97 @@ void agent_on_trigger(const char* skill_slug,
snprintf(user_prompt, user_len, "Triggering event JSON:\n%s", event_json);
free(event_json);
append_context_log(g_cfg->admin.pubkey, "llm_trigger", user_prompt);
char* response = llm_chat(system_prompt, user_prompt);
free(system_prompt);
free(user_prompt);
if (!response) {
const char* fallback = "Triggered skill execution failed: LLM unavailable.";
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, fallback);
char* tools_json = tools_build_openai_schema_json(&g_tools_ctx);
if (!tools_json) {
free(system_prompt);
free(user_prompt);
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, "Triggered skill execution failed: tools unavailable.");
return;
}
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, response);
free(response);
cJSON* messages = cJSON_CreateArray();
if (!messages || !cJSON_IsArray(messages) ||
append_simple_message(messages, "system", system_prompt) != 0 ||
append_simple_message(messages, "user", user_prompt) != 0) {
cJSON_Delete(messages);
free(tools_json);
free(system_prompt);
free(user_prompt);
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, "Triggered skill execution failed: prompt initialization failed.");
return;
}
append_context_log(g_cfg->admin.pubkey, "llm_trigger", user_prompt);
free(system_prompt);
free(user_prompt);
int max_turns = g_cfg->tools.max_turns > 0 ? g_cfg->tools.max_turns : 6;
char* final_answer_owned = NULL;
for (int turn = 0; turn < max_turns; turn++) {
char* messages_json = cJSON_PrintUnformatted(messages);
if (!messages_json) {
break;
}
append_context_log(g_cfg->admin.pubkey, "llm_trigger_with_tools_messages", messages_json);
llm_response_t resp;
int rc = llm_chat_with_tools_messages(messages_json, tools_json, "auto", &resp);
free(messages_json);
if (rc != 0) {
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, "Triggered skill execution failed: LLM request failed.");
cJSON_Delete(messages);
free(tools_json);
return;
}
if (resp.tool_call_count <= 0) {
const char* answer = resp.content ? resp.content : "No response content.";
final_answer_owned = strdup(answer);
llm_response_free(&resp);
break;
}
if (append_assistant_tool_calls_message(messages, &resp) != 0) {
llm_response_free(&resp);
break;
}
for (int i = 0; i < resp.tool_call_count; i++) {
llm_tool_call_t* tc = &resp.tool_calls[i];
char* tool_result = tools_execute(&g_tools_ctx, tc->name, tc->arguments_json);
if (!tool_result) {
tool_result = strdup("{\"success\":false,\"error\":\"tool execution failed\"}");
}
if (append_tool_result_message(messages,
tc->id ? tc->id : "",
tool_result ? tool_result : "{\"success\":false,\"error\":\"tool execution failed\"}") != 0) {
free(tool_result);
llm_response_free(&resp);
cJSON_Delete(messages);
free(tools_json);
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, "Triggered skill execution failed: tool result append failed.");
return;
}
free(tool_result);
}
llm_response_free(&resp);
}
if (!final_answer_owned) {
final_answer_owned = strdup("I hit my tool-use limit for this trigger.");
}
const char* final_answer = final_answer_owned ? final_answer_owned : "I hit my tool-use limit for this trigger.";
(void)nostr_handler_send_dm_auto(g_cfg->admin.pubkey, final_answer);
free(final_answer_owned);
cJSON_Delete(messages);
free(tools_json);
}
int agent_build_admin_messages_json(const char* current_user_message,

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 0
#define DIDACTYL_VERSION_PATCH 58
#define DIDACTYL_VERSION "v0.0.58"
#define DIDACTYL_VERSION_PATCH 59
#define DIDACTYL_VERSION "v0.0.59"
// Agent metadata
#define DIDACTYL_NAME "Didactyl"