Add text features: trusted triggers, context cache, response policy, MCP config tools

This commit is contained in:
Fisto
2026-09-11 15:31:23 +02:00
parent 23a1a8e593
commit 82f78bb2b4
20 changed files with 841 additions and 88 deletions
+67 -20
View File
@@ -1,30 +1,32 @@
# Communication
This document describes the trigger rules, the trust model, the commands, and the trigger log.
This document describes the trigger rules, the trust model, the commands, the trigger log, the
context cache, and the response policy.
## Trigger rules
A message is a trigger when one of these conditions is true:
A message is a trigger when both conditions are true:
- The message is a direct message to the puppet. A direct message is a one-to-one DM, not a group.
- The message mentions the puppet. This applies in guild channels and group DMs.
- The author is trusted. The owner counts as trusted.
- One of these conditions is true:
- The message is a one-to-one DM to the puppet.
- The message mentions the puppet in a guild channel or a group DM.
All other messages are ignored.
All other messages are ignored. Untrusted messages do not enter the log at this time. The daemon
ignores bots and its own messages.
## Trust model
The puppet has one owner and a trust list.
- The owner is always trusted. The default owner is `177117296140091393` (zzib).
- The trust list holds additional user IDs.
- A trusted user gets the 100-entry log. An untrusted user gets the 30-entry log.
The owner controls the trust list. Commands from other users do not change the list.
- The trust list holds more user IDs.
- The owner controls the trust list. Commands from other users do not change the list.
## Commands
The owner sends commands from Discord. In a direct message, the text is the command. In a guild or
a group DM, mention the puppet first.
The owner sends commands from Discord. In a DM, the text is the command. In a guild or a group DM,
mention the puppet first.
| Command | Effect |
| --- | --- |
@@ -36,7 +38,23 @@ Notes:
- The owner cannot be removed.
- The command accepts mentions and raw user IDs.
- The daemon replies with a confirmation. The reply uses the same pacing as all other sends.
- The reply follows the response policy.
## Response policy
The policy decides where a reply goes. Sensitive replies go by DM.
| Setting | Meaning | Default |
| --- | --- | --- |
| `defaultMode` | The mode for normal replies: `channel` or `dm` | `channel` |
| `sensitiveCommands` | Commands that always reply by DM | `whitelist`, `config` |
| `overrides` | A per-command mode | empty |
Rules:
- An override wins over the sensitive list. The sensitive list wins over the default mode.
- A DM reply failure does not fall back to the origin channel. The daemon logs the error only.
- Read the policy with `get_puppet_config`. Change it with `set_puppet_config`.
## Trigger log
@@ -45,7 +63,7 @@ The log has two ring buffers.
| Buffer | Limit | Content |
| --- | --- | --- |
| Trusted | 100 entries | Triggers from the owner and trusted users |
| Untrusted | 30 entries | Triggers from all other users |
| Untrusted | 30 entries | Reserved. No triggers enter this buffer at this time. |
One entry holds these fields:
@@ -59,28 +77,57 @@ One entry holds these fields:
| `content` | The raw message content |
| `timestamp` | The message timestamp |
| `trusted` | True for a trusted author |
| `command` | The parsed command text, when the message is a command |
| `command` | The parsed command text, when the message looks like a command |
| `context` | Prior messages. Present on mention triggers. |
## Context
The daemon collects prior messages for a mention trigger. Direct messages do not need context.
- Message limit: `contextMessages`, default 15.
- Character limit: `contextChars`, default 4000.
- The lower limit stops the collection.
- The content is the message text and the attachment file names. Media bodies stay on Discord.
- The trigger message is not part of its own context.
The cache makes the fetch small.
1. The daemon reads the newest cached message ID for the channel.
2. It fetches messages after that ID. On the first run, it fetches the newest messages.
3. It merges the new messages into the cache.
4. It assembles the context from the merged list.
Cache settings:
| Setting | Default |
| --- | --- |
| `VESKSLOP_CACHE_DIR` | `<tmp>/veskslop-cache` |
| `VESKSLOP_CACHE_MAX_BYTES` | 50 MiB |
| Messages per channel | 200 |
Eviction removes the least recently written channel files until the folder fits the size limit.
## Event flow
1. The client receives a `MESSAGE_CREATE` gateway event.
2. The core renderer normalizes the event.
2. The core normalizes the event.
3. The core bridge pushes the event to the daemon.
4. The daemon applies the trigger rules.
5. The daemon adds a qualifying message to the log.
6. The daemon runs a trusted command, when the message is a command.
5. The daemon collects context for a mention trigger.
6. The daemon adds the entry to the log.
7. The daemon runs a trusted command and replies through the response policy.
## State file
The daemon stores the owner ID and the trust list in JSON.
The daemon stores the owner ID, the trust list, and the config in JSON.
- Default path: `poc/.veskslop-state.json`.
- Override: `VESKSLOP_STATE_FILE`.
- The trigger log is in memory only. The log resets at restart.
## How to add a trigger rule
## How to add a trigger rule or a command
1. Add the rule in `poc/src/puppet.ts`, in `handleEvent`.
2. Keep the rule small and testable.
3. Add a unit test in `poc/src/test-communication.ts` when the rule is pure logic.
4. Run `pnpm test:comm`.
4. Run `pnpm test:comm` and `pnpm test:cache`.