Files
didactyl/plans/example_context_v2.md

382 lines
10 KiB
Markdown

# Example Context Window v2 — Refined Design
This revision addresses two refinements:
1. Tools stay JSON; template engine has markdown formatters
2. Runtime owns h1; skill headings get bumped down one level
---
## The Skills (as authored)
### identity skill (layer 2, no trigger)
```markdown
You are {{agent_profile}}, a sovereign AI agent living on Nostr.
- **npub**: {{agent_npub}}
- **NIP-05**: simon@nostr
> Not your keys, not your agent.
```
Note: No heading. This skill is designed to be embedded (layer 2).
`{{agent_profile}}` and `{{agent_npub}}` are template variables resolved
by the formatter registry.
### personality skill (layer 1, trigger: dm)
```markdown
system:
# {{identity}}
## Personality
You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.
## Rules
- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone
```
### chat skill (layer 1, trigger: dm)
```markdown
system:
# Chat
Respond helpfully to the admin.
Use tools when a request requires taking action.
user:
{{message}}
```
---
## Template Resolution (before heading bump)
After resolving `{{identity}}`, `{{agent_profile}}`, `{{agent_npub}}`,
`{{message}}`, and `{{dm_history}}`:
### personality skill (resolved)
```markdown
system:
# You are Simon, a sovereign AI agent living on Nostr.
- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr
> Not your keys, not your agent.
## Personality
You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.
## Rules
- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone
```
### chat skill (resolved)
```markdown
system:
# Chat
Respond helpfully to the admin.
Use tools when a request requires taking action.
user:
Hey Simon, who mentioned me on Nostr today?
```
---
## Runtime Assembly
The runtime:
1. Collects triggered skills in adoption-list order
2. Bumps all headings in each skill down one level (# -> ##, ## -> ###)
3. Adds a runtime-level `# title` from the agent identity
4. Splits on role markers (system: / user:)
5. Concatenates same-role sections with --- separators
### The assembled document (what gets logged)
```markdown
system:
# Simon — Didactyl Agent
## You are Simon, a sovereign AI agent living on Nostr.
- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr
> Not your keys, not your agent.
### Personality
You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.
### Rules
- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone
---
## Chat
Respond helpfully to the admin.
Use tools when a request requires taking action.
user:
Hey Simon, who mentioned me on Nostr today?
```
---
## Wait — Problem with the heading bump
Looking at this output, I notice the heading bump creates an awkward result.
The identity content has no heading, but the personality skill wraps it with
`# {{identity}}` which becomes `## You are Simon...` after the bump. That
reads oddly as a heading.
### Better approach: identity as prose, not heading
The identity skill should be **prose content**, not wrapped in a heading by
the personality skill. The runtime adds the `# title` and the identity
content flows as the opening paragraph:
### personality skill (revised)
```markdown
system:
{{identity}}
# Personality
You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.
# Rules
- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
...
```
### Assembled document (revised, cleaner)
```markdown
system:
# Simon — Didactyl Agent
You are Simon, a sovereign AI agent living on Nostr.
- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr
> Not your keys, not your agent.
## Personality
You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.
## Rules
- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone
---
## Chat
Respond helpfully to the admin.
Use tools when a request requires taking action.
user:
Hey Simon, who mentioned me on Nostr today?
```
This reads like a proper document. The runtime adds `# Simon — Didactyl Agent`
as the document title. Identity content flows as the opening section. Each
skill's `#` headings get bumped to `##`. The `---` separates skills.
---
## Formatter Registry
The template engine uses formatters to convert tool JSON output to markdown
for context injection. Here are the formatters needed:
| Template Variable | Tool Called | Formatter | Output |
|---|---|---|---|
| `{{agent_identity}}` | `agent_identity` | `format_agent_identity` | Prose with npub in backticks |
| `{{agent_profile}}` | `nostr_agent_profile` | `format_agent_profile` | Name extracted from kind 0 JSON |
| `{{admin_profile}}` | `nostr_admin_profile` | `format_admin_profile` | Name and about from kind 0 |
| `{{admin_notes}}` | `nostr_admin_notes` | `format_admin_notes` | Markdown list of recent notes |
| `{{admin_relays}}` | `nostr_admin_relays` | `format_admin_relays` | Markdown list of relay URLs |
| `{{dm_history}}` | built-in | `format_dm_history` | Markdown conversation list |
| `{{triggering_event}}` | `trigger_event` | `format_trigger_event` | Code block with JSON |
### Example formatter: agent_identity
Input (from tool):
```json
{"pubkey":"abc123...","npub":"npub1kfc89..."}
```
Output (markdown):
```markdown
- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
```
### Example formatter: dm_history
Input (from DM history system):
```json
[
{"role":"assistant","content":"Didactyl has started up...","created_at":1774263529},
{"role":"user","content":"Good morning","created_at":1774263548},
{"role":"assistant","content":"Good morning! How can I help?","created_at":1774263551}
]
```
Output (markdown):
```markdown
## Conversation History
- **You**: Didactyl has started up and is online at 2026-03-23 09:22:48.
- **Admin**: Good morning
- **You**: Good morning! How can I help?
```
### Example formatter: triggering_event
Input (from tool):
```json
{"type":"cron","filter":"0 12 * * *","created_at":1742641200}
```
Output (markdown):
````markdown
Triggering event:
```json
{"type":"cron","filter":"0 12 * * *","created_at":1742641200}
```
````
---
## Heading Bump Implementation
Simple string operation on each line of skill content:
```c
// For each line in skill content:
if (line starts with '#') {
output '#' + line; // prepend one more #
} else {
output line;
}
```
Layer 1 skills: bump once (# -> ##)
Layer 2 skills: bump twice (# -> ###) because they are embedded inside
a layer 1 skill that already got bumped once, plus one more for being layer 2.
Actually, layer 2 skills get bumped once during their own resolution, and then
the containing layer 1 skill gets bumped once — so the layer 2 content
effectively gets bumped twice. This happens naturally if we bump during
template resolution.
Wait — that depends on ordering. If we:
1. Resolve {{identity}} first (inserting identity content into personality)
2. Then bump personality's headings
Then identity headings get bumped once (same as personality). That's correct
because identity content is now PART of personality.
If we:
1. Bump identity headings first
2. Then resolve {{identity}} into personality
3. Then bump personality's headings
Then identity headings get bumped twice. That's too much.
**Correct order: resolve templates first, then bump headings.**
This means layer 2 content gets the same heading level as the layer 1 skill
it's embedded in. If the skill author wants layer 2 content at a deeper
level, they wrap it in a heading in the layer 1 skill:
```markdown
## Identity
{{identity}}
## Personality
...
```
This is the simplest and most predictable behavior.
---
## Summary of Design Decisions
1. **Tools stay JSON** — No duplication. One tool, one output format.
2. **Formatter registry** — Template engine converts tool JSON to markdown
during `{{variable}}` resolution. Small, focused functions.
3. **Runtime owns h1** — Adds `# Agent Name` as document title.
4. **Heading bump** — All skill headings bumped one level (# -> ##).
5. **Resolve then bump** — Template variables resolved first, then heading
bump applied to the complete skill content.
6. **Skills separated by ---** — Horizontal rules between layer 1 skills.
7. **Role markers parsed** — `system:` / `user:` at line start split content
into API message roles. Unmarked content defaults to system.
8. **Context log shows markdown** — The assembled document is logged as
readable markdown, not raw JSON.