brain backup 2026-09-14
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import { mkdtemp, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { encodeAttributes, decodeAttributes } from '../src/crdt.js';
|
||||
import { buildHermesPrompt } from '../src/hermes.js';
|
||||
import { createReplyMutation } from '../src/mutations.js';
|
||||
import { processNodeUpdate, type NodeCache } from '../src/processor.js';
|
||||
import { StateStore } from '../src/state.js';
|
||||
import type { BlockLeaf, MessageAttributes, SyncNodeUpdateData } from '../src/types.js';
|
||||
|
||||
const botUserId = 'bot-user';
|
||||
|
||||
test('mention extraction gates replies and ignores non-mentioned messages', async () => {
|
||||
const env = await setupProcessor();
|
||||
await processNodeUpdate({
|
||||
...env,
|
||||
update: makeUpdate('msg1', 'human', messageAttrs('msg1', 'parent', [{ type: 'text', text: 'hello' }]))
|
||||
});
|
||||
assert.equal(env.created.length, 0);
|
||||
});
|
||||
|
||||
test('mentioned messages invoke Hermes and dedupe by source message id', async () => {
|
||||
const env = await setupProcessor();
|
||||
const update = makeUpdate('msg2', 'human', messageAttrs('msg2', 'parent', [
|
||||
{ type: 'mention', text: '@bot', attrs: { id: 'm1', target: botUserId } },
|
||||
{ type: 'text', text: ' please summarize this' }
|
||||
]));
|
||||
await processNodeUpdate({ ...env, update });
|
||||
await processNodeUpdate({ ...env, update });
|
||||
assert.equal(env.prompts.length, 1);
|
||||
assert.equal(env.created.length, 1);
|
||||
});
|
||||
|
||||
test('messages created by the bot are ignored even when they mention the bot', async () => {
|
||||
const env = await setupProcessor();
|
||||
await processNodeUpdate({
|
||||
...env,
|
||||
update: makeUpdate('msg3', botUserId, messageAttrs('msg3', 'parent', [
|
||||
{ type: 'mention', attrs: { id: 'm1', target: botUserId } }
|
||||
]))
|
||||
});
|
||||
assert.equal(env.created.length, 0);
|
||||
});
|
||||
|
||||
test('prompt includes safety instruction, mentioned message, and parent context', () => {
|
||||
const prompt = buildHermesPrompt({ messageText: 'Can you help?', parentText: 'Family logistics thread' });
|
||||
assert.match(prompt, /Colanode family message/);
|
||||
assert.match(prompt, /Do not reveal secrets/);
|
||||
assert.match(prompt, /Can you help\?/);
|
||||
assert.match(prompt, /Family logistics thread/);
|
||||
});
|
||||
|
||||
test('reply mutation encodes a decodable Colanode message attributes document', () => {
|
||||
const { mutation, nodeId } = createReplyMutation('parent-id', 'A helpful reply.', new Date('2026-01-01T00:00:00.000Z'));
|
||||
const data = mutationData(mutation).data;
|
||||
const attrs = decodeAttributes<MessageAttributes>(data);
|
||||
assert.equal(attrs.type, 'message');
|
||||
assert.equal(attrs.subtype, 'standard');
|
||||
assert.equal(attrs.name, 'Reyna Family Bot');
|
||||
assert.equal(attrs.parentId, 'parent-id');
|
||||
assert.equal(Object.values(attrs.content ?? {})[0]?.content?.[0]?.text, 'A helpful reply.');
|
||||
});
|
||||
|
||||
async function setupProcessor() {
|
||||
const dir = await mkdtemp(join(tmpdir(), 'bridge-test-'));
|
||||
const state = new StateStore(join(dir, 'state.json'));
|
||||
await state.load();
|
||||
test.after(async () => rm(dir, { recursive: true, force: true }));
|
||||
const prompts: string[] = [];
|
||||
const created: unknown[] = [];
|
||||
const cache: NodeCache = new Map([
|
||||
['parent', { id: 'parent', createdBy: 'human', attrs: messageAttrs('parent', 'thread', [{ type: 'text', text: 'Parent context' }]) }]
|
||||
]);
|
||||
return {
|
||||
botUserId,
|
||||
workspaceId: 'workspace',
|
||||
cache,
|
||||
state,
|
||||
hermes: { bin: 'hermes', timeoutMs: 1000, maxOutputBytes: 1000 },
|
||||
colanode: { createMessage: async (_workspaceId: string, mutation: unknown) => { created.push(mutation); } } as never,
|
||||
runHermesFn: async (prompt: string) => {
|
||||
prompts.push(prompt);
|
||||
return 'Hermes reply';
|
||||
},
|
||||
prompts,
|
||||
created
|
||||
};
|
||||
}
|
||||
|
||||
function makeUpdate(nodeId: string, createdBy: string, attrs: MessageAttributes): SyncNodeUpdateData {
|
||||
return {
|
||||
id: `${nodeId}-update`,
|
||||
nodeId,
|
||||
rootId: 'root',
|
||||
workspaceId: 'workspace',
|
||||
revision: '1',
|
||||
data: encodeAttributes(attrs as unknown as Record<string, unknown>),
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy
|
||||
};
|
||||
}
|
||||
|
||||
function messageAttrs(id: string, parentId: string, content: BlockLeaf[]): MessageAttributes {
|
||||
const blockId = `${id}-block`;
|
||||
return {
|
||||
type: 'message',
|
||||
subtype: 'standard',
|
||||
parentId,
|
||||
content: {
|
||||
[blockId]: { id: blockId, type: 'paragraph', parentId: id, index: 'a0', content }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function mutationData(mutation: unknown): { data: string } {
|
||||
const outer = mutation as { data: { data: string } };
|
||||
return outer.data;
|
||||
}
|
||||
Reference in New Issue
Block a user