v0.0.59 - Use tool-capable multi-turn execution for triggered skills
This commit is contained in:
@@ -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.58 — Disable pool dedup on trigger subscriptions to restore kind-1 firing
|
||||
> Last release update: v0.0.59 — Use 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
|
||||
|
||||
@@ -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
|
||||
|
||||
99
src/agent.c
99
src/agent.c
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user