#define _POSIX_C_SOURCE 200809L

#include "tools_internal.h"

#include "cjson/cJSON.h"

char* tools_build_openai_schema_json_legacy(const tools_context_t* ctx) {
    (void)ctx;

    cJSON* tools = cJSON_CreateArray();
    if (!tools) return NULL;

    cJSON* t1 = cJSON_CreateObject();
    cJSON* t1_fn = cJSON_CreateObject();
    cJSON* t1_params = cJSON_CreateObject();
    cJSON* t1_props = cJSON_CreateObject();
    cJSON* t1_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t1, "type", "function");
    cJSON_AddStringToObject(t1_fn, "name", "nostr_post");
    cJSON_AddStringToObject(t1_fn, "description", "Publish a Nostr event to connected relays");
    cJSON_AddStringToObject(t1_params, "type", "object");
    cJSON_AddItemToObject(t1_params, "properties", t1_props);
    cJSON_AddItemToObject(t1_params, "required", t1_required);

    cJSON* p_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_kind, "type", "integer");
    cJSON_AddStringToObject(p_kind, "description", "Nostr event kind number (for example 1 for note, 7 for reaction, 30023 for longform)");
    cJSON_AddItemToObject(t1_props, "kind", p_kind);
    cJSON* p_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_content, "type", "string");
    cJSON_AddStringToObject(p_content, "description", "Event content/body text to publish");
    cJSON_AddItemToObject(t1_props, "content", p_content);
    cJSON* p_tags = cJSON_CreateObject();
    cJSON_AddStringToObject(p_tags, "type", "array");
    cJSON_AddStringToObject(p_tags, "description", "Optional Nostr tags array, e.g. [[\"d\",\"my-skill\"],[\"t\",\"nostr\"]]");
    cJSON* p_tags_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_tags_items, "type", "array");
    cJSON* p_tag_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_tag_item, "type", "string");
    cJSON_AddItemToObject(p_tags_items, "items", p_tag_item);
    cJSON_AddItemToObject(p_tags, "items", p_tags_items);
    cJSON_AddItemToObject(t1_props, "tags", p_tags);
    cJSON_AddItemToArray(t1_required, cJSON_CreateString("kind"));
    cJSON_AddItemToArray(t1_required, cJSON_CreateString("content"));

    cJSON_AddItemToObject(t1_fn, "parameters", t1_params);
    cJSON_AddItemToObject(t1, "function", t1_fn);
    cJSON_AddItemToArray(tools, t1);

    cJSON* t2 = cJSON_CreateObject();
    cJSON* t2_fn = cJSON_CreateObject();
    cJSON* t2_params = cJSON_CreateObject();
    cJSON* t2_props = cJSON_CreateObject();
    cJSON* t2_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t2, "type", "function");
    cJSON_AddStringToObject(t2_fn, "name", "nostr_query");
    cJSON_AddStringToObject(t2_fn, "description", "Query events from relays using a Nostr filter");
    cJSON_AddStringToObject(t2_params, "type", "object");
    cJSON_AddItemToObject(t2_params, "properties", t2_props);
    cJSON_AddItemToObject(t2_params, "required", t2_required);

    cJSON* p_filter = cJSON_CreateObject();
    cJSON_AddStringToObject(p_filter, "type", "object");
    cJSON_AddStringToObject(p_filter, "description", "Nostr filter object (authors, kinds, ids, since, until, limit, and tag filters)");
    cJSON_AddItemToObject(t2_props, "filter", p_filter);
    cJSON* p_timeout = cJSON_CreateObject();
    cJSON_AddStringToObject(p_timeout, "type", "integer");
    cJSON_AddStringToObject(p_timeout, "description", "Optional query timeout in milliseconds");
    cJSON_AddItemToObject(t2_props, "timeout_ms", p_timeout);
    cJSON_AddItemToArray(t2_required, cJSON_CreateString("filter"));

    cJSON_AddItemToObject(t2_fn, "parameters", t2_params);
    cJSON_AddItemToObject(t2, "function", t2_fn);
    cJSON_AddItemToArray(tools, t2);

    cJSON* t3 = cJSON_CreateObject();
    cJSON* t3_fn = cJSON_CreateObject();
    cJSON* t3_params = cJSON_CreateObject();
    cJSON* t3_props = cJSON_CreateObject();
    cJSON* t3_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t3, "type", "function");
    cJSON_AddStringToObject(t3_fn, "name", "local_shell_exec");
    cJSON_AddStringToObject(t3_fn, "description", "Execute a shell command and return stdout/stderr");
    cJSON_AddStringToObject(t3_params, "type", "object");
    cJSON_AddItemToObject(t3_params, "properties", t3_props);
    cJSON_AddItemToObject(t3_params, "required", t3_required);

    cJSON* p_cmd = cJSON_CreateObject();
    cJSON_AddStringToObject(p_cmd, "type", "string");
    cJSON_AddStringToObject(p_cmd, "description", "Shell command to execute in the configured working directory");
    cJSON_AddItemToObject(t3_props, "command", p_cmd);
    cJSON_AddItemToArray(t3_required, cJSON_CreateString("command"));

    cJSON_AddItemToObject(t3_fn, "parameters", t3_params);
    cJSON_AddItemToObject(t3, "function", t3_fn);
    cJSON_AddItemToArray(tools, t3);

    cJSON* t4 = cJSON_CreateObject();
    cJSON* t4_fn = cJSON_CreateObject();
    cJSON* t4_params = cJSON_CreateObject();
    cJSON* t4_props = cJSON_CreateObject();
    cJSON* t4_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t4, "type", "function");
    cJSON_AddStringToObject(t4_fn, "name", "local_file_read");
    cJSON_AddStringToObject(t4_fn, "description", "Read a local file as text from the configured working directory");
    cJSON_AddStringToObject(t4_params, "type", "object");
    cJSON_AddItemToObject(t4_params, "properties", t4_props);
    cJSON_AddItemToObject(t4_params, "required", t4_required);

    cJSON* p_fr_path = cJSON_CreateObject();
    cJSON_AddStringToObject(p_fr_path, "type", "string");
    cJSON_AddStringToObject(p_fr_path, "description", "Path to file to read (relative to configured working directory)");
    cJSON_AddItemToObject(t4_props, "path", p_fr_path);
    cJSON* p_fr_max = cJSON_CreateObject();
    cJSON_AddStringToObject(p_fr_max, "type", "integer");
    cJSON_AddStringToObject(p_fr_max, "description", "Optional maximum bytes to return");
    cJSON_AddItemToObject(t4_props, "max_bytes", p_fr_max);
    cJSON_AddItemToArray(t4_required, cJSON_CreateString("path"));

    cJSON_AddItemToObject(t4_fn, "parameters", t4_params);
    cJSON_AddItemToObject(t4, "function", t4_fn);
    cJSON_AddItemToArray(tools, t4);

    cJSON* t5 = cJSON_CreateObject();
    cJSON* t5_fn = cJSON_CreateObject();
    cJSON* t5_params = cJSON_CreateObject();
    cJSON* t5_props = cJSON_CreateObject();
    cJSON* t5_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t5, "type", "function");
    cJSON_AddStringToObject(t5_fn, "name", "local_file_write");
    cJSON_AddStringToObject(t5_fn, "description", "Write text content to a local file in the configured working directory");
    cJSON_AddStringToObject(t5_params, "type", "object");
    cJSON_AddItemToObject(t5_params, "properties", t5_props);
    cJSON_AddItemToObject(t5_params, "required", t5_required);

    cJSON* p_fw_path = cJSON_CreateObject();
    cJSON_AddStringToObject(p_fw_path, "type", "string");
    cJSON_AddStringToObject(p_fw_path, "description", "Path to file to write (relative to configured working directory)");
    cJSON_AddItemToObject(t5_props, "path", p_fw_path);
    cJSON* p_fw_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_fw_content, "type", "string");
    cJSON_AddStringToObject(p_fw_content, "description", "Text content to write");
    cJSON_AddItemToObject(t5_props, "content", p_fw_content);
    cJSON* p_fw_append = cJSON_CreateObject();
    cJSON_AddStringToObject(p_fw_append, "type", "boolean");
    cJSON_AddStringToObject(p_fw_append, "description", "When true, append to file instead of overwriting");
    cJSON_AddItemToObject(t5_props, "append", p_fw_append);
    cJSON_AddItemToArray(t5_required, cJSON_CreateString("path"));
    cJSON_AddItemToArray(t5_required, cJSON_CreateString("content"));

    cJSON_AddItemToObject(t5_fn, "parameters", t5_params);
    cJSON_AddItemToObject(t5, "function", t5_fn);
    cJSON_AddItemToArray(tools, t5);

    cJSON* t6 = cJSON_CreateObject();
    cJSON* t6_fn = cJSON_CreateObject();
    cJSON* t6_params = cJSON_CreateObject();
    cJSON* t6_props = cJSON_CreateObject();
    cJSON* t6_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t6, "type", "function");
    cJSON_AddStringToObject(t6_fn, "name", "nostr_post_readme");
    cJSON_AddStringToObject(t6_fn, "description", "Publish README.md as kind 30023 with deterministic d tag readme.md");
    cJSON_AddStringToObject(t6_params, "type", "object");
    cJSON_AddItemToObject(t6_params, "properties", t6_props);
    cJSON_AddItemToObject(t6_params, "required", t6_required);

    cJSON_AddItemToObject(t6_fn, "parameters", t6_params);
    cJSON_AddItemToObject(t6, "function", t6_fn);
    cJSON_AddItemToArray(tools, t6);

    cJSON* t7 = cJSON_CreateObject();
    cJSON* t7_fn = cJSON_CreateObject();
    cJSON* t7_params = cJSON_CreateObject();
    cJSON* t7_props = cJSON_CreateObject();
    cJSON* t7_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t7, "type", "function");
    cJSON_AddStringToObject(t7_fn, "name", "nostr_delete");
    cJSON_AddStringToObject(t7_fn, "description", "Request deletion of one or more previously published events (NIP-09 kind 5)");
    cJSON_AddStringToObject(t7_params, "type", "object");
    cJSON_AddItemToObject(t7_params, "properties", t7_props);
    cJSON_AddItemToObject(t7_params, "required", t7_required);

    cJSON* p_del_ids = cJSON_CreateObject();
    cJSON_AddStringToObject(p_del_ids, "type", "array");
    cJSON_AddStringToObject(p_del_ids, "description", "Event IDs to request deletion for");
    cJSON* p_del_ids_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_del_ids_items, "type", "string");
    cJSON_AddItemToObject(p_del_ids, "items", p_del_ids_items);
    cJSON_AddItemToObject(t7_props, "event_ids", p_del_ids);

    cJSON* p_del_kinds = cJSON_CreateObject();
    cJSON_AddStringToObject(p_del_kinds, "type", "array");
    cJSON_AddStringToObject(p_del_kinds, "description", "Optional kinds corresponding to event_ids entries");
    cJSON* p_del_kinds_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_del_kinds_items, "type", "integer");
    cJSON_AddItemToObject(p_del_kinds, "items", p_del_kinds_items);
    cJSON_AddItemToObject(t7_props, "kinds", p_del_kinds);

    cJSON* p_del_reason = cJSON_CreateObject();
    cJSON_AddStringToObject(p_del_reason, "type", "string");
    cJSON_AddStringToObject(p_del_reason, "description", "Optional human-readable reason");
    cJSON_AddItemToObject(t7_props, "reason", p_del_reason);

    cJSON_AddItemToArray(t7_required, cJSON_CreateString("event_ids"));

    cJSON_AddItemToObject(t7_fn, "parameters", t7_params);
    cJSON_AddItemToObject(t7, "function", t7_fn);
    cJSON_AddItemToArray(tools, t7);

    cJSON* t8 = cJSON_CreateObject();
    cJSON* t8_fn = cJSON_CreateObject();
    cJSON* t8_params = cJSON_CreateObject();
    cJSON* t8_props = cJSON_CreateObject();
    cJSON* t8_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t8, "type", "function");
    cJSON_AddStringToObject(t8_fn, "name", "nostr_react");
    cJSON_AddStringToObject(t8_fn, "description", "React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)");
    cJSON_AddStringToObject(t8_params, "type", "object");
    cJSON_AddItemToObject(t8_params, "properties", t8_props);
    cJSON_AddItemToObject(t8_params, "required", t8_required);

    cJSON* p_react_event_id = cJSON_CreateObject();
    cJSON_AddStringToObject(p_react_event_id, "type", "string");
    cJSON_AddStringToObject(p_react_event_id, "description", "Target event ID to react to");
    cJSON_AddItemToObject(t8_props, "event_id", p_react_event_id);

    cJSON* p_react_event_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_react_event_pubkey, "type", "string");
    cJSON_AddStringToObject(p_react_event_pubkey, "description", "Author pubkey of target event");
    cJSON_AddItemToObject(t8_props, "event_pubkey", p_react_event_pubkey);

    cJSON* p_react_event_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_react_event_kind, "type", "integer");
    cJSON_AddStringToObject(p_react_event_kind, "description", "Optional kind of target event");
    cJSON_AddItemToObject(t8_props, "event_kind", p_react_event_kind);

    cJSON* p_react_reaction = cJSON_CreateObject();
    cJSON_AddStringToObject(p_react_reaction, "type", "string");
    cJSON_AddStringToObject(p_react_reaction, "description", "Reaction content such as +, -, ❤️, or emoji");
    cJSON_AddItemToObject(t8_props, "reaction", p_react_reaction);

    cJSON_AddItemToArray(t8_required, cJSON_CreateString("event_id"));
    cJSON_AddItemToArray(t8_required, cJSON_CreateString("event_pubkey"));

    cJSON_AddItemToObject(t8_fn, "parameters", t8_params);
    cJSON_AddItemToObject(t8, "function", t8_fn);
    cJSON_AddItemToArray(tools, t8);

    cJSON* t9 = cJSON_CreateObject();
    cJSON* t9_fn = cJSON_CreateObject();
    cJSON* t9_params = cJSON_CreateObject();
    cJSON* t9_props = cJSON_CreateObject();
    cJSON* t9_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t9, "type", "function");
    cJSON_AddStringToObject(t9_fn, "name", "nostr_profile_get");
    cJSON_AddStringToObject(t9_fn, "description", "Look up a Nostr profile (kind 0 metadata) by pubkey");
    cJSON_AddStringToObject(t9_params, "type", "object");
    cJSON_AddItemToObject(t9_params, "properties", t9_props);
    cJSON_AddItemToObject(t9_params, "required", t9_required);

    cJSON* p_profile_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_profile_pubkey, "type", "string");
    cJSON_AddStringToObject(p_profile_pubkey, "description", "Hex pubkey of the profile to fetch");
    cJSON_AddItemToObject(t9_props, "pubkey", p_profile_pubkey);

    cJSON_AddItemToArray(t9_required, cJSON_CreateString("pubkey"));

    cJSON_AddItemToObject(t9_fn, "parameters", t9_params);
    cJSON_AddItemToObject(t9, "function", t9_fn);
    cJSON_AddItemToArray(tools, t9);

    cJSON* t10 = cJSON_CreateObject();
    cJSON* t10_fn = cJSON_CreateObject();
    cJSON* t10_params = cJSON_CreateObject();
    cJSON* t10_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t10, "type", "function");
    cJSON_AddStringToObject(t10_fn, "name", "nostr_relay_status");
    cJSON_AddStringToObject(t10_fn, "description", "Get connection status and statistics for all relays");
    cJSON_AddStringToObject(t10_params, "type", "object");
    cJSON_AddItemToObject(t10_params, "properties", t10_props);

    cJSON_AddItemToObject(t10_fn, "parameters", t10_params);
    cJSON_AddItemToObject(t10, "function", t10_fn);
    cJSON_AddItemToArray(tools, t10);

    cJSON* t11 = cJSON_CreateObject();
    cJSON* t11_fn = cJSON_CreateObject();
    cJSON* t11_params = cJSON_CreateObject();
    cJSON* t11_props = cJSON_CreateObject();
    cJSON* t11_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t11, "type", "function");
    cJSON_AddStringToObject(t11_fn, "name", "nostr_nip05_lookup");
    cJSON_AddStringToObject(t11_fn, "description", "Look up or verify a NIP-05 identifier (user@domain)");
    cJSON_AddStringToObject(t11_params, "type", "object");
    cJSON_AddItemToObject(t11_params, "properties", t11_props);
    cJSON_AddItemToObject(t11_params, "required", t11_required);

    cJSON* p_nip05_identifier = cJSON_CreateObject();
    cJSON_AddStringToObject(p_nip05_identifier, "type", "string");
    cJSON_AddStringToObject(p_nip05_identifier, "description", "NIP-05 identifier in the form user@domain");
    cJSON_AddItemToObject(t11_props, "identifier", p_nip05_identifier);
    cJSON* p_nip05_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_nip05_pubkey, "type", "string");
    cJSON_AddStringToObject(p_nip05_pubkey, "description", "Optional expected pubkey to verify against lookup result");
    cJSON_AddItemToObject(t11_props, "pubkey", p_nip05_pubkey);
    cJSON_AddItemToArray(t11_required, cJSON_CreateString("identifier"));

    cJSON_AddItemToObject(t11_fn, "parameters", t11_params);
    cJSON_AddItemToObject(t11, "function", t11_fn);
    cJSON_AddItemToArray(tools, t11);

    cJSON* t12 = cJSON_CreateObject();
    cJSON* t12_fn = cJSON_CreateObject();
    cJSON* t12_params = cJSON_CreateObject();
    cJSON* t12_props = cJSON_CreateObject();
    cJSON* t12_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t12, "type", "function");
    cJSON_AddStringToObject(t12_fn, "name", "nostr_encode");
    cJSON_AddStringToObject(t12_fn, "description", "Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)");
    cJSON_AddStringToObject(t12_params, "type", "object");
    cJSON_AddItemToObject(t12_params, "properties", t12_props);
    cJSON_AddItemToObject(t12_params, "required", t12_required);

    cJSON* p_encode_type = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_type, "type", "string");
    cJSON_AddStringToObject(p_encode_type, "description", "Encoding target: npub, note, nprofile, nevent, or naddr");
    cJSON_AddItemToObject(t12_props, "type", p_encode_type);
    cJSON* p_encode_hex = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_hex, "type", "string");
    cJSON_AddStringToObject(p_encode_hex, "description", "Hex pubkey or event id to encode");
    cJSON_AddItemToObject(t12_props, "hex", p_encode_hex);
    cJSON* p_encode_relays = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_relays, "type", "array");
    cJSON_AddStringToObject(p_encode_relays, "description", "Optional relay URLs included in nprofile/nevent/naddr encodings");
    cJSON* p_encode_relays_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_relays_item, "type", "string");
    cJSON_AddItemToObject(p_encode_relays, "items", p_encode_relays_item);
    cJSON_AddItemToObject(t12_props, "relays", p_encode_relays);
    cJSON* p_encode_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_kind, "type", "integer");
    cJSON_AddStringToObject(p_encode_kind, "description", "Required for naddr: replaceable event kind");
    cJSON_AddItemToObject(t12_props, "kind", p_encode_kind);
    cJSON* p_encode_identifier = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encode_identifier, "type", "string");
    cJSON_AddStringToObject(p_encode_identifier, "description", "Required for naddr: replaceable event identifier (d tag)");
    cJSON_AddItemToObject(t12_props, "identifier", p_encode_identifier);

    cJSON_AddItemToArray(t12_required, cJSON_CreateString("type"));
    cJSON_AddItemToArray(t12_required, cJSON_CreateString("hex"));

    cJSON_AddItemToObject(t12_fn, "parameters", t12_params);
    cJSON_AddItemToObject(t12, "function", t12_fn);
    cJSON_AddItemToArray(tools, t12);

    cJSON* t13 = cJSON_CreateObject();
    cJSON* t13_fn = cJSON_CreateObject();
    cJSON* t13_params = cJSON_CreateObject();
    cJSON* t13_props = cJSON_CreateObject();
    cJSON* t13_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t13, "type", "function");
    cJSON_AddStringToObject(t13_fn, "name", "nostr_decode");
    cJSON_AddStringToObject(t13_fn, "description", "Decode a Nostr bech32/nostr: URI into components");
    cJSON_AddStringToObject(t13_params, "type", "object");
    cJSON_AddItemToObject(t13_params, "properties", t13_props);
    cJSON_AddItemToObject(t13_params, "required", t13_required);

    cJSON* p_decode_uri = cJSON_CreateObject();
    cJSON_AddStringToObject(p_decode_uri, "type", "string");
    cJSON_AddStringToObject(p_decode_uri, "description", "nostr: URI or bech32 value to decode");
    cJSON_AddItemToObject(t13_props, "uri", p_decode_uri);
    cJSON_AddItemToArray(t13_required, cJSON_CreateString("uri"));

    cJSON_AddItemToObject(t13_fn, "parameters", t13_params);
    cJSON_AddItemToObject(t13, "function", t13_fn);
    cJSON_AddItemToArray(tools, t13);

    cJSON* t14 = cJSON_CreateObject();
    cJSON* t14_fn = cJSON_CreateObject();
    cJSON* t14_params = cJSON_CreateObject();
    cJSON* t14_props = cJSON_CreateObject();
    cJSON* t14_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t14, "type", "function");
    cJSON_AddStringToObject(t14_fn, "name", "nostr_dm_send");
    cJSON_AddStringToObject(t14_fn, "description", "Send a NIP-04 encrypted DM");
    cJSON_AddStringToObject(t14_params, "type", "object");
    cJSON_AddItemToObject(t14_params, "properties", t14_props);
    cJSON_AddItemToObject(t14_params, "required", t14_required);

    cJSON* p_dm_recipient = cJSON_CreateObject();
    cJSON_AddStringToObject(p_dm_recipient, "type", "string");
    cJSON_AddStringToObject(p_dm_recipient, "description", "Recipient pubkey in hex");
    cJSON_AddItemToObject(t14_props, "recipient_pubkey", p_dm_recipient);
    cJSON* p_dm_message = cJSON_CreateObject();
    cJSON_AddStringToObject(p_dm_message, "type", "string");
    cJSON_AddStringToObject(p_dm_message, "description", "Plaintext message to encrypt and send");
    cJSON_AddItemToObject(t14_props, "message", p_dm_message);

    cJSON_AddItemToArray(t14_required, cJSON_CreateString("recipient_pubkey"));
    cJSON_AddItemToArray(t14_required, cJSON_CreateString("message"));

    cJSON_AddItemToObject(t14_fn, "parameters", t14_params);
    cJSON_AddItemToObject(t14, "function", t14_fn);
    cJSON_AddItemToArray(tools, t14);

    cJSON* t15 = cJSON_CreateObject();
    cJSON* t15_fn = cJSON_CreateObject();
    cJSON* t15_params = cJSON_CreateObject();
    cJSON* t15_props = cJSON_CreateObject();
    cJSON* t15_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t15, "type", "function");
    cJSON_AddStringToObject(t15_fn, "name", "nostr_relay_info");
    cJSON_AddStringToObject(t15_fn, "description", "Fetch NIP-11 relay information document");
    cJSON_AddStringToObject(t15_params, "type", "object");
    cJSON_AddItemToObject(t15_params, "properties", t15_props);
    cJSON_AddItemToObject(t15_params, "required", t15_required);

    cJSON* p_relay_info_url = cJSON_CreateObject();
    cJSON_AddStringToObject(p_relay_info_url, "type", "string");
    cJSON_AddStringToObject(p_relay_info_url, "description", "Relay websocket URL (ws:// or wss://)");
    cJSON_AddItemToObject(t15_props, "relay_url", p_relay_info_url);
    cJSON_AddItemToArray(t15_required, cJSON_CreateString("relay_url"));

    cJSON_AddItemToObject(t15_fn, "parameters", t15_params);
    cJSON_AddItemToObject(t15, "function", t15_fn);
    cJSON_AddItemToArray(tools, t15);

    cJSON* t15b = cJSON_CreateObject();
    cJSON* t15b_fn = cJSON_CreateObject();
    cJSON* t15b_params = cJSON_CreateObject();
    cJSON* t15b_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t15b, "type", "function");
    cJSON_AddStringToObject(t15b_fn, "name", "nostr_subscription_status");
    cJSON_AddStringToObject(t15b_fn, "description", "List currently managed runtime Nostr subscriptions and filters");
    cJSON_AddStringToObject(t15b_params, "type", "object");
    cJSON_AddItemToObject(t15b_params, "properties", t15b_props);
    cJSON_AddItemToObject(t15b_fn, "parameters", t15b_params);
    cJSON_AddItemToObject(t15b, "function", t15b_fn);
    cJSON_AddItemToArray(tools, t15b);

    cJSON* t15c = cJSON_CreateObject();
    cJSON* t15c_fn = cJSON_CreateObject();
    cJSON* t15c_params = cJSON_CreateObject();
    cJSON* t15c_props = cJSON_CreateObject();
    cJSON* t15c_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t15c, "type", "function");
    cJSON_AddStringToObject(t15c_fn, "name", "nostr_subscription_set");
    cJSON_AddStringToObject(t15c_fn, "description", "Update one managed runtime subscription by name (toggle enabled and/or replace filter)");
    cJSON_AddStringToObject(t15c_params, "type", "object");
    cJSON_AddItemToObject(t15c_params, "properties", t15c_props);
    cJSON_AddItemToObject(t15c_params, "required", t15c_required);

    cJSON* p_sub_name = cJSON_CreateObject();
    cJSON_AddStringToObject(p_sub_name, "type", "string");
    cJSON_AddStringToObject(p_sub_name, "description", "Subscription name (e.g. admin_context_profile, agent_context_notes, dms_kind4)");
    cJSON_AddItemToObject(t15c_props, "name", p_sub_name);

    cJSON* p_sub_enabled = cJSON_CreateObject();
    cJSON_AddStringToObject(p_sub_enabled, "type", "boolean");
    cJSON_AddStringToObject(p_sub_enabled, "description", "Optional: enable or disable this subscription");
    cJSON_AddItemToObject(t15c_props, "enabled", p_sub_enabled);

    cJSON* p_sub_filter = cJSON_CreateObject();
    cJSON_AddStringToObject(p_sub_filter, "type", "object");
    cJSON_AddStringToObject(p_sub_filter, "description", "Optional: replacement Nostr filter object");
    cJSON_AddItemToObject(t15c_props, "filter", p_sub_filter);

    cJSON_AddItemToArray(t15c_required, cJSON_CreateString("name"));

    cJSON_AddItemToObject(t15c_fn, "parameters", t15c_params);
    cJSON_AddItemToObject(t15c, "function", t15c_fn);
    cJSON_AddItemToArray(tools, t15c);

    cJSON* t16 = cJSON_CreateObject();
    cJSON* t16_fn = cJSON_CreateObject();
    cJSON* t16_params = cJSON_CreateObject();
    cJSON* t16_props = cJSON_CreateObject();
    cJSON* t16_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t16, "type", "function");
    cJSON_AddStringToObject(t16_fn, "name", "nostr_encrypt");
    cJSON_AddStringToObject(t16_fn, "description", "Encrypt plaintext using NIP-44 for a recipient");
    cJSON_AddStringToObject(t16_params, "type", "object");
    cJSON_AddItemToObject(t16_params, "properties", t16_props);
    cJSON_AddItemToObject(t16_params, "required", t16_required);

    cJSON* p_encrypt_recipient = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encrypt_recipient, "type", "string");
    cJSON_AddStringToObject(p_encrypt_recipient, "description", "Recipient pubkey in hex");
    cJSON_AddItemToObject(t16_props, "recipient_pubkey", p_encrypt_recipient);
    cJSON* p_encrypt_plaintext = cJSON_CreateObject();
    cJSON_AddStringToObject(p_encrypt_plaintext, "type", "string");
    cJSON_AddStringToObject(p_encrypt_plaintext, "description", "Plaintext to encrypt with NIP-44");
    cJSON_AddItemToObject(t16_props, "plaintext", p_encrypt_plaintext);

    cJSON_AddItemToArray(t16_required, cJSON_CreateString("recipient_pubkey"));
    cJSON_AddItemToArray(t16_required, cJSON_CreateString("plaintext"));

    cJSON_AddItemToObject(t16_fn, "parameters", t16_params);
    cJSON_AddItemToObject(t16, "function", t16_fn);
    cJSON_AddItemToArray(tools, t16);

    cJSON* t17 = cJSON_CreateObject();
    cJSON* t17_fn = cJSON_CreateObject();
    cJSON* t17_params = cJSON_CreateObject();
    cJSON* t17_props = cJSON_CreateObject();
    cJSON* t17_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t17, "type", "function");
    cJSON_AddStringToObject(t17_fn, "name", "nostr_decrypt");
    cJSON_AddStringToObject(t17_fn, "description", "Decrypt NIP-44 ciphertext from a sender");
    cJSON_AddStringToObject(t17_params, "type", "object");
    cJSON_AddItemToObject(t17_params, "properties", t17_props);
    cJSON_AddItemToObject(t17_params, "required", t17_required);

    cJSON* p_decrypt_sender = cJSON_CreateObject();
    cJSON_AddStringToObject(p_decrypt_sender, "type", "string");
    cJSON_AddStringToObject(p_decrypt_sender, "description", "Sender pubkey in hex");
    cJSON_AddItemToObject(t17_props, "sender_pubkey", p_decrypt_sender);
    cJSON* p_decrypt_ciphertext = cJSON_CreateObject();
    cJSON_AddStringToObject(p_decrypt_ciphertext, "type", "string");
    cJSON_AddStringToObject(p_decrypt_ciphertext, "description", "NIP-44 ciphertext payload to decrypt");
    cJSON_AddItemToObject(t17_props, "ciphertext", p_decrypt_ciphertext);

    cJSON_AddItemToArray(t17_required, cJSON_CreateString("sender_pubkey"));
    cJSON_AddItemToArray(t17_required, cJSON_CreateString("ciphertext"));

    cJSON_AddItemToObject(t17_fn, "parameters", t17_params);
    cJSON_AddItemToObject(t17, "function", t17_fn);
    cJSON_AddItemToArray(tools, t17);

    cJSON* t18 = cJSON_CreateObject();
    cJSON* t18_fn = cJSON_CreateObject();
    cJSON* t18_params = cJSON_CreateObject();
    cJSON* t18_props = cJSON_CreateObject();
    cJSON* t18_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t18, "type", "function");
    cJSON_AddStringToObject(t18_fn, "name", "nostr_dm_send_nip17");
    cJSON_AddStringToObject(t18_fn, "description", "Send a private DM using NIP-17 gift wrap protocol");
    cJSON_AddStringToObject(t18_params, "type", "object");
    cJSON_AddItemToObject(t18_params, "properties", t18_props);
    cJSON_AddItemToObject(t18_params, "required", t18_required);

    cJSON* p_dm17_recipient = cJSON_CreateObject();
    cJSON_AddStringToObject(p_dm17_recipient, "type", "string");
    cJSON_AddStringToObject(p_dm17_recipient, "description", "Recipient pubkey in hex");
    cJSON_AddItemToObject(t18_props, "recipient_pubkey", p_dm17_recipient);
    cJSON* p_dm17_message = cJSON_CreateObject();
    cJSON_AddStringToObject(p_dm17_message, "type", "string");
    cJSON_AddStringToObject(p_dm17_message, "description", "Message body to send in gift-wrap DM");
    cJSON_AddItemToObject(t18_props, "message", p_dm17_message);
    cJSON* p_dm17_subject = cJSON_CreateObject();
    cJSON_AddStringToObject(p_dm17_subject, "type", "string");
    cJSON_AddStringToObject(p_dm17_subject, "description", "Optional subject label for the message");
    cJSON_AddItemToObject(t18_props, "subject", p_dm17_subject);

    cJSON_AddItemToArray(t18_required, cJSON_CreateString("recipient_pubkey"));
    cJSON_AddItemToArray(t18_required, cJSON_CreateString("message"));

    cJSON_AddItemToObject(t18_fn, "parameters", t18_params);
    cJSON_AddItemToObject(t18, "function", t18_fn);
    cJSON_AddItemToArray(tools, t18);

    cJSON* t19 = cJSON_CreateObject();
    cJSON* t19_fn = cJSON_CreateObject();
    cJSON* t19_params = cJSON_CreateObject();
    cJSON* t19_props = cJSON_CreateObject();
    cJSON* t19_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t19, "type", "function");
    cJSON_AddStringToObject(t19_fn, "name", "nostr_list_manage");
    cJSON_AddStringToObject(t19_fn, "description", "Add/remove tag tuples in replaceable list events (NIP-51 style)");
    cJSON_AddStringToObject(t19_params, "type", "object");
    cJSON_AddItemToObject(t19_params, "properties", t19_props);
    cJSON_AddItemToObject(t19_params, "required", t19_required);

    cJSON* p_list_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_list_kind, "type", "integer");
    cJSON_AddStringToObject(p_list_kind, "description", "Replaceable list kind to edit (for example 10000 mute, 10001 pin, 10002 relay list)");
    cJSON_AddItemToObject(t19_props, "list_kind", p_list_kind);
    cJSON* p_list_action = cJSON_CreateObject();
    cJSON_AddStringToObject(p_list_action, "type", "string");
    cJSON_AddStringToObject(p_list_action, "description", "Operation to perform: add or remove");
    cJSON_AddItemToObject(t19_props, "action", p_list_action);
    cJSON* p_list_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_list_items, "type", "array");
    cJSON_AddStringToObject(p_list_items, "description", "Tag tuples to add/remove, e.g. [[\"p\",\"<pubkey>\"],[\"e\",\"<event_id>\"]]");
    cJSON* p_list_items_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_list_items_item, "type", "array");
    cJSON* p_list_items_item_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_list_items_item_item, "type", "string");
    cJSON_AddItemToObject(p_list_items_item, "items", p_list_items_item_item);
    cJSON_AddItemToObject(p_list_items, "items", p_list_items_item);
    cJSON_AddItemToObject(t19_props, "items", p_list_items);

    cJSON_AddItemToArray(t19_required, cJSON_CreateString("list_kind"));
    cJSON_AddItemToArray(t19_required, cJSON_CreateString("action"));
    cJSON_AddItemToArray(t19_required, cJSON_CreateString("items"));

    cJSON_AddItemToObject(t19_fn, "parameters", t19_params);
    cJSON_AddItemToObject(t19, "function", t19_fn);
    cJSON_AddItemToArray(tools, t19);

    cJSON* t19b = cJSON_CreateObject();
    cJSON* t19b_fn = cJSON_CreateObject();
    cJSON* t19b_params = cJSON_CreateObject();
    cJSON* t19b_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t19b, "type", "function");
    cJSON_AddStringToObject(t19b_fn, "name", "nostr_block_list");
    cJSON_AddStringToObject(t19b_fn, "description", "View blocked pubkeys, event IDs, or hashtags from the local encrypted kind-10000 block list cache");
    cJSON_AddStringToObject(t19b_params, "type", "object");
    cJSON_AddItemToObject(t19b_params, "properties", t19b_props);

    cJSON* p_block_list_type = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_list_type, "type", "string");
    cJSON_AddStringToObject(p_block_list_type, "description", "Optional filter: all, p, e, or t (default all)");
    cJSON_AddItemToObject(t19b_props, "type", p_block_list_type);

    cJSON_AddItemToObject(t19b_fn, "parameters", t19b_params);
    cJSON_AddItemToObject(t19b, "function", t19b_fn);
    cJSON_AddItemToArray(tools, t19b);

    cJSON* t19c = cJSON_CreateObject();
    cJSON* t19c_fn = cJSON_CreateObject();
    cJSON* t19c_params = cJSON_CreateObject();
    cJSON* t19c_props = cJSON_CreateObject();
    cJSON* t19c_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t19c, "type", "function");
    cJSON_AddStringToObject(t19c_fn, "name", "nostr_block_edit");
    cJSON_AddStringToObject(t19c_fn, "description", "Add or remove blocked tuples in kind-10000 block list; entries are private (encrypted) by default");
    cJSON_AddStringToObject(t19c_params, "type", "object");
    cJSON_AddItemToObject(t19c_params, "properties", t19c_props);
    cJSON_AddItemToObject(t19c_params, "required", t19c_required);

    cJSON* p_block_action = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_action, "type", "string");
    cJSON_AddStringToObject(p_block_action, "description", "add or remove");
    cJSON_AddItemToObject(t19c_props, "action", p_block_action);

    cJSON* p_block_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_items, "type", "array");
    cJSON* p_block_items_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_items_item, "type", "array");
    cJSON* p_block_items_item_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_items_item_item, "type", "string");
    cJSON_AddItemToObject(p_block_items_item, "items", p_block_items_item_item);
    cJSON_AddItemToObject(p_block_items, "items", p_block_items_item);
    cJSON_AddStringToObject(p_block_items, "description", "Tag tuples like [[\"e\",\"<event_id>\"],[\"p\",\"<pubkey>\"],[\"t\",\"spam\"]]");
    cJSON_AddItemToObject(t19c_props, "items", p_block_items);

    cJSON* p_block_public = cJSON_CreateObject();
    cJSON_AddStringToObject(p_block_public, "type", "boolean");
    cJSON_AddStringToObject(p_block_public, "description", "Optional, default false; when true add to public tags instead of encrypted private content");
    cJSON_AddItemToObject(t19c_props, "public", p_block_public);

    cJSON_AddItemToArray(t19c_required, cJSON_CreateString("action"));
    cJSON_AddItemToArray(t19c_required, cJSON_CreateString("items"));

    cJSON_AddItemToObject(t19c_fn, "parameters", t19c_params);
    cJSON_AddItemToObject(t19c, "function", t19c_fn);
    cJSON_AddItemToArray(tools, t19c);

    cJSON* t20 = cJSON_CreateObject();
    cJSON* t20_fn = cJSON_CreateObject();
    cJSON* t20_params = cJSON_CreateObject();
    cJSON* t20_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t20, "type", "function");
    cJSON_AddStringToObject(t20_fn, "name", "agent_version");
    cJSON_AddStringToObject(t20_fn, "description", "Return current Didactyl version and metadata from build macros");
    cJSON_AddStringToObject(t20_params, "type", "object");
    cJSON_AddItemToObject(t20_params, "properties", t20_props);

    cJSON_AddItemToObject(t20_fn, "parameters", t20_params);
    cJSON_AddItemToObject(t20, "function", t20_fn);
    cJSON_AddItemToArray(tools, t20);

    cJSON* t21 = cJSON_CreateObject();
    cJSON* t21_fn = cJSON_CreateObject();
    cJSON* t21_params = cJSON_CreateObject();
    cJSON* t21_props = cJSON_CreateObject();
    cJSON* t21_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t21, "type", "function");
    cJSON_AddStringToObject(t21_fn, "name", "local_http_fetch");
    cJSON_AddStringToObject(t21_fn, "description", "Fetch HTTP(S) resources with optional method, headers, timeout, and body");
    cJSON_AddStringToObject(t21_params, "type", "object");
    cJSON_AddItemToObject(t21_params, "properties", t21_props);
    cJSON_AddItemToObject(t21_params, "required", t21_required);

    cJSON* p_http_url = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_url, "type", "string");
    cJSON_AddStringToObject(p_http_url, "description", "HTTP(S) URL to request");
    cJSON_AddItemToObject(t21_props, "url", p_http_url);

    cJSON* p_http_method = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_method, "type", "string");
    cJSON_AddStringToObject(p_http_method, "description", "Optional method such as GET, POST, PUT, PATCH, or DELETE (default GET)");
    cJSON_AddItemToObject(t21_props, "method", p_http_method);

    cJSON* p_http_headers = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_headers, "type", "array");
    cJSON_AddStringToObject(p_http_headers, "description", "Optional headers as [\"Name: value\", ...]");
    cJSON* p_http_headers_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_headers_item, "type", "string");
    cJSON_AddItemToObject(p_http_headers, "items", p_http_headers_item);
    cJSON_AddItemToObject(t21_props, "headers", p_http_headers);

    cJSON* p_http_body = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_body, "type", "string");
    cJSON_AddStringToObject(p_http_body, "description", "Optional request body for non-GET methods");
    cJSON_AddItemToObject(t21_props, "body", p_http_body);

    cJSON* p_http_timeout = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_timeout, "type", "integer");
    cJSON_AddStringToObject(p_http_timeout, "description", "Optional timeout in seconds");
    cJSON_AddItemToObject(t21_props, "timeout_seconds", p_http_timeout);

    cJSON* p_http_max_bytes = cJSON_CreateObject();
    cJSON_AddStringToObject(p_http_max_bytes, "type", "integer");
    cJSON_AddStringToObject(p_http_max_bytes, "description", "Optional maximum response bytes to capture");
    cJSON_AddItemToObject(t21_props, "max_bytes", p_http_max_bytes);

    cJSON_AddItemToArray(t21_required, cJSON_CreateString("url"));

    cJSON_AddItemToObject(t21_fn, "parameters", t21_params);
    cJSON_AddItemToObject(t21, "function", t21_fn);
    cJSON_AddItemToArray(tools, t21);

    cJSON* t22 = cJSON_CreateObject();
    cJSON* t22_fn = cJSON_CreateObject();
    cJSON* t22_params = cJSON_CreateObject();
    cJSON* t22_props = cJSON_CreateObject();
    cJSON* t22_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t22, "type", "function");
    cJSON_AddStringToObject(t22_fn, "name", "skill_create");
    cJSON_AddStringToObject(t22_fn, "description", "Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it");
    cJSON_AddStringToObject(t22_params, "type", "object");
    cJSON_AddItemToObject(t22_params, "properties", t22_props);
    cJSON_AddItemToObject(t22_params, "required", t22_required);

    cJSON* p_skill_create_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_d, "type", "string");
    cJSON_AddItemToObject(t22_props, "d", p_skill_create_d);
    cJSON* p_skill_create_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_content, "type", "string");
    cJSON_AddItemToObject(t22_props, "content", p_skill_create_content);
    cJSON* p_skill_create_scope = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_scope, "type", "string");
    cJSON_AddItemToObject(t22_props, "scope", p_skill_create_scope);
    cJSON* p_skill_create_desc = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_desc, "type", "string");
    cJSON_AddItemToObject(t22_props, "description", p_skill_create_desc);
    cJSON* p_skill_create_auto = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_auto, "type", "boolean");
    cJSON_AddItemToObject(t22_props, "auto_adopt", p_skill_create_auto);

    cJSON* p_skill_create_trigger = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_trigger, "type", "string");
    cJSON_AddItemToObject(t22_props, "trigger", p_skill_create_trigger);

    cJSON* p_skill_create_filter = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_filter, "type", "string");
    cJSON_AddItemToObject(t22_props, "filter", p_skill_create_filter);

    cJSON* p_skill_create_action = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_action, "type", "string");
    cJSON_AddItemToObject(t22_props, "action", p_skill_create_action);

    cJSON* p_skill_create_enabled = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_enabled, "type", "boolean");
    cJSON_AddItemToObject(t22_props, "enabled", p_skill_create_enabled);

    cJSON* p_skill_create_llm = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_llm, "type", "string");
    cJSON_AddStringToObject(p_skill_create_llm,
                            "description",
                            "Model to use when this trigger fires (e.g. 'gpt-4o-mini'); overrides the agent default model for this triggered skill execution only.");
    cJSON_AddItemToObject(t22_props, "llm", p_skill_create_llm);

    cJSON* p_skill_create_tools = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_tools, "type", "string");
    cJSON_AddItemToObject(t22_props, "tools", p_skill_create_tools);

    cJSON* p_skill_create_max_tokens = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_max_tokens, "type", "integer");
    cJSON_AddItemToObject(t22_props, "max_tokens", p_skill_create_max_tokens);

    cJSON* p_skill_create_temperature = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_temperature, "type", "number");
    cJSON_AddItemToObject(t22_props, "temperature", p_skill_create_temperature);

    cJSON* p_skill_create_seed = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_create_seed, "type", "integer");
    cJSON_AddItemToObject(t22_props, "seed", p_skill_create_seed);

    cJSON_AddItemToArray(t22_required, cJSON_CreateString("d"));
    cJSON_AddItemToArray(t22_required, cJSON_CreateString("content"));

    cJSON_AddItemToObject(t22_fn, "parameters", t22_params);
    cJSON_AddItemToObject(t22, "function", t22_fn);
    cJSON_AddItemToArray(tools, t22);

    cJSON* t23 = cJSON_CreateObject();
    cJSON* t23_fn = cJSON_CreateObject();
    cJSON* t23_params = cJSON_CreateObject();
    cJSON* t23_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t23, "type", "function");
    cJSON_AddStringToObject(t23_fn, "name", "skill_list");
    cJSON_AddStringToObject(t23_fn, "description", "List available skills discovered online (agent + admin), with adoption status and optional filters");
    cJSON_AddStringToObject(t23_params, "type", "object");
    cJSON_AddItemToObject(t23_params, "properties", t23_props);

    cJSON* p_skill_list_scope = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_list_scope, "type", "string");
    cJSON_AddItemToObject(t23_props, "scope", p_skill_list_scope);
    cJSON* p_skill_list_adopted = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_list_adopted, "type", "boolean");
    cJSON_AddItemToObject(t23_props, "adopted", p_skill_list_adopted);

    cJSON_AddItemToObject(t23_fn, "parameters", t23_params);
    cJSON_AddItemToObject(t23, "function", t23_fn);
    cJSON_AddItemToArray(tools, t23);

    cJSON* t24 = cJSON_CreateObject();
    cJSON* t24_fn = cJSON_CreateObject();
    cJSON* t24_params = cJSON_CreateObject();
    cJSON* t24_props = cJSON_CreateObject();
    cJSON* t24_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t24, "type", "function");
    cJSON_AddStringToObject(t24_fn, "name", "skill_adopt");
    cJSON_AddStringToObject(t24_fn, "description", "Adopt a skill by adding its address to kind 10123 adoption list");
    cJSON_AddStringToObject(t24_params, "type", "object");
    cJSON_AddItemToObject(t24_params, "properties", t24_props);
    cJSON_AddItemToObject(t24_params, "required", t24_required);

    cJSON* p_skill_adopt_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_adopt_pubkey, "type", "string");
    cJSON_AddItemToObject(t24_props, "pubkey", p_skill_adopt_pubkey);
    cJSON* p_skill_adopt_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_adopt_d, "type", "string");
    cJSON_AddItemToObject(t24_props, "d", p_skill_adopt_d);
    cJSON* p_skill_adopt_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_adopt_kind, "type", "integer");
    cJSON_AddItemToObject(t24_props, "kind", p_skill_adopt_kind);

    cJSON_AddItemToArray(t24_required, cJSON_CreateString("pubkey"));
    cJSON_AddItemToArray(t24_required, cJSON_CreateString("d"));

    cJSON_AddItemToObject(t24_fn, "parameters", t24_params);
    cJSON_AddItemToObject(t24, "function", t24_fn);
    cJSON_AddItemToArray(tools, t24);

    cJSON* t25 = cJSON_CreateObject();
    cJSON* t25_fn = cJSON_CreateObject();
    cJSON* t25_params = cJSON_CreateObject();
    cJSON* t25_props = cJSON_CreateObject();
    cJSON* t25_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t25, "type", "function");
    cJSON_AddStringToObject(t25_fn, "name", "skill_remove");
    cJSON_AddStringToObject(t25_fn, "description", "Remove a skill address from kind 10123 adoption list");
    cJSON_AddStringToObject(t25_params, "type", "object");
    cJSON_AddItemToObject(t25_params, "properties", t25_props);
    cJSON_AddItemToObject(t25_params, "required", t25_required);

    cJSON* p_skill_remove_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_remove_pubkey, "type", "string");
    cJSON_AddItemToObject(t25_props, "pubkey", p_skill_remove_pubkey);
    cJSON* p_skill_remove_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_remove_d, "type", "string");
    cJSON_AddItemToObject(t25_props, "d", p_skill_remove_d);
    cJSON* p_skill_remove_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_remove_kind, "type", "integer");
    cJSON_AddItemToObject(t25_props, "kind", p_skill_remove_kind);

    cJSON_AddItemToArray(t25_required, cJSON_CreateString("d"));

    cJSON_AddItemToObject(t25_fn, "parameters", t25_params);
    cJSON_AddItemToObject(t25, "function", t25_fn);
    cJSON_AddItemToArray(tools, t25);

    cJSON* t25b = cJSON_CreateObject();
    cJSON* t25b_fn = cJSON_CreateObject();
    cJSON* t25b_params = cJSON_CreateObject();
    cJSON* t25b_props = cJSON_CreateObject();
    cJSON* t25b_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t25b, "type", "function");
    cJSON_AddStringToObject(t25b_fn, "name", "skill_edit");
    cJSON_AddStringToObject(t25b_fn, "description", "Edit an existing self skill by d tag and republish it as kind 31123/31124");
    cJSON_AddStringToObject(t25b_params, "type", "object");
    cJSON_AddItemToObject(t25b_params, "properties", t25b_props);
    cJSON_AddItemToObject(t25b_params, "required", t25b_required);

    cJSON* p_skill_edit_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_d, "type", "string");
    cJSON_AddItemToObject(t25b_props, "d", p_skill_edit_d);

    cJSON* p_skill_edit_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_content, "type", "string");
    cJSON_AddItemToObject(t25b_props, "content", p_skill_edit_content);

    cJSON* p_skill_edit_scope = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_scope, "type", "string");
    cJSON_AddItemToObject(t25b_props, "scope", p_skill_edit_scope);

    cJSON* p_skill_edit_desc = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_desc, "type", "string");
    cJSON_AddItemToObject(t25b_props, "description", p_skill_edit_desc);

    cJSON* p_skill_edit_trigger = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_trigger, "type", "string");
    cJSON_AddItemToObject(t25b_props, "trigger", p_skill_edit_trigger);

    cJSON* p_skill_edit_filter = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_filter, "type", "string");
    cJSON_AddItemToObject(t25b_props, "filter", p_skill_edit_filter);

    cJSON* p_skill_edit_action = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_action, "type", "string");
    cJSON_AddItemToObject(t25b_props, "action", p_skill_edit_action);

    cJSON* p_skill_edit_enabled = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_enabled, "type", "boolean");
    cJSON_AddItemToObject(t25b_props, "enabled", p_skill_edit_enabled);

    cJSON* p_skill_edit_llm = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_llm, "type", "string");
    cJSON_AddStringToObject(p_skill_edit_llm,
                            "description",
                            "Model to use when this trigger fires (e.g. 'gpt-4o-mini'); overrides the agent default model for this triggered skill execution only.");
    cJSON_AddItemToObject(t25b_props, "llm", p_skill_edit_llm);

    cJSON* p_skill_edit_tools = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_tools, "type", "string");
    cJSON_AddItemToObject(t25b_props, "tools", p_skill_edit_tools);

    cJSON* p_skill_edit_max_tokens = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_max_tokens, "type", "integer");
    cJSON_AddItemToObject(t25b_props, "max_tokens", p_skill_edit_max_tokens);

    cJSON* p_skill_edit_temperature = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_temperature, "type", "number");
    cJSON_AddItemToObject(t25b_props, "temperature", p_skill_edit_temperature);

    cJSON* p_skill_edit_seed = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_edit_seed, "type", "integer");
    cJSON_AddItemToObject(t25b_props, "seed", p_skill_edit_seed);

    cJSON_AddItemToArray(t25b_required, cJSON_CreateString("d"));

    cJSON_AddItemToObject(t25b_fn, "parameters", t25b_params);
    cJSON_AddItemToObject(t25b, "function", t25b_fn);
    cJSON_AddItemToArray(tools, t25b);

    cJSON* t26 = cJSON_CreateObject();
    cJSON* t26_fn = cJSON_CreateObject();
    cJSON* t26_params = cJSON_CreateObject();
    cJSON* t26_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t26, "type", "function");
    cJSON_AddStringToObject(t26_fn, "name", "skill_search");
    cJSON_AddStringToObject(t26_fn, "description", "Search public skills by query/author and optionally rank by adoption popularity");
    cJSON_AddStringToObject(t26_params, "type", "object");
    cJSON_AddItemToObject(t26_params, "properties", t26_props);

    cJSON* p_skill_search_query = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_search_query, "type", "string");
    cJSON_AddItemToObject(t26_props, "query", p_skill_search_query);
    cJSON* p_skill_search_pubkey = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_search_pubkey, "type", "string");
    cJSON_AddItemToObject(t26_props, "pubkey", p_skill_search_pubkey);
    cJSON* p_skill_search_popular = cJSON_CreateObject();
    cJSON_AddStringToObject(p_skill_search_popular, "type", "boolean");
    cJSON_AddItemToObject(t26_props, "popular", p_skill_search_popular);

    cJSON_AddItemToObject(t26_fn, "parameters", t26_params);
    cJSON_AddItemToObject(t26, "function", t26_fn);
    cJSON_AddItemToArray(tools, t26);

    cJSON* t27 = cJSON_CreateObject();
    cJSON* t27_fn = cJSON_CreateObject();
    cJSON* t27_params = cJSON_CreateObject();
    cJSON* t27_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t27, "type", "function");
    cJSON_AddStringToObject(t27_fn, "name", "trigger_list");
    cJSON_AddStringToObject(t27_fn, "description", "List active triggered skills and their runtime status");
    cJSON_AddStringToObject(t27_params, "type", "object");
    cJSON_AddItemToObject(t27_params, "properties", t27_props);

    cJSON_AddItemToObject(t27_fn, "parameters", t27_params);
    cJSON_AddItemToObject(t27, "function", t27_fn);
    cJSON_AddItemToArray(tools, t27);

    cJSON* t28 = cJSON_CreateObject();
    cJSON* t28_fn = cJSON_CreateObject();
    cJSON* t28_params = cJSON_CreateObject();
    cJSON* t28_props = cJSON_CreateObject();
    cJSON* t28_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t28, "type", "function");
    cJSON_AddStringToObject(t28_fn, "name", "nostr_file_md_to_longform_post");
    cJSON_AddStringToObject(t28_fn, "description", "Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename");
    cJSON_AddStringToObject(t28_params, "type", "object");
    cJSON_AddItemToObject(t28_params, "properties", t28_props);
    cJSON_AddItemToObject(t28_params, "required", t28_required);

    cJSON* p_lf_file = cJSON_CreateObject();
    cJSON_AddStringToObject(p_lf_file, "type", "string");
    cJSON_AddItemToObject(t28_props, "file", p_lf_file);

    cJSON* p_lf_title = cJSON_CreateObject();
    cJSON_AddStringToObject(p_lf_title, "type", "string");
    cJSON_AddItemToObject(t28_props, "title", p_lf_title);

    cJSON* p_lf_image = cJSON_CreateObject();
    cJSON_AddStringToObject(p_lf_image, "type", "string");
    cJSON_AddItemToObject(t28_props, "image", p_lf_image);

    cJSON* p_lf_summary = cJSON_CreateObject();
    cJSON_AddStringToObject(p_lf_summary, "type", "string");
    cJSON_AddItemToObject(t28_props, "summary", p_lf_summary);

    cJSON_AddItemToArray(t28_required, cJSON_CreateString("file"));

    cJSON_AddItemToObject(t28_fn, "parameters", t28_params);
    cJSON_AddItemToObject(t28, "function", t28_fn);
    cJSON_AddItemToArray(tools, t28);

    cJSON* t29 = cJSON_CreateObject();
    cJSON* t29_fn = cJSON_CreateObject();
    cJSON* t29_params = cJSON_CreateObject();
    cJSON* t29_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t29, "type", "function");
    cJSON_AddStringToObject(t29_fn, "name", "tool_list");
    cJSON_AddStringToObject(t29_fn, "description", "List available tools with name, description, and JSON parameter schema");
    cJSON_AddStringToObject(t29_params, "type", "object");
    cJSON_AddItemToObject(t29_params, "properties", t29_props);

    cJSON_AddItemToObject(t29_fn, "parameters", t29_params);
    cJSON_AddItemToObject(t29, "function", t29_fn);
    cJSON_AddItemToArray(tools, t29);

    cJSON* t30 = cJSON_CreateObject();
    cJSON* t30_fn = cJSON_CreateObject();
    cJSON* t30_params = cJSON_CreateObject();
    cJSON* t30_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t30, "type", "function");
    cJSON_AddStringToObject(t30_fn, "name", "model_get");
    cJSON_AddStringToObject(t30_fn, "description", "Get current active LLM runtime configuration (excluding API key)");
    cJSON_AddStringToObject(t30_params, "type", "object");
    cJSON_AddItemToObject(t30_params, "properties", t30_props);

    cJSON_AddItemToObject(t30_fn, "parameters", t30_params);
    cJSON_AddItemToObject(t30, "function", t30_fn);
    cJSON_AddItemToArray(tools, t30);

    cJSON* t31 = cJSON_CreateObject();
    cJSON* t31_fn = cJSON_CreateObject();
    cJSON* t31_params = cJSON_CreateObject();
    cJSON* t31_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t31, "type", "function");
    cJSON_AddStringToObject(t31_fn, "name", "model_set");
    cJSON_AddStringToObject(t31_fn, "description", "Update active LLM configuration and persist it to Nostr kind 30078 (d=llm_config)");
    cJSON_AddStringToObject(t31_params, "type", "object");
    cJSON_AddItemToObject(t31_params, "properties", t31_props);

    cJSON* p_model_set_provider = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_provider, "type", "string");
    cJSON_AddItemToObject(t31_props, "provider", p_model_set_provider);

    cJSON* p_model_set_api_key = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_api_key, "type", "string");
    cJSON_AddItemToObject(t31_props, "api_key", p_model_set_api_key);

    cJSON* p_model_set_model = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_model, "type", "string");
    cJSON_AddItemToObject(t31_props, "model", p_model_set_model);

    cJSON* p_model_set_base_url = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_base_url, "type", "string");
    cJSON_AddItemToObject(t31_props, "base_url", p_model_set_base_url);

    cJSON* p_model_set_max_tokens = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_max_tokens, "type", "integer");
    cJSON_AddItemToObject(t31_props, "max_tokens", p_model_set_max_tokens);

    cJSON* p_model_set_temperature = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_set_temperature, "type", "number");
    cJSON_AddItemToObject(t31_props, "temperature", p_model_set_temperature);

    cJSON_AddItemToObject(t31_fn, "parameters", t31_params);
    cJSON_AddItemToObject(t31, "function", t31_fn);
    cJSON_AddItemToArray(tools, t31);

    cJSON* t32 = cJSON_CreateObject();
    cJSON* t32_fn = cJSON_CreateObject();
    cJSON* t32_params = cJSON_CreateObject();
    cJSON* t32_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t32, "type", "function");
    cJSON_AddStringToObject(t32_fn, "name", "model_list");
    cJSON_AddStringToObject(t32_fn, "description", "List available model IDs using provider OpenAI-compatible /models endpoint");
    cJSON_AddStringToObject(t32_params, "type", "object");
    cJSON_AddItemToObject(t32_params, "properties", t32_props);

    cJSON* p_model_list_base_url = cJSON_CreateObject();
    cJSON_AddStringToObject(p_model_list_base_url, "type", "string");
    cJSON_AddItemToObject(t32_props, "base_url", p_model_list_base_url);

    cJSON_AddItemToObject(t32_fn, "parameters", t32_params);
    cJSON_AddItemToObject(t32, "function", t32_fn);
    cJSON_AddItemToArray(tools, t32);

    cJSON* t33 = cJSON_CreateObject();
    cJSON* t33_fn = cJSON_CreateObject();
    cJSON* t33_params = cJSON_CreateObject();
    cJSON* t33_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t33, "type", "function");
    cJSON_AddStringToObject(t33_fn, "name", "nostr_pubkey");
    cJSON_AddStringToObject(t33_fn, "description", "Return this agent's pubkey in hex format");
    cJSON_AddStringToObject(t33_params, "type", "object");
    cJSON_AddItemToObject(t33_params, "properties", t33_props);

    cJSON_AddItemToObject(t33_fn, "parameters", t33_params);
    cJSON_AddItemToObject(t33, "function", t33_fn);
    cJSON_AddItemToArray(tools, t33);

    cJSON* t34 = cJSON_CreateObject();
    cJSON* t34_fn = cJSON_CreateObject();
    cJSON* t34_params = cJSON_CreateObject();
    cJSON* t34_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t34, "type", "function");
    cJSON_AddStringToObject(t34_fn, "name", "nostr_npub");
    cJSON_AddStringToObject(t34_fn, "description", "Return this agent's pubkey encoded as npub bech32");
    cJSON_AddStringToObject(t34_params, "type", "object");
    cJSON_AddItemToObject(t34_params, "properties", t34_props);

    cJSON_AddItemToObject(t34_fn, "parameters", t34_params);
    cJSON_AddItemToObject(t34, "function", t34_fn);
    cJSON_AddItemToArray(tools, t34);

    cJSON* t35 = cJSON_CreateObject();
    cJSON* t35_fn = cJSON_CreateObject();
    cJSON* t35_params = cJSON_CreateObject();
    cJSON* t35_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t35, "type", "function");
    cJSON_AddStringToObject(t35_fn, "name", "my_pubkey");
    cJSON_AddStringToObject(t35_fn, "description", "Alias for nostr_pubkey: return this agent's pubkey in hex format");
    cJSON_AddStringToObject(t35_params, "type", "object");
    cJSON_AddItemToObject(t35_params, "properties", t35_props);

    cJSON_AddItemToObject(t35_fn, "parameters", t35_params);
    cJSON_AddItemToObject(t35, "function", t35_fn);
    cJSON_AddItemToArray(tools, t35);

    cJSON* t36 = cJSON_CreateObject();
    cJSON* t36_fn = cJSON_CreateObject();
    cJSON* t36_params = cJSON_CreateObject();
    cJSON* t36_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t36, "type", "function");
    cJSON_AddStringToObject(t36_fn, "name", "my_npub");
    cJSON_AddStringToObject(t36_fn, "description", "Alias for nostr_npub: return this agent's pubkey encoded as npub bech32");
    cJSON_AddStringToObject(t36_params, "type", "object");
    cJSON_AddItemToObject(t36_params, "properties", t36_props);

    cJSON_AddItemToObject(t36_fn, "parameters", t36_params);
    cJSON_AddItemToObject(t36, "function", t36_fn);
    cJSON_AddItemToArray(tools, t36);

    cJSON* t37 = cJSON_CreateObject();
    cJSON* t37_fn = cJSON_CreateObject();
    cJSON* t37_params = cJSON_CreateObject();
    cJSON* t37_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t37, "type", "function");
    cJSON_AddStringToObject(t37_fn, "name", "admin_identity");
    cJSON_AddStringToObject(t37_fn, "description", "Build admin identity context block from cached runtime metadata");
    cJSON_AddStringToObject(t37_params, "type", "object");
    cJSON_AddItemToObject(t37_params, "properties", t37_props);
    cJSON_AddItemToObject(t37_fn, "parameters", t37_params);
    cJSON_AddItemToObject(t37, "function", t37_fn);
    cJSON_AddItemToArray(tools, t37);

    cJSON* t38 = cJSON_CreateObject();
    cJSON* t38_fn = cJSON_CreateObject();
    cJSON* t38_params = cJSON_CreateObject();
    cJSON* t38_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t38, "type", "function");
    cJSON_AddStringToObject(t38_fn, "name", "nostr_admin_profile");
    cJSON_AddStringToObject(t38_fn, "description", "Build admin profile context block from cached kind 0 metadata");
    cJSON_AddStringToObject(t38_params, "type", "object");
    cJSON_AddItemToObject(t38_params, "properties", t38_props);
    cJSON_AddItemToObject(t38_fn, "parameters", t38_params);
    cJSON_AddItemToObject(t38, "function", t38_fn);
    cJSON_AddItemToArray(tools, t38);

    cJSON* t39 = cJSON_CreateObject();
    cJSON* t39_fn = cJSON_CreateObject();
    cJSON* t39_params = cJSON_CreateObject();
    cJSON* t39_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t39, "type", "function");
    cJSON_AddStringToObject(t39_fn, "name", "nostr_admin_contacts");
    cJSON_AddStringToObject(t39_fn, "description", "Build admin contacts context block from cached kind 3 contact list");
    cJSON_AddStringToObject(t39_params, "type", "object");
    cJSON_AddItemToObject(t39_params, "properties", t39_props);
    cJSON_AddItemToObject(t39_fn, "parameters", t39_params);
    cJSON_AddItemToObject(t39, "function", t39_fn);
    cJSON_AddItemToArray(tools, t39);

    cJSON* t40 = cJSON_CreateObject();
    cJSON* t40_fn = cJSON_CreateObject();
    cJSON* t40_params = cJSON_CreateObject();
    cJSON* t40_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t40, "type", "function");
    cJSON_AddStringToObject(t40_fn, "name", "nostr_admin_relays");
    cJSON_AddStringToObject(t40_fn, "description", "Build admin relay context block from cached kind 10002 data");
    cJSON_AddStringToObject(t40_params, "type", "object");
    cJSON_AddItemToObject(t40_params, "properties", t40_props);
    cJSON_AddItemToObject(t40_fn, "parameters", t40_params);
    cJSON_AddItemToObject(t40, "function", t40_fn);
    cJSON_AddItemToArray(tools, t40);

    cJSON* t41 = cJSON_CreateObject();
    cJSON* t41_fn = cJSON_CreateObject();
    cJSON* t41_params = cJSON_CreateObject();
    cJSON* t41_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41, "type", "function");
    cJSON_AddStringToObject(t41_fn, "name", "nostr_admin_notes");
    cJSON_AddStringToObject(t41_fn, "description", "Build admin notes context block from cached kind 1 notes");
    cJSON_AddStringToObject(t41_params, "type", "object");
    cJSON_AddItemToObject(t41_params, "properties", t41_props);
    cJSON_AddItemToObject(t41_fn, "parameters", t41_params);
    cJSON_AddItemToObject(t41, "function", t41_fn);
    cJSON_AddItemToArray(tools, t41);

    cJSON* t41b = cJSON_CreateObject();
    cJSON* t41b_fn = cJSON_CreateObject();
    cJSON* t41b_params = cJSON_CreateObject();
    cJSON* t41b_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41b, "type", "function");
    cJSON_AddStringToObject(t41b_fn, "name", "nostr_agent_profile");
    cJSON_AddStringToObject(t41b_fn, "description", "Build agent profile context block from cached kind 0 metadata");
    cJSON_AddStringToObject(t41b_params, "type", "object");
    cJSON_AddItemToObject(t41b_params, "properties", t41b_props);
    cJSON_AddItemToObject(t41b_fn, "parameters", t41b_params);
    cJSON_AddItemToObject(t41b, "function", t41b_fn);
    cJSON_AddItemToArray(tools, t41b);

    cJSON* t41c = cJSON_CreateObject();
    cJSON* t41c_fn = cJSON_CreateObject();
    cJSON* t41c_params = cJSON_CreateObject();
    cJSON* t41c_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41c, "type", "function");
    cJSON_AddStringToObject(t41c_fn, "name", "nostr_agent_contacts");
    cJSON_AddStringToObject(t41c_fn, "description", "Build agent contacts context block from cached kind 3 contact list");
    cJSON_AddStringToObject(t41c_params, "type", "object");
    cJSON_AddItemToObject(t41c_params, "properties", t41c_props);
    cJSON_AddItemToObject(t41c_fn, "parameters", t41c_params);
    cJSON_AddItemToObject(t41c, "function", t41c_fn);
    cJSON_AddItemToArray(tools, t41c);

    cJSON* t41d = cJSON_CreateObject();
    cJSON* t41d_fn = cJSON_CreateObject();
    cJSON* t41d_params = cJSON_CreateObject();
    cJSON* t41d_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41d, "type", "function");
    cJSON_AddStringToObject(t41d_fn, "name", "nostr_agent_relays");
    cJSON_AddStringToObject(t41d_fn, "description", "Build agent relay context block from cached kind 10002 data");
    cJSON_AddStringToObject(t41d_params, "type", "object");
    cJSON_AddItemToObject(t41d_params, "properties", t41d_props);
    cJSON_AddItemToObject(t41d_fn, "parameters", t41d_params);
    cJSON_AddItemToObject(t41d, "function", t41d_fn);
    cJSON_AddItemToArray(tools, t41d);

    cJSON* t41e = cJSON_CreateObject();
    cJSON* t41e_fn = cJSON_CreateObject();
    cJSON* t41e_params = cJSON_CreateObject();
    cJSON* t41e_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41e, "type", "function");
    cJSON_AddStringToObject(t41e_fn, "name", "nostr_agent_notes");
    cJSON_AddStringToObject(t41e_fn, "description", "Build agent notes context block from cached kind 1 notes");
    cJSON_AddStringToObject(t41e_params, "type", "object");
    cJSON_AddItemToObject(t41e_params, "properties", t41e_props);
    cJSON_AddItemToObject(t41e_fn, "parameters", t41e_params);
    cJSON_AddItemToObject(t41e, "function", t41e_fn);
    cJSON_AddItemToArray(tools, t41e);

    cJSON* t41f = cJSON_CreateObject();
    cJSON* t41f_fn = cJSON_CreateObject();
    cJSON* t41f_params = cJSON_CreateObject();
    cJSON* t41f_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41f, "type", "function");
    cJSON_AddStringToObject(t41f_fn, "name", "my_kind0_profile");
    cJSON_AddStringToObject(t41f_fn, "description", "Alias for nostr_agent_profile: return this agent's kind 0 profile context");
    cJSON_AddStringToObject(t41f_params, "type", "object");
    cJSON_AddItemToObject(t41f_params, "properties", t41f_props);
    cJSON_AddItemToObject(t41f_fn, "parameters", t41f_params);
    cJSON_AddItemToObject(t41f, "function", t41f_fn);
    cJSON_AddItemToArray(tools, t41f);

    cJSON* t41g = cJSON_CreateObject();
    cJSON* t41g_fn = cJSON_CreateObject();
    cJSON* t41g_params = cJSON_CreateObject();
    cJSON* t41g_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41g, "type", "function");
    cJSON_AddStringToObject(t41g_fn, "name", "my_contacts");
    cJSON_AddStringToObject(t41g_fn, "description", "Alias for nostr_agent_contacts: return this agent's kind 3 contacts context");
    cJSON_AddStringToObject(t41g_params, "type", "object");
    cJSON_AddItemToObject(t41g_params, "properties", t41g_props);
    cJSON_AddItemToObject(t41g_fn, "parameters", t41g_params);
    cJSON_AddItemToObject(t41g, "function", t41g_fn);
    cJSON_AddItemToArray(tools, t41g);

    cJSON* t41h = cJSON_CreateObject();
    cJSON* t41h_fn = cJSON_CreateObject();
    cJSON* t41h_params = cJSON_CreateObject();
    cJSON* t41h_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41h, "type", "function");
    cJSON_AddStringToObject(t41h_fn, "name", "my_relays");
    cJSON_AddStringToObject(t41h_fn, "description", "Alias for nostr_agent_relays: return this agent's kind 10002 relay context");
    cJSON_AddStringToObject(t41h_params, "type", "object");
    cJSON_AddItemToObject(t41h_params, "properties", t41h_props);
    cJSON_AddItemToObject(t41h_fn, "parameters", t41h_params);
    cJSON_AddItemToObject(t41h, "function", t41h_fn);
    cJSON_AddItemToArray(tools, t41h);

    cJSON* t41i = cJSON_CreateObject();
    cJSON* t41i_fn = cJSON_CreateObject();
    cJSON* t41i_params = cJSON_CreateObject();
    cJSON* t41i_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t41i, "type", "function");
    cJSON_AddStringToObject(t41i_fn, "name", "my_notes");
    cJSON_AddStringToObject(t41i_fn, "description", "Alias for nostr_agent_notes: return this agent's recent kind 1 notes context");
    cJSON_AddStringToObject(t41i_params, "type", "object");
    cJSON_AddItemToObject(t41i_params, "properties", t41i_props);
    cJSON_AddItemToObject(t41i_fn, "parameters", t41i_params);
    cJSON_AddItemToObject(t41i, "function", t41i_fn);
    cJSON_AddItemToArray(tools, t41i);

    cJSON* t42 = cJSON_CreateObject();
    cJSON* t42_fn = cJSON_CreateObject();
    cJSON* t42_params = cJSON_CreateObject();
    cJSON* t42_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t42, "type", "function");
    cJSON_AddStringToObject(t42_fn, "name", "task_list");
    cJSON_AddStringToObject(t42_fn, "description", "Build current task list context block from agent task memory on Nostr");
    cJSON_AddStringToObject(t42_params, "type", "object");
    cJSON_AddItemToObject(t42_params, "properties", t42_props);
    cJSON_AddItemToObject(t42_fn, "parameters", t42_params);
    cJSON_AddItemToObject(t42, "function", t42_fn);
    cJSON_AddItemToArray(tools, t42);

    cJSON* t44 = cJSON_CreateObject();
    cJSON* t44_fn = cJSON_CreateObject();
    cJSON* t44_params = cJSON_CreateObject();
    cJSON* t44_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t44, "type", "function");
    cJSON_AddStringToObject(t44_fn, "name", "agent_identity");
    cJSON_AddStringToObject(t44_fn, "description", "Build agent identity context block with pubkey and npub");
    cJSON_AddStringToObject(t44_params, "type", "object");
    cJSON_AddItemToObject(t44_params, "properties", t44_props);
    cJSON_AddItemToObject(t44_fn, "parameters", t44_params);
    cJSON_AddItemToObject(t44, "function", t44_fn);
    cJSON_AddItemToArray(tools, t44);

    cJSON* t45 = cJSON_CreateObject();
    cJSON* t45_fn = cJSON_CreateObject();
    cJSON* t45_params = cJSON_CreateObject();
    cJSON* t45_props = cJSON_CreateObject();
    cJSON* t45_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t45, "type", "function");
    cJSON_AddStringToObject(t45_fn, "name", "task_manage");
    cJSON_AddStringToObject(t45_fn, "description", "Manage agent short-term task memory stored on Nostr kind 30078 (d=tasks): list/add/update/remove/clear/replace");
    cJSON_AddStringToObject(t45_params, "type", "object");
    cJSON_AddItemToObject(t45_params, "properties", t45_props);
    cJSON_AddItemToObject(t45_params, "required", t45_required);

    cJSON* p_task_action = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_action, "type", "string");
    cJSON* p_task_action_enum = cJSON_CreateArray();
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("list"));
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("add"));
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("update"));
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("remove"));
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("clear"));
    cJSON_AddItemToArray(p_task_action_enum, cJSON_CreateString("replace"));
    cJSON_AddItemToObject(p_task_action, "enum", p_task_action_enum);
    cJSON_AddItemToObject(t45_props, "action", p_task_action);

    cJSON* p_task_text = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_text, "type", "string");
    cJSON_AddItemToObject(t45_props, "text", p_task_text);

    cJSON* p_task_id = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_id, "type", "integer");
    cJSON_AddItemToObject(t45_props, "id", p_task_id);

    cJSON* p_task_status = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_status, "type", "string");
    cJSON* p_task_status_enum = cJSON_CreateArray();
    cJSON_AddItemToArray(p_task_status_enum, cJSON_CreateString("pending"));
    cJSON_AddItemToArray(p_task_status_enum, cJSON_CreateString("active"));
    cJSON_AddItemToArray(p_task_status_enum, cJSON_CreateString("done"));
    cJSON_AddItemToObject(p_task_status, "enum", p_task_status_enum);
    cJSON_AddItemToObject(t45_props, "status", p_task_status);

    cJSON* p_task_tasks = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_tasks, "type", "array");
    cJSON* p_task_tasks_item = cJSON_CreateObject();
    cJSON_AddStringToObject(p_task_tasks_item, "type", "string");
    cJSON_AddItemToObject(p_task_tasks, "items", p_task_tasks_item);
    cJSON_AddItemToObject(t45_props, "tasks", p_task_tasks);

    cJSON_AddItemToArray(t45_required, cJSON_CreateString("action"));

    cJSON_AddItemToObject(t45_fn, "parameters", t45_params);
    cJSON_AddItemToObject(t45, "function", t45_fn);
    cJSON_AddItemToArray(tools, t45);

    cJSON* t46 = cJSON_CreateObject();
    cJSON* t46_fn = cJSON_CreateObject();
    cJSON* t46_params = cJSON_CreateObject();
    cJSON* t46_props = cJSON_CreateObject();
    cJSON* t46_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t46, "type", "function");
    cJSON_AddStringToObject(t46_fn, "name", "memory_save");
    cJSON_AddStringToObject(t46_fn, "description", "Prepend a new entry to encrypted agent memory (kind 30078, d=memory) and truncate oldest content if needed");
    cJSON_AddStringToObject(t46_params, "type", "object");
    cJSON_AddItemToObject(t46_params, "properties", t46_props);
    cJSON_AddItemToObject(t46_params, "required", t46_required);

    cJSON* p_mem_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_mem_content, "type", "string");
    cJSON_AddItemToObject(t46_props, "content", p_mem_content);

    cJSON_AddItemToArray(t46_required, cJSON_CreateString("content"));

    cJSON_AddItemToObject(t46_fn, "parameters", t46_params);
    cJSON_AddItemToObject(t46, "function", t46_fn);
    cJSON_AddItemToArray(tools, t46);

    cJSON* t47 = cJSON_CreateObject();
    cJSON* t47_fn = cJSON_CreateObject();
    cJSON* t47_params = cJSON_CreateObject();
    cJSON* t47_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t47, "type", "function");
    cJSON_AddStringToObject(t47_fn, "name", "memory_recall");
    cJSON_AddStringToObject(t47_fn, "description", "Recall encrypted agent memory (kind 30078, d=memory)");
    cJSON_AddStringToObject(t47_params, "type", "object");
    cJSON_AddItemToObject(t47_params, "properties", t47_props);

    cJSON_AddItemToObject(t47_fn, "parameters", t47_params);
    cJSON_AddItemToObject(t47, "function", t47_fn);
    cJSON_AddItemToArray(tools, t47);

    cJSON* t48 = cJSON_CreateObject();
    cJSON* t48_fn = cJSON_CreateObject();
    cJSON* t48_params = cJSON_CreateObject();
    cJSON* t48_props = cJSON_CreateObject();
    cJSON* t48_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t48, "type", "function");
    cJSON_AddStringToObject(t48_fn, "name", "config_store");
    cJSON_AddStringToObject(t48_fn, "description", "Encrypt and publish agent config as kind 30078 for a given d_tag");
    cJSON_AddStringToObject(t48_params, "type", "object");
    cJSON_AddItemToObject(t48_params, "properties", t48_props);
    cJSON_AddItemToObject(t48_params, "required", t48_required);

    cJSON* p_cfg_store_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_cfg_store_d, "type", "string");
    cJSON_AddItemToObject(t48_props, "d_tag", p_cfg_store_d);

    cJSON* p_cfg_store_content = cJSON_CreateObject();
    cJSON_AddStringToObject(p_cfg_store_content, "description", "Arbitrary JSON value or string to encrypt and store");
    cJSON_AddItemToObject(t48_props, "content", p_cfg_store_content);

    cJSON_AddItemToArray(t48_required, cJSON_CreateString("d_tag"));
    cJSON_AddItemToArray(t48_required, cJSON_CreateString("content"));

    cJSON_AddItemToObject(t48_fn, "parameters", t48_params);
    cJSON_AddItemToObject(t48, "function", t48_fn);
    cJSON_AddItemToArray(tools, t48);

    cJSON* t49 = cJSON_CreateObject();
    cJSON* t49_fn = cJSON_CreateObject();
    cJSON* t49_params = cJSON_CreateObject();
    cJSON* t49_props = cJSON_CreateObject();
    cJSON* t49_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t49, "type", "function");
    cJSON_AddStringToObject(t49_fn, "name", "config_recall");
    cJSON_AddStringToObject(t49_fn, "description", "Fetch and decrypt agent config kind 30078 by d_tag");
    cJSON_AddStringToObject(t49_params, "type", "object");
    cJSON_AddItemToObject(t49_params, "properties", t49_props);
    cJSON_AddItemToObject(t49_params, "required", t49_required);

    cJSON* p_cfg_recall_d = cJSON_CreateObject();
    cJSON_AddStringToObject(p_cfg_recall_d, "type", "string");
    cJSON_AddItemToObject(t49_props, "d_tag", p_cfg_recall_d);

    cJSON_AddItemToArray(t49_required, cJSON_CreateString("d_tag"));

    cJSON_AddItemToObject(t49_fn, "parameters", t49_params);
    cJSON_AddItemToObject(t49, "function", t49_fn);
    cJSON_AddItemToArray(tools, t49);

    cJSON* t50 = cJSON_CreateObject();
    cJSON* t50_fn = cJSON_CreateObject();
    cJSON* t50_params = cJSON_CreateObject();
    cJSON* t50_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t50, "type", "function");
    cJSON_AddStringToObject(t50_fn, "name", "nostr_my_events");
    cJSON_AddStringToObject(t50_fn, "description", "Query recent events authored by this agent and return kind, event_id, timestamp, d_tag, and cache presence");
    cJSON_AddStringToObject(t50_params, "type", "object");
    cJSON_AddItemToObject(t50_params, "properties", t50_props);

    cJSON* p_my_events_limit = cJSON_CreateObject();
    cJSON_AddStringToObject(p_my_events_limit, "type", "integer");
    cJSON_AddStringToObject(p_my_events_limit, "description", "Maximum number of authored events to query (1-2000, default 200)");
    cJSON_AddItemToObject(t50_props, "limit", p_my_events_limit);

    cJSON* p_my_events_kind = cJSON_CreateObject();
    cJSON_AddStringToObject(p_my_events_kind, "type", "integer");
    cJSON_AddStringToObject(p_my_events_kind, "description", "Optional specific kind to query; omit for all kinds");
    cJSON_AddItemToObject(t50_props, "kind", p_my_events_kind);

    cJSON* p_my_events_timeout = cJSON_CreateObject();
    cJSON_AddStringToObject(p_my_events_timeout, "type", "integer");
    cJSON_AddStringToObject(p_my_events_timeout, "description", "Query timeout in milliseconds (1000-60000, default 8000)");
    cJSON_AddItemToObject(t50_props, "timeout_ms", p_my_events_timeout);

    cJSON_AddItemToObject(t50_fn, "parameters", t50_params);
    cJSON_AddItemToObject(t50, "function", t50_fn);
    cJSON_AddItemToArray(tools, t50);

    cJSON* t51 = cJSON_CreateObject();
    cJSON* t51_fn = cJSON_CreateObject();
    cJSON* t51_params = cJSON_CreateObject();
    cJSON* t51_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t51, "type", "function");
    cJSON_AddStringToObject(t51_fn, "name", "cashu_wallet_balance");
    cJSON_AddStringToObject(t51_fn, "description", "Return current wallet balances aggregated by mint and unit");
    cJSON_AddStringToObject(t51_params, "type", "object");
    cJSON_AddItemToObject(t51_params, "properties", t51_props);

    cJSON_AddItemToObject(t51_fn, "parameters", t51_params);
    cJSON_AddItemToObject(t51, "function", t51_fn);
    cJSON_AddItemToArray(tools, t51);

    cJSON* t52 = cJSON_CreateObject();
    cJSON* t52_fn = cJSON_CreateObject();
    cJSON* t52_params = cJSON_CreateObject();
    cJSON* t52_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t52, "type", "function");
    cJSON_AddStringToObject(t52_fn, "name", "cashu_wallet_info");
    cJSON_AddStringToObject(t52_fn, "description", "Fetch mint info for a specific mint_url or the default configured mint");
    cJSON_AddStringToObject(t52_params, "type", "object");
    cJSON_AddItemToObject(t52_params, "properties", t52_props);

    cJSON* p_wallet_info_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_info_mint, "type", "string");
    cJSON_AddStringToObject(p_wallet_info_mint, "description", "Optional mint base URL; uses configured default when omitted");
    cJSON_AddItemToObject(t52_props, "mint_url", p_wallet_info_mint);

    cJSON_AddItemToObject(t52_fn, "parameters", t52_params);
    cJSON_AddItemToObject(t52, "function", t52_fn);
    cJSON_AddItemToArray(tools, t52);

    cJSON* t53 = cJSON_CreateObject();
    cJSON* t53_fn = cJSON_CreateObject();
    cJSON* t53_params = cJSON_CreateObject();
    cJSON* t53_props = cJSON_CreateObject();
    cJSON* t53_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t53, "type", "function");
    cJSON_AddStringToObject(t53_fn, "name", "cashu_wallet_mint_quote");
    cJSON_AddStringToObject(t53_fn, "description", "Request a mint quote for a target amount");
    cJSON_AddStringToObject(t53_params, "type", "object");
    cJSON_AddItemToObject(t53_params, "properties", t53_props);
    cJSON_AddItemToObject(t53_params, "required", t53_required);

    cJSON* p_wallet_mq_amount = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mq_amount, "type", "integer");
    cJSON_AddStringToObject(p_wallet_mq_amount, "description", "Amount to mint in the selected unit");
    cJSON_AddItemToObject(t53_props, "amount", p_wallet_mq_amount);

    cJSON* p_wallet_mq_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mq_mint, "type", "string");
    cJSON_AddStringToObject(p_wallet_mq_mint, "description", "Optional mint base URL; uses configured default when omitted");
    cJSON_AddItemToObject(t53_props, "mint_url", p_wallet_mq_mint);

    cJSON* p_wallet_mq_unit = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mq_unit, "type", "string");
    cJSON_AddStringToObject(p_wallet_mq_unit, "description", "Optional unit, e.g. sat");
    cJSON_AddItemToObject(t53_props, "unit", p_wallet_mq_unit);

    cJSON_AddItemToArray(t53_required, cJSON_CreateString("amount"));

    cJSON_AddItemToObject(t53_fn, "parameters", t53_params);
    cJSON_AddItemToObject(t53, "function", t53_fn);
    cJSON_AddItemToArray(tools, t53);

    cJSON* t54 = cJSON_CreateObject();
    cJSON* t54_fn = cJSON_CreateObject();
    cJSON* t54_params = cJSON_CreateObject();
    cJSON* t54_props = cJSON_CreateObject();
    cJSON* t54_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t54, "type", "function");
    cJSON_AddStringToObject(t54_fn, "name", "cashu_wallet_mint_check");
    cJSON_AddStringToObject(t54_fn, "description", "Check a previously requested mint quote status");
    cJSON_AddStringToObject(t54_params, "type", "object");
    cJSON_AddItemToObject(t54_params, "properties", t54_props);
    cJSON_AddItemToObject(t54_params, "required", t54_required);

    cJSON* p_wallet_mc_quote = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mc_quote, "type", "string");
    cJSON_AddItemToObject(t54_props, "quote_id", p_wallet_mc_quote);

    cJSON* p_wallet_mc_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mc_mint, "type", "string");
    cJSON_AddItemToObject(t54_props, "mint_url", p_wallet_mc_mint);

    cJSON_AddItemToArray(t54_required, cJSON_CreateString("quote_id"));

    cJSON_AddItemToObject(t54_fn, "parameters", t54_params);
    cJSON_AddItemToObject(t54, "function", t54_fn);
    cJSON_AddItemToArray(tools, t54);

    cJSON* t55 = cJSON_CreateObject();
    cJSON* t55_fn = cJSON_CreateObject();
    cJSON* t55_params = cJSON_CreateObject();
    cJSON* t55_props = cJSON_CreateObject();
    cJSON* t55_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t55, "type", "function");
    cJSON_AddStringToObject(t55_fn, "name", "cashu_wallet_mint_claim");
    cJSON_AddStringToObject(t55_fn, "description", "Claim minted proofs for a paid quote_id and add them to wallet state");
    cJSON_AddStringToObject(t55_params, "type", "object");
    cJSON_AddItemToObject(t55_params, "properties", t55_props);
    cJSON_AddItemToObject(t55_params, "required", t55_required);

    cJSON* p_wallet_mclaim_quote = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mclaim_quote, "type", "string");
    cJSON_AddItemToObject(t55_props, "quote_id", p_wallet_mclaim_quote);

    cJSON* p_wallet_mclaim_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mclaim_mint, "type", "string");
    cJSON_AddItemToObject(t55_props, "mint_url", p_wallet_mclaim_mint);

    cJSON* p_wallet_mclaim_amount = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mclaim_amount, "type", "integer");
    cJSON_AddStringToObject(p_wallet_mclaim_amount, "description", "Optional target amount; if omitted wallet attempts best-effort claim");
    cJSON_AddItemToObject(t55_props, "amount", p_wallet_mclaim_amount);

    cJSON_AddItemToArray(t55_required, cJSON_CreateString("quote_id"));

    cJSON_AddItemToObject(t55_fn, "parameters", t55_params);
    cJSON_AddItemToObject(t55, "function", t55_fn);
    cJSON_AddItemToArray(tools, t55);

    cJSON* t56 = cJSON_CreateObject();
    cJSON* t56_fn = cJSON_CreateObject();
    cJSON* t56_params = cJSON_CreateObject();
    cJSON* t56_props = cJSON_CreateObject();
    cJSON* t56_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t56, "type", "function");
    cJSON_AddStringToObject(t56_fn, "name", "cashu_wallet_melt_quote");
    cJSON_AddStringToObject(t56_fn, "description", "Request a melt quote for a Lightning payment request");
    cJSON_AddStringToObject(t56_params, "type", "object");
    cJSON_AddItemToObject(t56_params, "properties", t56_props);
    cJSON_AddItemToObject(t56_params, "required", t56_required);

    cJSON* p_wallet_meq_pr = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_meq_pr, "type", "string");
    cJSON_AddItemToObject(t56_props, "payment_request", p_wallet_meq_pr);

    cJSON* p_wallet_meq_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_meq_mint, "type", "string");
    cJSON_AddItemToObject(t56_props, "mint_url", p_wallet_meq_mint);

    cJSON* p_wallet_meq_unit = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_meq_unit, "type", "string");
    cJSON_AddItemToObject(t56_props, "unit", p_wallet_meq_unit);

    cJSON_AddItemToArray(t56_required, cJSON_CreateString("payment_request"));

    cJSON_AddItemToObject(t56_fn, "parameters", t56_params);
    cJSON_AddItemToObject(t56, "function", t56_fn);
    cJSON_AddItemToArray(tools, t56);

    cJSON* t57 = cJSON_CreateObject();
    cJSON* t57_fn = cJSON_CreateObject();
    cJSON* t57_params = cJSON_CreateObject();
    cJSON* t57_props = cJSON_CreateObject();
    cJSON* t57_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t57, "type", "function");
    cJSON_AddStringToObject(t57_fn, "name", "cashu_wallet_melt_pay");
    cJSON_AddStringToObject(t57_fn, "description", "Pay a previously quoted melt by quote_id");
    cJSON_AddStringToObject(t57_params, "type", "object");
    cJSON_AddItemToObject(t57_params, "properties", t57_props);
    cJSON_AddItemToObject(t57_params, "required", t57_required);

    cJSON* p_wallet_mp_quote = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mp_quote, "type", "string");
    cJSON_AddItemToObject(t57_props, "quote_id", p_wallet_mp_quote);

    cJSON* p_wallet_mp_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_mp_mint, "type", "string");
    cJSON_AddItemToObject(t57_props, "mint_url", p_wallet_mp_mint);

    cJSON_AddItemToArray(t57_required, cJSON_CreateString("quote_id"));

    cJSON_AddItemToObject(t57_fn, "parameters", t57_params);
    cJSON_AddItemToObject(t57, "function", t57_fn);
    cJSON_AddItemToArray(tools, t57);

    cJSON* t58 = cJSON_CreateObject();
    cJSON* t58_fn = cJSON_CreateObject();
    cJSON* t58_params = cJSON_CreateObject();
    cJSON* t58_props = cJSON_CreateObject();

    cJSON_AddStringToObject(t58, "type", "function");
    cJSON_AddStringToObject(t58_fn, "name", "cashu_wallet_check_proofs");
    cJSON_AddStringToObject(t58_fn, "description", "Check current wallet proofs state against mint");
    cJSON_AddStringToObject(t58_params, "type", "object");
    cJSON_AddItemToObject(t58_params, "properties", t58_props);

    cJSON* p_wallet_cp_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_cp_mint, "type", "string");
    cJSON_AddItemToObject(t58_props, "mint_url", p_wallet_cp_mint);

    cJSON_AddItemToObject(t58_fn, "parameters", t58_params);
    cJSON_AddItemToObject(t58, "function", t58_fn);
    cJSON_AddItemToArray(tools, t58);

    cJSON* t59 = cJSON_CreateObject();
    cJSON* t59_fn = cJSON_CreateObject();
    cJSON* t59_params = cJSON_CreateObject();
    cJSON* t59_props = cJSON_CreateObject();
    cJSON* t59_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t59, "type", "function");
    cJSON_AddStringToObject(t59_fn, "name", "cashu_wallet_receive_token");
    cJSON_AddStringToObject(t59_fn, "description", "Receive an ecash token string (cashuA/cashuB), swap to fresh proofs, and store it in wallet state");
    cJSON_AddStringToObject(t59_params, "type", "object");
    cJSON_AddItemToObject(t59_params, "properties", t59_props);
    cJSON_AddItemToObject(t59_params, "required", t59_required);

    cJSON* p_wallet_rt_token = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_rt_token, "type", "string");
    cJSON_AddStringToObject(p_wallet_rt_token, "description", "Incoming token string beginning with cashuA or cashuB");
    cJSON_AddItemToObject(t59_props, "token", p_wallet_rt_token);

    cJSON* p_wallet_rt_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_rt_mint, "type", "string");
    cJSON_AddStringToObject(p_wallet_rt_mint, "description", "Optional mint URL override; when provided must match token mint");
    cJSON_AddItemToObject(t59_props, "mint_url", p_wallet_rt_mint);

    cJSON_AddItemToArray(t59_required, cJSON_CreateString("token"));

    cJSON_AddItemToObject(t59_fn, "parameters", t59_params);
    cJSON_AddItemToObject(t59, "function", t59_fn);
    cJSON_AddItemToArray(tools, t59);

    cJSON* t60 = cJSON_CreateObject();
    cJSON* t60_fn = cJSON_CreateObject();
    cJSON* t60_params = cJSON_CreateObject();
    cJSON* t60_props = cJSON_CreateObject();
    cJSON* t60_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t60, "type", "function");
    cJSON_AddStringToObject(t60_fn, "name", "cashu_wallet_send_token");
    cJSON_AddStringToObject(t60_fn, "description", "Create an outbound ecash token from wallet proofs for an exact amount");
    cJSON_AddStringToObject(t60_params, "type", "object");
    cJSON_AddItemToObject(t60_params, "properties", t60_props);
    cJSON_AddItemToObject(t60_params, "required", t60_required);

    cJSON* p_wallet_st_amount = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_st_amount, "type", "integer");
    cJSON_AddStringToObject(p_wallet_st_amount, "description", "Exact amount to send as ecash token");
    cJSON_AddItemToObject(t60_props, "amount", p_wallet_st_amount);

    cJSON* p_wallet_st_mint = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_st_mint, "type", "string");
    cJSON_AddStringToObject(p_wallet_st_mint, "description", "Optional mint URL; defaults to configured wallet mint when omitted");
    cJSON_AddItemToObject(t60_props, "mint_url", p_wallet_st_mint);

    cJSON* p_wallet_st_format = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_st_format, "type", "string");
    cJSON_AddStringToObject(p_wallet_st_format, "description", "Optional token format: cashuA or cashuB (default cashuB)");
    cJSON_AddItemToObject(t60_props, "format", p_wallet_st_format);

    cJSON_AddItemToArray(t60_required, cJSON_CreateString("amount"));

    cJSON_AddItemToObject(t60_fn, "parameters", t60_params);
    cJSON_AddItemToObject(t60, "function", t60_fn);
    cJSON_AddItemToArray(tools, t60);

    cJSON* t61 = cJSON_CreateObject();
    cJSON* t61_fn = cJSON_CreateObject();
    cJSON* t61_params = cJSON_CreateObject();
    cJSON* t61_props = cJSON_CreateObject();
    cJSON* t61_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t61, "type", "function");
    cJSON_AddStringToObject(t61_fn, "name", "cashu_wallet_mints_set");
    cJSON_AddStringToObject(t61_fn, "description", "Set wallet mints (NIP-60), public mints (NIP-61), or both");
    cJSON_AddStringToObject(t61_params, "type", "object");
    cJSON_AddItemToObject(t61_params, "properties", t61_props);
    cJSON_AddItemToObject(t61_params, "required", t61_required);

    cJSON* p_wallet_ms_target = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_ms_target, "type", "string");
    cJSON_AddStringToObject(p_wallet_ms_target, "description", "Where to apply mint updates: wallet, public, or both");
    cJSON_AddItemToObject(t61_props, "target", p_wallet_ms_target);

    cJSON* p_wallet_ms_wallet = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_ms_wallet, "type", "array");
    cJSON* p_wallet_ms_wallet_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_ms_wallet_items, "type", "string");
    cJSON_AddItemToObject(p_wallet_ms_wallet, "items", p_wallet_ms_wallet_items);
    cJSON_AddStringToObject(p_wallet_ms_wallet, "description", "Mint URLs for wallet event update");
    cJSON_AddItemToObject(t61_props, "wallet_mints", p_wallet_ms_wallet);

    cJSON* p_wallet_ms_public = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_ms_public, "type", "array");
    cJSON* p_wallet_ms_public_items = cJSON_CreateObject();
    cJSON_AddStringToObject(p_wallet_ms_public_items, "type", "string");
    cJSON_AddItemToObject(p_wallet_ms_public, "items", p_wallet_ms_public_items);
    cJSON_AddStringToObject(p_wallet_ms_public, "description", "Mint URLs for public nutzap info update");
    cJSON_AddItemToObject(t61_props, "public_mints", p_wallet_ms_public);

    cJSON_AddItemToArray(t61_required, cJSON_CreateString("target"));

    cJSON_AddItemToObject(t61_fn, "parameters", t61_params);
    cJSON_AddItemToObject(t61, "function", t61_fn);
    cJSON_AddItemToArray(tools, t61);

    cJSON* t62 = cJSON_CreateObject();
    cJSON* t62_fn = cJSON_CreateObject();
    cJSON* t62_params = cJSON_CreateObject();
    cJSON* t62_props = cJSON_CreateObject();
    cJSON* t62_required = cJSON_CreateArray();

    cJSON_AddStringToObject(t62, "type", "function");
    cJSON_AddStringToObject(t62_fn, "name", "cashu_wallet_mints_get");
    cJSON_AddStringToObject(t62_fn, "description", "Get currently configured wallet and public mints");
    cJSON_AddStringToObject(t62_params, "type", "object");
    cJSON_AddItemToObject(t62_params, "properties", t62_props);
    cJSON_AddItemToObject(t62_params, "required", t62_required);

    cJSON_AddItemToObject(t62_fn, "parameters", t62_params);
    cJSON_AddItemToObject(t62, "function", t62_fn);
    cJSON_AddItemToArray(tools, t62);

    cJSON* t63 = cJSON_CreateObject();
    cJSON* t63_fn = cJSON_CreateObject();
    cJSON* t63_params = cJSON_CreateObject();
    cJSON* t63_props = cJSON_CreateObject();
    cJSON* t63_required = cJSON_CreateArray();
    cJSON_AddStringToObject(t63, "type", "function");
    cJSON_AddStringToObject(t63_fn, "name", "blossom_upload");
    cJSON_AddStringToObject(t63_fn, "description", "Upload a local file to a Blossom server");
    cJSON_AddStringToObject(t63_params, "type", "object");
    cJSON_AddItemToObject(t63_params, "properties", t63_props);
    cJSON_AddItemToObject(t63_params, "required", t63_required);
    cJSON* p63_server = cJSON_CreateObject(); cJSON_AddStringToObject(p63_server, "type", "string"); cJSON_AddItemToObject(t63_props, "server", p63_server);
    cJSON* p63_file = cJSON_CreateObject(); cJSON_AddStringToObject(p63_file, "type", "string"); cJSON_AddItemToObject(t63_props, "file_path", p63_file);
    cJSON* p63_ct = cJSON_CreateObject(); cJSON_AddStringToObject(p63_ct, "type", "string"); cJSON_AddItemToObject(t63_props, "content_type", p63_ct);
    cJSON_AddItemToArray(t63_required, cJSON_CreateString("server"));
    cJSON_AddItemToArray(t63_required, cJSON_CreateString("file_path"));
    cJSON_AddItemToObject(t63_fn, "parameters", t63_params);
    cJSON_AddItemToObject(t63, "function", t63_fn);
    cJSON_AddItemToArray(tools, t63);

    cJSON* t64 = cJSON_CreateObject();
    cJSON* t64_fn = cJSON_CreateObject();
    cJSON* t64_params = cJSON_CreateObject();
    cJSON* t64_props = cJSON_CreateObject();
    cJSON* t64_required = cJSON_CreateArray();
    cJSON_AddStringToObject(t64, "type", "function");
    cJSON_AddStringToObject(t64_fn, "name", "blossom_download");
    cJSON_AddStringToObject(t64_fn, "description", "Download a blob from Blossom to a local file");
    cJSON_AddStringToObject(t64_params, "type", "object");
    cJSON_AddItemToObject(t64_params, "properties", t64_props);
    cJSON_AddItemToObject(t64_params, "required", t64_required);
    cJSON* p64_server = cJSON_CreateObject(); cJSON_AddStringToObject(p64_server, "type", "string"); cJSON_AddItemToObject(t64_props, "server", p64_server);
    cJSON* p64_sha = cJSON_CreateObject(); cJSON_AddStringToObject(p64_sha, "type", "string"); cJSON_AddItemToObject(t64_props, "sha256", p64_sha);
    cJSON* p64_out = cJSON_CreateObject(); cJSON_AddStringToObject(p64_out, "type", "string"); cJSON_AddItemToObject(t64_props, "output_path", p64_out);
    cJSON* p64_overwrite = cJSON_CreateObject(); cJSON_AddStringToObject(p64_overwrite, "type", "boolean"); cJSON_AddItemToObject(t64_props, "overwrite", p64_overwrite);
    cJSON_AddItemToArray(t64_required, cJSON_CreateString("server"));
    cJSON_AddItemToArray(t64_required, cJSON_CreateString("sha256"));
    cJSON_AddItemToArray(t64_required, cJSON_CreateString("output_path"));
    cJSON_AddItemToObject(t64_fn, "parameters", t64_params);
    cJSON_AddItemToObject(t64, "function", t64_fn);
    cJSON_AddItemToArray(tools, t64);

    cJSON* t65 = cJSON_CreateObject();
    cJSON* t65_fn = cJSON_CreateObject();
    cJSON* t65_params = cJSON_CreateObject();
    cJSON* t65_props = cJSON_CreateObject();
    cJSON* t65_required = cJSON_CreateArray();
    cJSON_AddStringToObject(t65, "type", "function");
    cJSON_AddStringToObject(t65_fn, "name", "blossom_head");
    cJSON_AddStringToObject(t65_fn, "description", "Fetch blob metadata from Blossom");
    cJSON_AddStringToObject(t65_params, "type", "object");
    cJSON_AddItemToObject(t65_params, "properties", t65_props);
    cJSON_AddItemToObject(t65_params, "required", t65_required);
    cJSON* p65_server = cJSON_CreateObject(); cJSON_AddStringToObject(p65_server, "type", "string"); cJSON_AddItemToObject(t65_props, "server", p65_server);
    cJSON* p65_sha = cJSON_CreateObject(); cJSON_AddStringToObject(p65_sha, "type", "string"); cJSON_AddItemToObject(t65_props, "sha256", p65_sha);
    cJSON_AddItemToArray(t65_required, cJSON_CreateString("server"));
    cJSON_AddItemToArray(t65_required, cJSON_CreateString("sha256"));
    cJSON_AddItemToObject(t65_fn, "parameters", t65_params);
    cJSON_AddItemToObject(t65, "function", t65_fn);
    cJSON_AddItemToArray(tools, t65);

    cJSON* t66 = cJSON_CreateObject();
    cJSON* t66_fn = cJSON_CreateObject();
    cJSON* t66_params = cJSON_CreateObject();
    cJSON* t66_props = cJSON_CreateObject();
    cJSON* t66_required = cJSON_CreateArray();
    cJSON_AddStringToObject(t66, "type", "function");
    cJSON_AddStringToObject(t66_fn, "name", "blossom_delete");
    cJSON_AddStringToObject(t66_fn, "description", "Delete a blob from Blossom");
    cJSON_AddStringToObject(t66_params, "type", "object");
    cJSON_AddItemToObject(t66_params, "properties", t66_props);
    cJSON_AddItemToObject(t66_params, "required", t66_required);
    cJSON* p66_server = cJSON_CreateObject(); cJSON_AddStringToObject(p66_server, "type", "string"); cJSON_AddItemToObject(t66_props, "server", p66_server);
    cJSON* p66_sha = cJSON_CreateObject(); cJSON_AddStringToObject(p66_sha, "type", "string"); cJSON_AddItemToObject(t66_props, "sha256", p66_sha);
    cJSON_AddItemToArray(t66_required, cJSON_CreateString("server"));
    cJSON_AddItemToArray(t66_required, cJSON_CreateString("sha256"));
    cJSON_AddItemToObject(t66_fn, "parameters", t66_params);
    cJSON_AddItemToObject(t66, "function", t66_fn);
    cJSON_AddItemToArray(tools, t66);

    cJSON* t67 = cJSON_CreateObject();
    cJSON* t67_fn = cJSON_CreateObject();
    cJSON* t67_params = cJSON_CreateObject();
    cJSON* t67_props = cJSON_CreateObject();
    cJSON* t67_required = cJSON_CreateArray();
    cJSON_AddStringToObject(t67, "type", "function");
    cJSON_AddStringToObject(t67_fn, "name", "blossom_list");
    cJSON_AddStringToObject(t67_fn, "description", "List blobs for a pubkey on Blossom");
    cJSON_AddStringToObject(t67_params, "type", "object");
    cJSON_AddItemToObject(t67_params, "properties", t67_props);
    cJSON_AddItemToObject(t67_params, "required", t67_required);
    cJSON* p67_server = cJSON_CreateObject(); cJSON_AddStringToObject(p67_server, "type", "string"); cJSON_AddItemToObject(t67_props, "server", p67_server);
    cJSON* p67_pubkey = cJSON_CreateObject(); cJSON_AddStringToObject(p67_pubkey, "type", "string"); cJSON_AddItemToObject(t67_props, "pubkey", p67_pubkey);
    cJSON_AddItemToArray(t67_required, cJSON_CreateString("server"));
    cJSON_AddItemToObject(t67_fn, "parameters", t67_params);
    cJSON_AddItemToObject(t67, "function", t67_fn);
    cJSON_AddItemToArray(tools, t67);

    char* out = cJSON_PrintUnformatted(tools);
    cJSON_Delete(tools);
    return out;
}

char* tools_build_openai_schema_json(const tools_context_t* ctx) {
    return tools_build_openai_schema_json_legacy(ctx);
}
