The bot's id never reached its prompt: `composeBotPrompt` only took its instructions, the appendix, its memory and its workspace, and `grabBotPrompt` never passed `bot.id` or `bot.name` on. A bot could only learn its id by accident, from a tool description that named it, so "which bot am I" was unanswerable in most contexts. - Open the prompt with who the bot is (`composeIdentity`): its name, whether it's the coordinator or a worker, its role, and its id, said to be how tools and refs point back at it. `grabBotPrompt` now passes the bot, which covers chat replies, tasks, routines and delegated tasks, since both runners build their prompt there. - Turn the notes' example refs into functions bound to the running bot: `chatReplyNote`, `botFilesNote` and `coordinatorReplyNote` take its id, so the folder-ref example no longer points at a hardcoded `owner_id: 5` (another bot's folder) nor `[bot:3]`. ComputerFilesNote keeps the computer it's given. - Stop `create_task` from hiding the worker's own id in its own chat. Tests: four new `composeBotPrompt` cases pin the identity block (worker, coordinator, unnamed, no bot at all), and a new `harness-prompts.test.ts` checks each note's own-folder and self refs point at exactly the running bot, for three ids.
121 lines
6.2 KiB
TypeScript
121 lines
6.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import composeBotPrompt from "./compose-bot-prompt";
|
|
|
|
describe("composeBotPrompt", () => {
|
|
test("opens with who the bot is, its id included", () => {
|
|
expect(composeBotPrompt({ bot: { id: 7, name: "Scout", kind: "worker", role: "Finds things" } })).toBe(
|
|
[
|
|
"# You are Scout",
|
|
"You are a worker bot on this crew. Your role: Finds things.",
|
|
"Your bot id is 7. That id is you: when a tool takes a bot id for the bot it is about (your own tasks, your own picture), this is it, and when you name yourself in a message write the ref `[bot:7]`, never another bot's.",
|
|
].join("\n\n"),
|
|
);
|
|
});
|
|
|
|
test("knows the coordinator by its kind and keeps an unknown name", () => {
|
|
expect(composeBotPrompt({ bot: { id: "1", kind: "coordinator" } })).toBe(
|
|
[
|
|
"# You are A bot",
|
|
"You are the coordinator on this crew.",
|
|
"Your bot id is 1. That id is you: when a tool takes a bot id for the bot it is about (your own tasks, your own picture), this is it, and when you name yourself in a message write the ref `[bot:1]`, never another bot's.",
|
|
].join("\n\n"),
|
|
);
|
|
});
|
|
|
|
test("says nothing about identity when the caller gives no bot", () => {
|
|
expect(composeBotPrompt({ bot: { id: null, name: "Scout" }, system_prompt: "Core." })).toBe(
|
|
"Core.",
|
|
);
|
|
});
|
|
|
|
test("puts the identity above the core instructions", () => {
|
|
expect(composeBotPrompt({ bot: { id: 4, name: "Scout" }, system_prompt: "Core." })).toBe(
|
|
[
|
|
"# You are Scout",
|
|
"You are a worker bot on this crew.",
|
|
"Your bot id is 4. That id is you: when a tool takes a bot id for the bot it is about (your own tasks, your own picture), this is it, and when you name yourself in a message write the ref `[bot:4]`, never another bot's.",
|
|
"Core.",
|
|
].join("\n\n"),
|
|
);
|
|
});
|
|
|
|
test("orders core instructions, the workspace, then memory", () => {
|
|
expect(
|
|
composeBotPrompt({
|
|
bot: { id: 7, name: "Scout" },
|
|
system_prompt: "# You are Scout\n\nFind things.",
|
|
memory: "- Cite sources.",
|
|
user_memory: "- The user prefers short replies.",
|
|
workspace: {
|
|
name: "Launch",
|
|
description: "The spring launch.",
|
|
system_prompt: "Ship by Friday.",
|
|
},
|
|
workspace_bot: {
|
|
system_prompt: "Own the changelog.",
|
|
memory: "- Marketing signs off on copy.",
|
|
},
|
|
}),
|
|
).toBe(
|
|
[
|
|
"# You are Scout",
|
|
"You are a worker bot on this crew.",
|
|
"Your bot id is 7. That id is you: when a tool takes a bot id for the bot it is about (your own tasks, your own picture), this is it, and when you name yourself in a message write the ref `[bot:7]`, never another bot's.",
|
|
"# You are Scout\n\nFind things.",
|
|
`# Workspace: Launch\n\nYou're working in the workspace "Launch". Follow its context and your instructions for it below, over your general habits where they differ.\n\nThe workspace's context, which the user sets:\n\nThe spring launch.\n\nShip by Friday.`,
|
|
"# Your instructions in Launch\n\nOwn the changelog.",
|
|
"# Memory\n\n- Cite sources.",
|
|
"# Memory about the user\n\n- The user prefers short replies.",
|
|
`# Memory in Launch\n\nYour own notes for this workspace: what you have learned here. They are not the workspace's description or context, which the user sets above; never call them the workspace's record. The user reads them in the workspace's settings, under this bot's row.\n\n- Marketing signs off on copy.`,
|
|
].join("\n\n"),
|
|
);
|
|
});
|
|
|
|
test("puts the install-wide appendix right after the core instructions", () => {
|
|
expect(
|
|
composeBotPrompt({
|
|
bot: { id: 4, name: "Scout" },
|
|
system_prompt: "Core.",
|
|
appendix: "Never invent sources.",
|
|
workspace: { name: "Launch", description: "The spring launch." },
|
|
memory: "- Cite sources.",
|
|
}),
|
|
).toBe(
|
|
[
|
|
"# You are Scout",
|
|
"You are a worker bot on this crew.",
|
|
"Your bot id is 4. That id is you: when a tool takes a bot id for the bot it is about (your own tasks, your own picture), this is it, and when you name yourself in a message write the ref `[bot:4]`, never another bot's.",
|
|
"Core.",
|
|
"# Install-wide instructions\n\nNever invent sources.",
|
|
`# Workspace: Launch\n\nYou're working in the workspace "Launch". Follow its context and your instructions for it below, over your general habits where they differ.\n\nThe workspace's context, which the user sets:\n\nThe spring launch.`,
|
|
"# Memory\n\n- Cite sources.",
|
|
].join("\n\n"),
|
|
);
|
|
});
|
|
|
|
test("shows an appendix on its own and ignores a blank one", () => {
|
|
expect(composeBotPrompt({ appendix: "Be brief." })).toBe(
|
|
"# Install-wide instructions\n\nBe brief.",
|
|
);
|
|
expect(composeBotPrompt({ system_prompt: "Core.", appendix: " " })).toBe("Core.");
|
|
});
|
|
|
|
test("leaves out empty parts and has no workspace outside one", () => {
|
|
expect(
|
|
composeBotPrompt({
|
|
system_prompt: "Core.",
|
|
memory: " ",
|
|
user_memory: "",
|
|
workspace_bot: { system_prompt: "Ignored." },
|
|
}),
|
|
).toBe("Core.");
|
|
expect(composeBotPrompt({})).toBe("");
|
|
});
|
|
|
|
test("names an untitled workspace even when it has no context", () => {
|
|
expect(composeBotPrompt({ workspace: { name: null } })).toBe(
|
|
`# Workspace: Untitled\n\nYou're working in the workspace "Untitled". Follow its context and your instructions for it below, over your general habits where they differ.`,
|
|
);
|
|
});
|
|
});
|