v0.2.52 - Fix trigger manager bypassing skill adoption list — cron/webhook triggers now only fire for adopted and enabled skills
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.51
|
## Current Status — v0.2.52
|
||||||
|
|
||||||
**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.51 — Implement n_signer integration through Phase 4: signer config/CLI/wizard, signer-backed signing/encryption/auth/cashu/blossom paths, nsigner_unix e2e validation, and signer health observability
|
> Last release update: v0.2.52 — Fix trigger manager bypassing skill adoption list — cron/webhook triggers now only fire for adopted and enabled skills
|
||||||
|
|
||||||
- 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
|
||||||
|
|||||||
77
plans/fix_trigger_adoption_gate.md
Normal file
77
plans/fix_trigger_adoption_gate.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Fix: Trigger Manager Bypasses Skill Adoption List
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
`trigger_manager_load_from_skills()` and `trigger_manager_reconcile_from_relays()`
|
||||||
|
activate cron/webhook/subscription triggers for **every** self-authored skill event
|
||||||
|
(kind 31123/31124) that has trigger metadata, without checking whether the skill is
|
||||||
|
on the kind 10123 adoption list.
|
||||||
|
|
||||||
|
This means a skill that was published but never adopted (or was un-adopted) will
|
||||||
|
still have its cron trigger firing.
|
||||||
|
|
||||||
|
Contrast: `agent.c:refresh_adopted_skills_cache_if_needed()` properly fetches the
|
||||||
|
kind 10123 list, parses `"a"` tags, and only loads adopted skills — and also checks
|
||||||
|
the `enabled` tag. The trigger manager was written as a parallel system that skips
|
||||||
|
both gates.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
|
||||||
|
- `trigger_manager.c:939` — `trigger_manager_load_from_skills()`: no reference to
|
||||||
|
kind 10123 or adoption anywhere in the function. Calls `trigger_manager_add()`
|
||||||
|
unconditionally.
|
||||||
|
- `trigger_manager.c:592` — `trigger_manager_reconcile_from_relays()`: same bug.
|
||||||
|
Currently disabled (`enable_periodic_reconcile = 0` at line 1575) but should be
|
||||||
|
fixed before re-enabling.
|
||||||
|
- Neither function checks the `enabled` tag either, unlike
|
||||||
|
`trigger_manager_load_from_startup_events()` (line 1078) which does check it.
|
||||||
|
|
||||||
|
## Fix
|
||||||
|
|
||||||
|
### 1. Add a static helper: `load_adopted_d_tags()`
|
||||||
|
|
||||||
|
Add a static function in `trigger_manager.c` that:
|
||||||
|
- Fetches kind 10123 events via `nostr_handler_get_self_events_by_kind_json(10123)`
|
||||||
|
- Selects the latest event by `created_at` (same logic as agent.c)
|
||||||
|
- Parses `"a"` tags using a local `parse_skill_address_tag_local()` equivalent
|
||||||
|
- Populates a fixed-size array of adopted d_tag strings
|
||||||
|
- Returns the count
|
||||||
|
|
||||||
|
Since both call sites only deal with self-authored skills, matching on d_tag
|
||||||
|
alone is sufficient (the pubkey in the "a" tag will be the agent's own).
|
||||||
|
|
||||||
|
### 2. Add `enabled` tag check
|
||||||
|
|
||||||
|
Both functions should read the `enabled` tag (defaulting to `"true"`) and skip
|
||||||
|
skills where `enabled` is `false` or `0`, matching the pattern already used in
|
||||||
|
`trigger_manager_load_from_startup_events()`.
|
||||||
|
|
||||||
|
### 3. Gate `trigger_manager_load_from_skills()`
|
||||||
|
|
||||||
|
Before calling `trigger_manager_add()`, check:
|
||||||
|
1. The skill's d_tag is in the adopted set
|
||||||
|
2. The skill's `enabled` tag is not false/0
|
||||||
|
|
||||||
|
If the adoption list is empty or missing, log a warning and load nothing (do not
|
||||||
|
fall back to loading all skills — that's the bug).
|
||||||
|
|
||||||
|
### 4. Gate `trigger_manager_reconcile_from_relays()`
|
||||||
|
|
||||||
|
Apply the same adoption + enabled checks. This ensures the code is correct when
|
||||||
|
`enable_periodic_reconcile` is eventually flipped back to 1.
|
||||||
|
|
||||||
|
### 5. Pass `is_enabled` to `trigger_manager_add()`
|
||||||
|
|
||||||
|
Currently both functions pass `1` (hardcoded enabled) as the `enabled` parameter.
|
||||||
|
Change to pass the actual `is_enabled` value derived from the `enabled` tag.
|
||||||
|
|
||||||
|
## Files Changed
|
||||||
|
|
||||||
|
- `src/trigger_manager.c` — add helper, fix both functions
|
||||||
|
|
||||||
|
## Risk
|
||||||
|
|
||||||
|
Low. The fix adds a filter before `trigger_manager_add()`. If the adoption list
|
||||||
|
is present and correct, behavior is unchanged for adopted skills. If the adoption
|
||||||
|
list is missing, triggers simply won't load (which is the correct behavior —
|
||||||
|
nothing should fire if nothing is adopted).
|
||||||
@@ -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 51
|
#define DIDACTYL_VERSION_PATCH 52
|
||||||
#define DIDACTYL_VERSION "v0.2.51"
|
#define DIDACTYL_VERSION "v0.2.52"
|
||||||
|
|
||||||
// Agent metadata
|
// Agent metadata
|
||||||
#define DIDACTYL_NAME "Didactyl"
|
#define DIDACTYL_NAME "Didactyl"
|
||||||
|
|||||||
@@ -589,6 +589,126 @@ static void parse_trigger_runtime_tags(cJSON* tags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the set of adopted skill d_tags from the kind 10123 adoption list.
|
||||||
|
*
|
||||||
|
* Fetches the agent's latest kind 10123 event from cache, parses the "a" tags,
|
||||||
|
* and populates out_d_tags with the d_tag portion of each adopted skill address.
|
||||||
|
*
|
||||||
|
* Since both trigger load paths only deal with self-authored skills, matching on
|
||||||
|
* d_tag alone is sufficient — the pubkey in the "a" tag will be the agent's own.
|
||||||
|
*
|
||||||
|
* Returns the number of adopted d_tags, or -1 on error.
|
||||||
|
*/
|
||||||
|
#define TRIGGER_ADOPTED_D_TAGS_MAX 64
|
||||||
|
static int load_adopted_d_tags(trigger_manager_t* mgr,
|
||||||
|
char out_d_tags[][65],
|
||||||
|
int max_d_tags) {
|
||||||
|
if (!mgr || !mgr->cfg || !out_d_tags || max_d_tags <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
char* adoption_json = nostr_handler_get_self_events_by_kind_json(10123);
|
||||||
|
if (!adoption_json) {
|
||||||
|
DEBUG_WARN("[didactyl] trigger adoption check: no kind 10123 event in cache");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON* adoption_events = cJSON_Parse(adoption_json);
|
||||||
|
free(adoption_json);
|
||||||
|
if (!adoption_events || !cJSON_IsArray(adoption_events) ||
|
||||||
|
cJSON_GetArraySize(adoption_events) <= 0) {
|
||||||
|
cJSON_Delete(adoption_events);
|
||||||
|
DEBUG_WARN("[didactyl] trigger adoption check: kind 10123 parse failed or empty");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the latest adoption list event by created_at */
|
||||||
|
cJSON* list_event = NULL;
|
||||||
|
double list_event_created_at = -1.0;
|
||||||
|
int adoption_n = cJSON_GetArraySize(adoption_events);
|
||||||
|
for (int ai = 0; ai < adoption_n; ai++) {
|
||||||
|
cJSON* ev = cJSON_GetArrayItem(adoption_events, ai);
|
||||||
|
if (!ev || !cJSON_IsObject(ev)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON* ev_pubkey = cJSON_GetObjectItemCaseSensitive(ev, "pubkey");
|
||||||
|
if (!ev_pubkey || !cJSON_IsString(ev_pubkey) || !ev_pubkey->valuestring ||
|
||||||
|
strcmp(ev_pubkey->valuestring, mgr->cfg->keys.public_key_hex) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON* created_at = cJSON_GetObjectItemCaseSensitive(ev, "created_at");
|
||||||
|
double created = (created_at && cJSON_IsNumber(created_at)) ? created_at->valuedouble : 0.0;
|
||||||
|
if (!list_event || created > list_event_created_at) {
|
||||||
|
list_event = ev;
|
||||||
|
list_event_created_at = created;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON* list_tags = list_event ? cJSON_GetObjectItemCaseSensitive(list_event, "tags") : NULL;
|
||||||
|
if (!list_tags || !cJSON_IsArray(list_tags)) {
|
||||||
|
cJSON_Delete(adoption_events);
|
||||||
|
DEBUG_INFO("[didactyl] trigger adoption check: no tags in adoption list event");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tn = cJSON_GetArraySize(list_tags);
|
||||||
|
for (int i = 0; i < tn && count < max_d_tags; i++) {
|
||||||
|
cJSON* tag = cJSON_GetArrayItem(list_tags, i);
|
||||||
|
if (!tag || !cJSON_IsArray(tag)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON* key = cJSON_GetArrayItem(tag, 0);
|
||||||
|
cJSON* val = cJSON_GetArrayItem(tag, 1);
|
||||||
|
if (!key || !val || !cJSON_IsString(key) || !cJSON_IsString(val) ||
|
||||||
|
!key->valuestring || !val->valuestring ||
|
||||||
|
strcmp(key->valuestring, "a") != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse "kind:pubkey:d_tag" — we only need the d_tag (3rd field) */
|
||||||
|
const char* p1 = strchr(val->valuestring, ':');
|
||||||
|
if (!p1) continue;
|
||||||
|
const char* p2 = strchr(p1 + 1, ':');
|
||||||
|
if (!p2) continue;
|
||||||
|
|
||||||
|
const char* d_tag_start = p2 + 1;
|
||||||
|
size_t d_tag_len = strlen(d_tag_start);
|
||||||
|
if (d_tag_len == 0 || d_tag_len >= 65U) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(out_d_tags[count], 65, "%s", d_tag_start);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_Delete(adoption_events);
|
||||||
|
DEBUG_INFO("[didactyl] trigger adoption check: %d adopted skill(s) found", count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether d_tag appears in the adopted_d_tags array.
|
||||||
|
*/
|
||||||
|
static int is_d_tag_adopted(const char* d_tag,
|
||||||
|
char adopted_d_tags[][65],
|
||||||
|
int adopted_count) {
|
||||||
|
if (!d_tag || d_tag[0] == '\0' || !adopted_d_tags || adopted_count <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < adopted_count; i++) {
|
||||||
|
if (strcmp(adopted_d_tags[i], d_tag) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
||||||
if (!mgr || !mgr->cfg) {
|
if (!mgr || !mgr->cfg) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -628,6 +748,18 @@ static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
|||||||
|
|
||||||
int considered = 0;
|
int considered = 0;
|
||||||
int loaded = 0;
|
int loaded = 0;
|
||||||
|
int skipped_not_adopted = 0;
|
||||||
|
int skipped_disabled = 0;
|
||||||
|
|
||||||
|
/* Load adopted d_tags from kind 10123 adoption list */
|
||||||
|
char adopted_d_tags[TRIGGER_ADOPTED_D_TAGS_MAX][65];
|
||||||
|
memset(adopted_d_tags, 0, sizeof(adopted_d_tags));
|
||||||
|
int adopted_count = load_adopted_d_tags(mgr, adopted_d_tags, TRIGGER_ADOPTED_D_TAGS_MAX);
|
||||||
|
if (adopted_count <= 0) {
|
||||||
|
DEBUG_WARN("[didactyl] trigger reconcile: no adopted skills found — skipping all trigger registration");
|
||||||
|
cJSON_Delete(events);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int event_count = cJSON_GetArraySize(events);
|
int event_count = cJSON_GetArraySize(events);
|
||||||
for (int i = 0; i < event_count; i++) {
|
for (int i = 0; i < event_count; i++) {
|
||||||
@@ -642,17 +774,25 @@ static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
|||||||
cJSON* trigger = find_tag_value_string(tags, "trigger");
|
cJSON* trigger = find_tag_value_string(tags, "trigger");
|
||||||
cJSON* filter_j = find_tag_value_string(tags, "filter");
|
cJSON* filter_j = find_tag_value_string(tags, "filter");
|
||||||
cJSON* action = find_tag_value_string(tags, "action");
|
cJSON* action = find_tag_value_string(tags, "action");
|
||||||
|
cJSON* enabled = find_tag_value_string(tags, "enabled");
|
||||||
|
|
||||||
const char* d_tag = (d && cJSON_IsString(d) && d->valuestring) ? d->valuestring : NULL;
|
const char* d_tag = (d && cJSON_IsString(d) && d->valuestring) ? d->valuestring : NULL;
|
||||||
const char* trigger_s = (trigger && cJSON_IsString(trigger) && trigger->valuestring) ? trigger->valuestring : NULL;
|
const char* trigger_s = (trigger && cJSON_IsString(trigger) && trigger->valuestring) ? trigger->valuestring : NULL;
|
||||||
const char* filter_s = (filter_j && cJSON_IsString(filter_j) && filter_j->valuestring) ? filter_j->valuestring : NULL;
|
const char* filter_s = (filter_j && cJSON_IsString(filter_j) && filter_j->valuestring) ? filter_j->valuestring : NULL;
|
||||||
const char* action_s = (action && cJSON_IsString(action) && action->valuestring) ? action->valuestring : "llm";
|
const char* action_s = (action && cJSON_IsString(action) && action->valuestring) ? action->valuestring : "llm";
|
||||||
|
const char* enabled_s = (enabled && cJSON_IsString(enabled) && enabled->valuestring) ? enabled->valuestring : "true";
|
||||||
|
|
||||||
considered++;
|
considered++;
|
||||||
if (!d_tag || d_tag[0] == '\0') {
|
if (!d_tag || d_tag[0] == '\0') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adoption gate: only register triggers for adopted skills */
|
||||||
|
if (!is_d_tag_adopted(d_tag, adopted_d_tags, adopted_count)) {
|
||||||
|
skipped_not_adopted++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int trigger_supported = trigger_s &&
|
int trigger_supported = trigger_s &&
|
||||||
(strcmp(trigger_s, "nostr-subscription") == 0 ||
|
(strcmp(trigger_s, "nostr-subscription") == 0 ||
|
||||||
strcmp(trigger_s, "webhook") == 0 ||
|
strcmp(trigger_s, "webhook") == 0 ||
|
||||||
@@ -663,6 +803,13 @@ static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enabled gate: skip skills explicitly disabled */
|
||||||
|
int is_enabled = (strcmp(enabled_s, "false") == 0 || strcmp(enabled_s, "0") == 0) ? 0 : 1;
|
||||||
|
if (!is_enabled) {
|
||||||
|
skipped_disabled++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(action_s, "template") == 0) {
|
if (strcmp(action_s, "template") == 0) {
|
||||||
DEBUG_WARN("[didactyl] trigger action template is deprecated; forcing llm for d_tag=%s", d_tag);
|
DEBUG_WARN("[didactyl] trigger action template is deprecated; forcing llm for d_tag=%s", d_tag);
|
||||||
}
|
}
|
||||||
@@ -691,7 +838,7 @@ static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
|||||||
filter_s,
|
filter_s,
|
||||||
TRIGGER_ACTION_LLM,
|
TRIGGER_ACTION_LLM,
|
||||||
trigger_s,
|
trigger_s,
|
||||||
1,
|
is_enabled,
|
||||||
llm_s,
|
llm_s,
|
||||||
tools_s,
|
tools_s,
|
||||||
has_max_tokens,
|
has_max_tokens,
|
||||||
@@ -705,7 +852,8 @@ static int trigger_manager_reconcile_from_relays(trigger_manager_t* mgr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cJSON_Delete(events);
|
cJSON_Delete(events);
|
||||||
DEBUG_INFO("[didactyl] trigger reconcile complete: loaded=%d considered=%d", loaded, considered);
|
DEBUG_INFO("[didactyl] trigger reconcile complete: loaded=%d considered=%d skipped_not_adopted=%d skipped_disabled=%d",
|
||||||
|
loaded, considered, skipped_not_adopted, skipped_disabled);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,8 +1091,19 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
|||||||
|
|
||||||
int loaded = 0;
|
int loaded = 0;
|
||||||
int considered = 0;
|
int considered = 0;
|
||||||
|
int skipped_not_adopted = 0;
|
||||||
|
int skipped_disabled = 0;
|
||||||
const int kinds[2] = {31123, 31124};
|
const int kinds[2] = {31123, 31124};
|
||||||
|
|
||||||
|
/* Load adopted d_tags from kind 10123 adoption list */
|
||||||
|
char adopted_d_tags[TRIGGER_ADOPTED_D_TAGS_MAX][65];
|
||||||
|
memset(adopted_d_tags, 0, sizeof(adopted_d_tags));
|
||||||
|
int adopted_count = load_adopted_d_tags(mgr, adopted_d_tags, TRIGGER_ADOPTED_D_TAGS_MAX);
|
||||||
|
if (adopted_count <= 0) {
|
||||||
|
DEBUG_WARN("[didactyl] trigger load from skills: no adopted skills found — skipping all trigger registration");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int k = 0; k < 2; k++) {
|
for (int k = 0; k < 2; k++) {
|
||||||
char* skill_json = nostr_handler_get_self_events_by_kind_json(kinds[k]);
|
char* skill_json = nostr_handler_get_self_events_by_kind_json(kinds[k]);
|
||||||
if (!skill_json) {
|
if (!skill_json) {
|
||||||
@@ -971,17 +1130,25 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
|||||||
cJSON* trigger = find_tag_value_string(tags, "trigger");
|
cJSON* trigger = find_tag_value_string(tags, "trigger");
|
||||||
cJSON* filter = find_tag_value_string(tags, "filter");
|
cJSON* filter = find_tag_value_string(tags, "filter");
|
||||||
cJSON* action = find_tag_value_string(tags, "action");
|
cJSON* action = find_tag_value_string(tags, "action");
|
||||||
|
cJSON* enabled = find_tag_value_string(tags, "enabled");
|
||||||
|
|
||||||
const char* d_tag = (d && cJSON_IsString(d) && d->valuestring) ? d->valuestring : NULL;
|
const char* d_tag = (d && cJSON_IsString(d) && d->valuestring) ? d->valuestring : NULL;
|
||||||
const char* trigger_s = (trigger && cJSON_IsString(trigger) && trigger->valuestring) ? trigger->valuestring : NULL;
|
const char* trigger_s = (trigger && cJSON_IsString(trigger) && trigger->valuestring) ? trigger->valuestring : NULL;
|
||||||
const char* filter_s = (filter && cJSON_IsString(filter) && filter->valuestring) ? filter->valuestring : NULL;
|
const char* filter_s = (filter && cJSON_IsString(filter) && filter->valuestring) ? filter->valuestring : NULL;
|
||||||
const char* action_s = (action && cJSON_IsString(action) && action->valuestring) ? action->valuestring : "llm";
|
const char* action_s = (action && cJSON_IsString(action) && action->valuestring) ? action->valuestring : "llm";
|
||||||
|
const char* enabled_s = (enabled && cJSON_IsString(enabled) && enabled->valuestring) ? enabled->valuestring : "true";
|
||||||
|
|
||||||
considered++;
|
considered++;
|
||||||
if (!d_tag || d_tag[0] == '\0') {
|
if (!d_tag || d_tag[0] == '\0') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adoption gate: only register triggers for adopted skills */
|
||||||
|
if (!is_d_tag_adopted(d_tag, adopted_d_tags, adopted_count)) {
|
||||||
|
skipped_not_adopted++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int trigger_supported = trigger_s &&
|
int trigger_supported = trigger_s &&
|
||||||
(strcmp(trigger_s, "nostr-subscription") == 0 ||
|
(strcmp(trigger_s, "nostr-subscription") == 0 ||
|
||||||
strcmp(trigger_s, "webhook") == 0 ||
|
strcmp(trigger_s, "webhook") == 0 ||
|
||||||
@@ -992,6 +1159,13 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enabled gate: skip skills explicitly disabled */
|
||||||
|
int is_enabled = (strcmp(enabled_s, "false") == 0 || strcmp(enabled_s, "0") == 0) ? 0 : 1;
|
||||||
|
if (!is_enabled) {
|
||||||
|
skipped_disabled++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(action_s, "template") == 0) {
|
if (strcmp(action_s, "template") == 0) {
|
||||||
DEBUG_WARN("[didactyl] trigger action template is deprecated; forcing llm for d_tag=%s", d_tag);
|
DEBUG_WARN("[didactyl] trigger action template is deprecated; forcing llm for d_tag=%s", d_tag);
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1194,7 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
|||||||
filter_s,
|
filter_s,
|
||||||
TRIGGER_ACTION_LLM,
|
TRIGGER_ACTION_LLM,
|
||||||
trigger_s,
|
trigger_s,
|
||||||
1,
|
is_enabled,
|
||||||
llm_s,
|
llm_s,
|
||||||
tools_s,
|
tools_s,
|
||||||
has_max_tokens,
|
has_max_tokens,
|
||||||
@@ -1036,7 +1210,8 @@ int trigger_manager_load_from_skills(trigger_manager_t* mgr) {
|
|||||||
cJSON_Delete(skill_events);
|
cJSON_Delete(skill_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_INFO("[didactyl] trigger manager loaded %d trigger(s) from self skills (considered=%d)", loaded, considered);
|
DEBUG_INFO("[didactyl] trigger manager loaded %d trigger(s) from self skills (considered=%d skipped_not_adopted=%d skipped_disabled=%d)",
|
||||||
|
loaded, considered, skipped_not_adopted, skipped_disabled);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user