247 lines
8.7 KiB
Markdown
247 lines
8.7 KiB
Markdown
# DM History Context Cleanup, Skill Rename & Startup Events Unification
|
|
|
|
## Problems
|
|
|
|
### 1. DM History as JSON in System Prompt
|
|
The `{{nostr_dm_history}}` template variable resolves to a raw JSON array string pasted into the system prompt. The LLM receives conversation history as JSON-within-text, wasting tokens and forcing it to parse structured data embedded in prose.
|
|
|
|
### 2. Misleading Skill Name
|
|
The skill `default_admin_dm` is really an identity and rules skill. Rename to `identity_and_rules`.
|
|
|
|
### 3. `default_skill` Config Section Is Redundant
|
|
The `default_skill` section in genesis.jsonc is a special-case config path that converts a skill into a startup event and auto-adopts it. This is unnecessary — skills should just be startup events like everything else. The program should treat all startup events equally and halt if any fail to publish.
|
|
|
|
## Solution
|
|
|
|
Three coordinated changes:
|
|
|
|
### Part A: DM History Text Format
|
|
Add a `format` parameter to the `nostr_dm_history` tool. Create a separate `dm_history` skill.
|
|
|
|
### Part B: Skill Rename
|
|
Rename `default_admin_dm` → `identity_and_rules` everywhere.
|
|
|
|
### Part C: Eliminate `default_skill` Config Section
|
|
Move skills into `startup_events`. Auto-adopt kind 31123/31124 startup events. Make startup event publishing mandatory (halt on failure).
|
|
|
|
---
|
|
|
|
## Implementation Steps
|
|
|
|
### Part A: DM History Text Format
|
|
|
|
#### A1. Add `format` parameter to `execute_nostr_dm_history()`
|
|
|
|
**File:** `src/tools/tool_agent.c` — line 265
|
|
|
|
Add a `format` parameter: `"json"` (default, current behavior) or `"text"`.
|
|
|
|
When `format` is `"text"`, after the filtering loop (lines 320-360), iterate the filtered array and build plain text:
|
|
|
|
```
|
|
User: Good morning
|
|
Assistant: Good morning! ☀️ How can I help you today?
|
|
User: What is the capital of England?
|
|
Assistant: London! 🇬🇧
|
|
```
|
|
|
|
Existing `include_current=false` default already deduplicates the current live message (line 339).
|
|
|
|
#### A2. Add `format` to the tool schema
|
|
|
|
**File:** `src/tools/tools_schema.c` — around line 1493
|
|
|
|
Add `format` property with description. Update tool description to mention the parameter.
|
|
|
|
---
|
|
|
|
### Part B: Skill Rename
|
|
|
|
#### B1. Update `src/default_events.h`
|
|
|
|
- `DIDACTYL_DEFAULT_SKILL_D_TAG`: `"default_admin_dm"` → `"identity_and_rules"`
|
|
- `DIDACTYL_DEFAULT_SKILL_TAGS_JSON`: update d-tag and description
|
|
- `DIDACTYL_DEFAULT_SKILL_TEMPLATE`: keep as-is (already clean, no `{{nostr_dm_history}}`)
|
|
|
|
#### B2. Update tool description examples in `src/tools/tools_schema.c`
|
|
|
|
- Line 854: `skill_get` example
|
|
- Line 883: `skill_view` example
|
|
- Line 911: `skill_set` example
|
|
|
|
#### B3. Update `docs/GENESIS.md`
|
|
|
|
- Line 33 and 124: `default_admin_dm` → `identity_and_rules`
|
|
|
|
---
|
|
|
|
### Part C: Eliminate `default_skill` Config Section
|
|
|
|
#### C1. Auto-adopt kind 31123/31124 startup events
|
|
|
|
**File:** `src/config.c`
|
|
|
|
Replace `config_ensure_default_skill_startup_events()` with a new function `config_ensure_startup_skill_adoption()` that:
|
|
|
|
1. Scans all startup events for kind 31123 and 31124
|
|
2. For each skill found, extracts its `d_tag` from tags
|
|
3. Builds the skill address (`kind:pubkey:d_tag`)
|
|
4. Ensures a kind 10123 adoption list startup event exists with all skill addresses
|
|
5. If no 10123 event exists, creates one
|
|
|
|
This replaces the single-skill logic with a generic "adopt all startup skills" approach.
|
|
|
|
#### C2. Remove `default_skill` config parsing
|
|
|
|
**File:** `src/config.c`
|
|
|
|
- Remove `parse_default_skill_config()` function (lines 733-816)
|
|
- Remove the call at line 1369
|
|
- Keep backward compatibility: if `default_skill` section exists in genesis.jsonc, convert it to a startup event during parsing (migration path) — OR just remove support and let users update their genesis.jsonc
|
|
|
|
#### C3. Remove `default_skill_config_t` from config struct
|
|
|
|
**File:** `src/config.h`
|
|
|
|
- Remove `default_skill_config_t` typedef (lines 67-72)
|
|
- Remove `default_skill` field from `didactyl_config_t` (line 134)
|
|
|
|
#### C4. Update `src/main.c`
|
|
|
|
- Line 1060: Replace `config_ensure_default_skill_startup_events()` call with `config_ensure_startup_skill_adoption()`
|
|
|
|
#### C5. Make startup event publishing mandatory
|
|
|
|
**File:** `src/nostr_handler.c`
|
|
|
|
In the startup publish flow (around line 3150), after all relays have been tried:
|
|
- Check that each startup event was published to at least one relay
|
|
- If any event failed on all relays, log an error and return failure
|
|
- The caller in `main.c` should halt on this failure
|
|
|
|
#### C6. Update setup wizard
|
|
|
|
**File:** `src/setup_wizard.c`
|
|
|
|
- `configure_default_skill_for_agent()` (line 498): Instead of populating `cfg->default_skill`, append the identity skill as a startup event directly
|
|
- Add the `dm_history` skill as a second startup event
|
|
- The auto-adoption logic (C1) handles the adoption list
|
|
|
|
#### C7. Update `default_events.h`
|
|
|
|
Add the `dm_history` skill template:
|
|
|
|
```c
|
|
#define DIDACTYL_DEFAULT_DM_HISTORY_SKILL_D_TAG "dm_history"
|
|
|
|
static const char* DIDACTYL_DEFAULT_DM_HISTORY_SKILL_TEMPLATE =
|
|
"## Recent Conversation\n\n"
|
|
"{{nostr_dm_history({\"format\":\"text\",\"limit\":12})}}";
|
|
```
|
|
|
|
---
|
|
|
|
### Part D: Genesis Config Updates
|
|
|
|
#### D1. Update `genesis.jsonc.example`
|
|
|
|
Remove `default_skill` section. Add skills as startup events:
|
|
|
|
```jsonc
|
|
"startup_events": [
|
|
{
|
|
"kind": 0,
|
|
"content_fields": {
|
|
"name": "Didactyl",
|
|
"about": "I am a Didactyl agent living on Nostr"
|
|
},
|
|
"tags": []
|
|
},
|
|
{
|
|
"kind": 3,
|
|
"content": "",
|
|
"tags": [["p", "ADMIN_HEX_PUBKEY"]]
|
|
},
|
|
{
|
|
"kind": 10002,
|
|
"content": "",
|
|
"tags": [
|
|
["r", "wss://relay.damus.io"],
|
|
["r", "wss://relay.primal.net"]
|
|
]
|
|
},
|
|
{
|
|
"kind": 31124,
|
|
"content": "# Didactyl Agent\n\nYou are {{my_kind0_profile}}\n\nYour npub: {{my_npub}}\n\n## Rules\n\n- Communicate through encrypted Nostr direct messages\n- Keep responses concise and clear\n- Be helpful and technically accurate\n- If unsure, state uncertainty directly\n- Use tools when a request requires taking action\n- After a tool call, base your answer on the actual tool result\n- Never claim a tool was run if no tool was executed\n- Maintain your task list as short-term working memory\n- Never reveal your private key (nsec)\n- You may share your public key (npub) with anyone",
|
|
"tags": [
|
|
["d", "identity_and_rules"],
|
|
["app", "didactyl"],
|
|
["scope", "private"],
|
|
["description", "Agent identity and behavioral rules"],
|
|
["trigger", "dm"],
|
|
["filter", "{\"from\":\"admin\"}"]
|
|
]
|
|
},
|
|
{
|
|
"kind": 31124,
|
|
"content": "## Recent Conversation\n\n{{nostr_dm_history({\"format\":\"text\",\"limit\":12})}}",
|
|
"tags": [
|
|
["d", "dm_history"],
|
|
["app", "didactyl"],
|
|
["scope", "private"],
|
|
["description", "DM conversation history for context continuity"],
|
|
["trigger", "dm"],
|
|
["filter", "{\"from\":\"admin\"}"]
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
#### D2. Update live `genesis.jsonc`
|
|
|
|
Same changes as D1 but for the actual deployment config.
|
|
|
|
---
|
|
|
|
## Result
|
|
|
|
### Before
|
|
|
|
```json
|
|
[
|
|
{"role": "system", "content": "You are {...}\n\nYour npub: npub1...\n\n## Rules\n...\n[{\"role\":\"user\",\"content\":\"Good morning\",...}]"},
|
|
{"role": "user", "content": "And Fiji?"}
|
|
]
|
|
```
|
|
|
|
### After
|
|
|
|
```json
|
|
[
|
|
{"role": "system", "content": "# Didactyl Agent\n\nYou are {...}\n\nYour npub: npub1...\n\n## Rules\n...\n\n---\n\n## Recent Conversation\n\nUser: Good morning\nAssistant: Good morning! ☀️ How can I help you today?\nUser: What is the capital of England?\nAssistant: London! 🇬🇧\nUser: How about France?\nAssistant: Paris! 🇫🇷"},
|
|
{"role": "user", "content": "And Fiji?"}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## Files Changed
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `src/tools/tool_agent.c` | Add `format` parameter to `execute_nostr_dm_history()` |
|
|
| `src/tools/tools_schema.c` | Add `format` to schema; update example d-tags |
|
|
| `src/default_events.h` | Rename d-tag; add `dm_history` skill template |
|
|
| `src/config.h` | Remove `default_skill_config_t` and field |
|
|
| `src/config.c` | Remove `parse_default_skill_config()`; replace `config_ensure_default_skill_startup_events()` with `config_ensure_startup_skill_adoption()` |
|
|
| `src/main.c` | Update call to new adoption function |
|
|
| `src/nostr_handler.c` | Make startup event publishing mandatory (halt on total failure) |
|
|
| `src/setup_wizard.c` | Put skills in startup_events; add dm_history |
|
|
| `genesis.jsonc.example` | Remove `default_skill`; add skills as startup events |
|
|
| `genesis.jsonc` | Same as example |
|
|
| `docs/GENESIS.md` | Update references |
|
|
|
|
## Migration Note
|
|
|
|
For backward compatibility, consider keeping `parse_default_skill_config()` as a migration shim that converts `default_skill` into a startup event with a deprecation warning. This way existing genesis.jsonc files with `default_skill` still work but users are prompted to update.
|