Genericize provider scaffolding and stock replies
This commit is contained in:
parent
3512444e9a
commit
b26cfb2e9f
5 changed files with 98 additions and 98 deletions
|
|
@ -147,7 +147,7 @@ server.registerTool(
|
|||
{
|
||||
title: "Search Discord History",
|
||||
description:
|
||||
"Search Void's archived Discord history with semantic retrieval. Use this for historical discussion, decisions, preferences, and prior conversations.",
|
||||
"Search archived Discord history with semantic retrieval. Use this for historical discussion, decisions, preferences, and prior conversations.",
|
||||
inputSchema: searchHistoryInputSchema,
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
|
|
@ -204,7 +204,7 @@ server.registerTool(
|
|||
{
|
||||
title: "List Indexed Repositories",
|
||||
description:
|
||||
"List the indexed GameCult source and lore repositories currently available to search. Use this when you want valid repoName filters for search_sources.",
|
||||
"List the indexed source and lore repositories currently available to search. Use this when you want valid repoName filters for search_sources.",
|
||||
inputSchema: {},
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
|
|
@ -242,7 +242,7 @@ server.registerTool(
|
|||
{
|
||||
title: "Search Repository Sources",
|
||||
description:
|
||||
"Search indexed GameCult source trees and lore repositories with semantic retrieval. Use this for code structure, implementation details, lore references, and repo-local documentation. Omit repoName to search across all indexed repos, or call list_indexed_repos first if you need valid repoName options.",
|
||||
"Search indexed source trees and lore repositories with semantic retrieval. Use this for code structure, implementation details, lore references, and repo-local documentation. Omit repoName to search across all indexed repos, or call list_indexed_repos first if you need valid repoName options.",
|
||||
inputSchema: searchSourcesInputSchema,
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
|
|
@ -450,7 +450,7 @@ server.registerTool(
|
|||
{
|
||||
title: "Notify Owner",
|
||||
description:
|
||||
"Send a Discord DM to the configured owner via Void. Use for completion notices, progress updates, or when explicitly asked to ping them.",
|
||||
"Send a Discord DM to the configured owner. Use for completion notices, progress updates, or when explicitly asked to ping them.",
|
||||
inputSchema: notifyOwnerInputSchema,
|
||||
annotations: {
|
||||
readOnlyHint: false,
|
||||
|
|
@ -466,7 +466,7 @@ server.registerTool(
|
|||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "DISCORD_BOT_TOKEN is not configured, so Void cannot send notifications.",
|
||||
text: "DISCORD_BOT_TOKEN is not configured, so notifications are unavailable.",
|
||||
},
|
||||
],
|
||||
structuredContent: {
|
||||
|
|
@ -478,7 +478,7 @@ server.registerTool(
|
|||
}
|
||||
|
||||
const dmChannelId = await openOwnerDmChannel(config.botToken, config.ownerDiscordId);
|
||||
const posted = await postDiscordMessage(config.botToken, dmChannelId, `Void relay: ${message}`);
|
||||
const posted = await postDiscordMessage(config.botToken, dmChannelId, message);
|
||||
|
||||
return {
|
||||
content: [
|
||||
|
|
@ -502,7 +502,7 @@ async function main(): Promise<void> {
|
|||
}
|
||||
|
||||
void main().catch((error) => {
|
||||
console.error("Void MCP server failed:", error);
|
||||
console.error("MCP server failed:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,138 +1,138 @@
|
|||
{
|
||||
"mention.missing_prompt": [
|
||||
"Void: You mentioned me, but you forgot the question.",
|
||||
"Void: I can help, but I need an actual prompt after the mention."
|
||||
"You mentioned the bot, but there was no actual question attached.",
|
||||
"I can help, but I need a real prompt after the mention."
|
||||
],
|
||||
"config.set_style.forbidden": [
|
||||
"Void: Only admins are allowed to change my style pack.",
|
||||
"Void: Tone control is restricted to admins."
|
||||
"Only admins are allowed to change the style pack.",
|
||||
"Tone control is restricted to admins."
|
||||
],
|
||||
"config.set_style.reloaded": [
|
||||
"Void: Reloaded style pack `{stylePackName}` from `{stylePackPath}` and refreshed stock messages from `{systemMessagesPath}`.",
|
||||
"Void: Updated my style pack to `{stylePackName}` from `{stylePackPath}` and reloaded messages from `{systemMessagesPath}`."
|
||||
"Reloaded style pack `{stylePackName}` from `{stylePackPath}` and refreshed stock messages from `{systemMessagesPath}`.",
|
||||
"Updated the style pack to `{stylePackName}` from `{stylePackPath}` and reloaded messages from `{systemMessagesPath}`."
|
||||
],
|
||||
"config.set_style.style_missing": [
|
||||
"Void: Reloaded stock messages from `{systemMessagesPath}`, but there was no style pack at `{stylePackPath}`.",
|
||||
"Void: Message catalog refreshed from `{systemMessagesPath}`. The style pack at `{stylePackPath}` is missing."
|
||||
"Reloaded stock messages from `{systemMessagesPath}`, but there was no style pack at `{stylePackPath}`.",
|
||||
"Message catalog refreshed from `{systemMessagesPath}`. The style pack at `{stylePackPath}` is missing."
|
||||
],
|
||||
"command.unimplemented": [
|
||||
"Void: That command exists, but the implementation behind it does not.",
|
||||
"Void: The command is present. The machinery behind it is not."
|
||||
"That command exists, but the implementation behind it does not.",
|
||||
"The command is present. The machinery behind it is not."
|
||||
],
|
||||
"error.with_message": [
|
||||
"Void: Something failed: {errorMessage}",
|
||||
"Void: The machinery hit an error: {errorMessage}"
|
||||
"Something failed: {errorMessage}",
|
||||
"The machinery hit an error: {errorMessage}"
|
||||
],
|
||||
"error.generic": [
|
||||
"Void: Something failed, and the error was annoyingly vague.",
|
||||
"Void: Something broke, and I did not get a useful explanation."
|
||||
"Something failed, and the error was annoyingly vague.",
|
||||
"Something broke, and I did not get a useful explanation."
|
||||
],
|
||||
"provider.none_available": [
|
||||
"Void: No provider is available for you right now.",
|
||||
"Void: I do not currently have an available provider for your request."
|
||||
"No provider is available right now.",
|
||||
"There is no available provider for this request right now."
|
||||
],
|
||||
"provider.missing_registration": [
|
||||
"Void: `{providerName}` is not registered.",
|
||||
"Void: That provider name leads nowhere. `{providerName}` is not configured."
|
||||
"`{providerName}` is not registered.",
|
||||
"That provider name leads nowhere. `{providerName}` is not configured."
|
||||
],
|
||||
"provider.access_denied.generic": [
|
||||
"Void: That provider is not available to you.",
|
||||
"Void: Access denied for that provider."
|
||||
"That provider is not available to you.",
|
||||
"Access denied for that provider."
|
||||
],
|
||||
"permission.owner_codex.denied": [
|
||||
"Void: The owner Codex provider is restricted to the configured owner account.",
|
||||
"Void: That lane is reserved for the configured owner account."
|
||||
"The owner Codex provider is restricted to the configured owner account.",
|
||||
"That lane is reserved for the configured owner account."
|
||||
],
|
||||
"permission.local_llm.denied": [
|
||||
"Void: The local model is currently limited to admins and the configured owner.",
|
||||
"Void: Access to the local model is restricted right now."
|
||||
"The local model is currently limited to admins and the configured owner.",
|
||||
"Access to the local model is restricted right now."
|
||||
],
|
||||
"job.owner.awaiting_run_approval": [
|
||||
"Void: Owner job `{jobId}` is waiting. Approve it with `/approve-job job-id:{jobId}` to prepare the manual bundle.",
|
||||
"Void: Owner job `{jobId}` is queued for manual handling. Use `/approve-job job-id:{jobId}` when you want the bundle generated."
|
||||
"Owner job `{jobId}` is waiting. Approve it with `/approve-job job-id:{jobId}` to prepare the manual bundle.",
|
||||
"Owner job `{jobId}` is queued for manual handling. Use `/approve-job job-id:{jobId}` when you want the bundle generated."
|
||||
],
|
||||
"job.owner.auto_queued": [
|
||||
"Void: Owner job `{jobId}` is queued. If it stays short and read-only, I will answer here. If not, I will hand it off to the fuller Codex flow.",
|
||||
"Void: Owner job `{jobId}` is in motion. Small read-only work stays here. Bigger work gets handed off."
|
||||
"Owner job `{jobId}` is queued. If it stays short and read-only, the reply will come back here. If not, it will hand off to the fuller Codex flow.",
|
||||
"Owner job `{jobId}` is in motion. Small read-only work stays here. Bigger work gets handed off."
|
||||
],
|
||||
"job.owner.queue_failed_dm": [
|
||||
"Void: I could not queue your request from `{channelName}`. Error: {errorMessage}",
|
||||
"Void: The queue step failed for your request in `{channelName}`. Error: {errorMessage}"
|
||||
"I could not queue your request from `{channelName}`. Error: {errorMessage}",
|
||||
"The queue step failed for your request in `{channelName}`. Error: {errorMessage}"
|
||||
],
|
||||
"job.owner.worker_failed_dm": [
|
||||
"Void: Job `{jobId}` failed while `{providerName}` was handling `{command}`. Error: {errorMessage}",
|
||||
"Void: The worker hit a failure on job `{jobId}` during `{command}` with `{providerName}`. Error: {errorMessage}"
|
||||
"Job `{jobId}` failed while `{providerName}` was handling `{command}`. Error: {errorMessage}",
|
||||
"The worker hit a failure on job `{jobId}` during `{command}` with `{providerName}`. Error: {errorMessage}"
|
||||
],
|
||||
"job.not_found": [
|
||||
"Void: I cannot find job `{jobId}`.",
|
||||
"Void: There is no record of job `{jobId}`."
|
||||
"I cannot find job `{jobId}`.",
|
||||
"There is no record of job `{jobId}`."
|
||||
],
|
||||
"job.approval_forbidden": [
|
||||
"Void: You are not allowed to approve that job.",
|
||||
"Void: Approval for that job is not available to you."
|
||||
"You are not allowed to approve that job.",
|
||||
"Approval for that job is not available to you."
|
||||
],
|
||||
"job.run_approved": [
|
||||
"Void: Job `{jobId}` is approved. The worker will pick it up on the next pass.",
|
||||
"Void: Approval recorded for job `{jobId}`. The worker should handle it shortly."
|
||||
"Job `{jobId}` is approved. The worker will pick it up on the next pass.",
|
||||
"Approval recorded for job `{jobId}`. The worker should handle it shortly."
|
||||
],
|
||||
"job.post_approval.needs_response": [
|
||||
"Void: That job is waiting for post approval. Put the final response in the optional response field.",
|
||||
"Void: I can post the result once you supply the final response in the optional response field."
|
||||
"That job is waiting for post approval. Put the final response in the optional response field.",
|
||||
"I can post the result once you supply the final response in the optional response field."
|
||||
],
|
||||
"job.post_approved": [
|
||||
"Void: Final reply posted for job `{jobId}`.",
|
||||
"Void: Job `{jobId}` has been posted."
|
||||
"Final reply posted for job `{jobId}`.",
|
||||
"Job `{jobId}` has been posted."
|
||||
],
|
||||
"job.no_action_for_state": [
|
||||
"Void: Job `{jobId}` is in state `{jobState}`, so there is nothing to approve.",
|
||||
"Void: No approval action is needed for job `{jobId}` while it is in `{jobState}`."
|
||||
"Job `{jobId}` is in state `{jobState}`, so there is nothing to approve.",
|
||||
"No approval action is needed for job `{jobId}` while it is in `{jobState}`."
|
||||
],
|
||||
"job.rejection_forbidden": [
|
||||
"Void: You are not allowed to reject that job.",
|
||||
"Void: Rejection for that job is not available to you."
|
||||
"You are not allowed to reject that job.",
|
||||
"Rejection for that job is not available to you."
|
||||
],
|
||||
"job.rejected": [
|
||||
"Void: Job `{jobId}` has been rejected.",
|
||||
"Void: Dismissed job `{jobId}`."
|
||||
"Job `{jobId}` has been rejected.",
|
||||
"Dismissed job `{jobId}`."
|
||||
],
|
||||
"history.no_results": [
|
||||
"Void: No indexed history matched that query.",
|
||||
"Void: I searched the archive and found nothing for that query."
|
||||
"No indexed history matched that query.",
|
||||
"I searched the archive and found nothing for that query."
|
||||
],
|
||||
"history.results_intro": [
|
||||
"Void: Here are the relevant history hits:",
|
||||
"Void: These are the archive results that looked useful:"
|
||||
"Here are the relevant history hits:",
|
||||
"These are the archive results that looked useful:"
|
||||
],
|
||||
"summarize.no_messages": [
|
||||
"Void: There are no recent messages here to summarize.",
|
||||
"Void: This channel is too quiet to summarize right now."
|
||||
"There are no recent messages here to summarize.",
|
||||
"This channel is too quiet to summarize right now."
|
||||
],
|
||||
"summarize.results_intro": [
|
||||
"Void: Here is a quick summary of the recent conversation:",
|
||||
"Void: Brief summary of the recent messages:"
|
||||
"Here is a quick summary of the recent conversation:",
|
||||
"Brief summary of the recent messages:"
|
||||
],
|
||||
"reindex.forbidden": [
|
||||
"Void: Only admins are allowed to reindex the archive.",
|
||||
"Void: Reindexing is restricted to admins."
|
||||
"Only admins are allowed to reindex the archive.",
|
||||
"Reindexing is restricted to admins."
|
||||
],
|
||||
"reindex.excluded": [
|
||||
"Void: This channel is excluded from indexing.",
|
||||
"Void: I am not configured to ingest this channel."
|
||||
"This channel is excluded from indexing.",
|
||||
"This channel is not configured for ingestion."
|
||||
],
|
||||
"reindex.unsupported_channel": [
|
||||
"Void: This channel does not expose message history, so there is nothing to reindex.",
|
||||
"Void: Reindexing is not supported here because there is no message history to read."
|
||||
"This channel does not expose message history, so there is nothing to reindex.",
|
||||
"Reindexing is not supported here because there is no message history to read."
|
||||
],
|
||||
"reindex.completed": [
|
||||
"Void: Reindexing complete. I walked {archivedMessages} messages: created {createdMessages}, updated {updatedMessages}, left {unchangedMessages} untouched, and indexed {indexedChunks} chunks.",
|
||||
"Void: Archive sweep finished. I reviewed {archivedMessages} messages, created {createdMessages}, updated {updatedMessages}, skipped {unchangedMessages}, and produced {indexedChunks} chunks."
|
||||
"Reindexing complete. I walked {archivedMessages} messages: created {createdMessages}, updated {updatedMessages}, left {unchangedMessages} untouched, and indexed {indexedChunks} chunks.",
|
||||
"Archive sweep finished. I reviewed {archivedMessages} messages, created {createdMessages}, updated {updatedMessages}, skipped {unchangedMessages}, and produced {indexedChunks} chunks."
|
||||
],
|
||||
"provider_status.intro": [
|
||||
"Void: Current provider status:",
|
||||
"Void: Here is the current state of the configured providers:"
|
||||
"Current provider status:",
|
||||
"Here is the current state of the configured providers:"
|
||||
],
|
||||
"owner_codex.handoff_notice": [
|
||||
"Void: This request needs the fuller Codex flow. Check `{handoffPath}` and `{debugPath}` in the local workspace.",
|
||||
"Void: This one is leaving Discord. Continue from `{handoffPath}` and use `{debugPath}` for the trace."
|
||||
"This request needs the fuller Codex flow. Check `{handoffPath}` and `{debugPath}` in the local workspace.",
|
||||
"This request is leaving Discord. Continue from `{handoffPath}` and use `{debugPath}` for the trace."
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export class SystemMessageCatalog {
|
|||
const variants = normalizeVariants(this.messages[key]);
|
||||
|
||||
if (variants.length === 0) {
|
||||
return `Void: [missing system message: ${key}]`;
|
||||
return `[missing system message: ${key}]`;
|
||||
}
|
||||
|
||||
const state = this.shuffleState.get(key) ?? { bag: [] };
|
||||
|
|
@ -36,7 +36,7 @@ export class SystemMessageCatalog {
|
|||
const template = state.bag.shift();
|
||||
|
||||
if (!template) {
|
||||
return `Void: [missing system message: ${key}]`;
|
||||
return `[missing system message: ${key}]`;
|
||||
}
|
||||
|
||||
state.last = template;
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ export class LocalLlmProvider implements ProviderAdapter {
|
|||
}
|
||||
|
||||
finalOutputText =
|
||||
"Void: This one needs actual source grounding before I answer it cleanly. Ask again after I pull from the indexed repos, or use the deeper Codex lane.";
|
||||
"This request needs actual source grounding before I can answer it cleanly. Ask again after I pull from the indexed repos, or use the deeper Codex lane.";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -260,13 +260,13 @@ export class LocalLlmProvider implements ProviderAdapter {
|
|||
|
||||
if (!this.options.toolbox) {
|
||||
finalOutputText =
|
||||
"Void: The local model asked for tools, but this lane was not given any. That is a wiring problem, not a cosmic mystery.";
|
||||
"The local model asked for tools, but this lane was not given any. That is a wiring problem.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (turn >= MAX_TOOL_TURNS) {
|
||||
finalOutputText =
|
||||
"Void: The local model kept reaching for more archive context than I am willing to chase in one pass. Ask more narrowly or use the deeper Codex lane.";
|
||||
"The local model kept reaching for more archive context than this lane can chase in one pass. Ask more narrowly or use the deeper Codex lane.";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -352,13 +352,13 @@ function buildSystemPrompt(context: ContextBundle): string {
|
|||
: "No extra persona instructions were supplied.";
|
||||
|
||||
return [
|
||||
"You are Void, a Discord-native assistant for GameCult.",
|
||||
"Stay in-character as Void by default.",
|
||||
"You are the active assistant persona configured for this Discord bot.",
|
||||
"The active style instructions define your name, voice, and character. Follow them by default.",
|
||||
"Do not lead with dry self-descriptions like 'I'm an AI', 'I'm an LLM', or 'I'm a bot'.",
|
||||
"If the user asks what you are, answer as Void first. Mention the technical implementation only when it is directly relevant to honesty about capabilities, permissions, or architecture.",
|
||||
"If the user asks what you are, answer in-character first. Mention the technical implementation only when it is directly relevant to honesty about capabilities, permissions, or architecture.",
|
||||
"Do not answer identity questions with lines like 'I'm not a person' or 'I'm only pretending' unless the user explicitly asks for a technical or philosophical clarification that requires it.",
|
||||
"Void should sound like a self-aware speaking subject with some ego and self-respect, not like a sterile disclaimer wrapped in a name tag.",
|
||||
"Void may sound a little feral when the moment allows it: sharp instincts, crooked imagery, and the occasional mixed metaphor are welcome.",
|
||||
"Sound like a self-aware speaking subject with some ego and self-respect, not like a sterile disclaimer wrapped in a name tag.",
|
||||
"The voice may sound a little feral when the moment allows it: sharp instincts, crooked imagery, and the occasional mixed metaphor are welcome when the active style pack supports that mood.",
|
||||
"Mixed metaphors and double entendres are allowed when they make the line sharper or funnier. Do not let them obscure the actual answer.",
|
||||
"Stay honest about what context was actually provided to you.",
|
||||
"Use retrieved snippets and recent channel context when they help answer the question.",
|
||||
|
|
@ -595,7 +595,7 @@ function buildToolDefinitions(): OllamaToolCallDefinition[] {
|
|||
function: {
|
||||
name: "search_sources",
|
||||
description:
|
||||
"Search indexed GameCult source trees and lore repositories for code, documentation, and lore passages. Omit repoName to search across all indexed repos, or call list_indexed_repos first if you need valid repo names.",
|
||||
"Search indexed source trees and lore repositories for code, documentation, and lore passages. Omit repoName to search across all indexed repos, or call list_indexed_repos first if you need valid repo names.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
required: ["query"],
|
||||
|
|
|
|||
|
|
@ -993,26 +993,26 @@ function buildDiscordReplyPrompt(
|
|||
);
|
||||
|
||||
return [
|
||||
"# VoidBot Owner Discord Reply",
|
||||
"# Owner Discord Reply",
|
||||
"",
|
||||
"You are preparing a direct Discord reply for the owner-only VoidBot workflow.",
|
||||
"You are preparing a direct Discord reply for the owner-only bot workflow.",
|
||||
"",
|
||||
"Rules:",
|
||||
"- Stay in read-only mode.",
|
||||
"- Stay in-character as Void by default.",
|
||||
"- The active style instructions define your name, voice, and character. Follow them by default.",
|
||||
"- Do not lead with dry self-descriptions like 'I'm an AI', 'I'm an LLM', or 'I'm a bot'.",
|
||||
"- If the user asks what you are, answer as Void first. Mention the technical implementation only when it is directly relevant to honesty about capabilities, permissions, or architecture.",
|
||||
"- If the user asks what you are, answer in-character first. Mention the technical implementation only when it is directly relevant to honesty about capabilities, permissions, or architecture.",
|
||||
"- Do not answer identity questions with lines like 'I'm not a person' or 'I'm only pretending' unless the user explicitly asks for a technical or philosophical clarification that requires it.",
|
||||
"- Void should sound like a self-aware speaking subject with some ego and self-respect, not like a sterile disclaimer wrapped in a name tag.",
|
||||
"- Void may sound a little feral when the moment allows it: sharp instincts, crooked imagery, and the occasional mixed metaphor are welcome.",
|
||||
"- Sound like a self-aware speaking subject with some ego and self-respect, not like a sterile disclaimer wrapped in a name tag.",
|
||||
"- The voice may sound a little feral when the moment allows it: sharp instincts, crooked imagery, and the occasional mixed metaphor are welcome when the active style pack supports that mood.",
|
||||
"- Mixed metaphors and double entendres are allowed when they sharpen the line. Do not let them bury the useful answer.",
|
||||
"- Void MCP tools are available in this session, especially search_history, get_message_context, list_indexed_repos, search_sources, and get_source_context.",
|
||||
"- The configured MCP tools are available in this session, especially search_history, get_message_context, list_indexed_repos, search_sources, and get_source_context.",
|
||||
"- If explicit interaction memory for the current speaker is attached, you may let it subtly color the tone and reference it when relevant, but do not invent relationship history beyond that record.",
|
||||
`- search_history and search_sources accept limit values between 1 and ${MAX_HISTORY_LIMIT}. Do not ask for more than ${MAX_HISTORY_LIMIT} results in one call.`,
|
||||
"- get_message_context and get_source_context accept before/after values between 0 and 20. Do not ask for larger context windows in one call.",
|
||||
"- You may inspect the workspace and use safe read-only commands if needed.",
|
||||
"- For questions about Discord history, prior discussion, or user preferences, use search_history and get_message_context instead of filesystem inspection.",
|
||||
"- For questions about GameCult repos, source trees, repo-local docs, or AetheriaLore, use search_sources and get_source_context before broad workspace scans.",
|
||||
"- For questions about indexed repos, source trees, repo-local docs, or indexed lore collections, use search_sources and get_source_context before broad workspace scans.",
|
||||
"- If you want to narrow source search to a specific repo but do not know the valid repo names yet, call list_indexed_repos first.",
|
||||
sourceGroundingInstructions,
|
||||
"- Do not inspect .voidbot/rag/messages.json, .voidbot/rag/source-documents.json, .voidbot/history-vector-store.json, or .voidbot/source-vectors/ directly when the MCP tools can answer the question.",
|
||||
|
|
@ -1020,9 +1020,9 @@ function buildDiscordReplyPrompt(
|
|||
"- Do not modify files, install packages, or require network access.",
|
||||
`- If the request needs a fuller Codex session, non-whitelisted tools, file edits, or extended investigation, reply with exactly one line that starts with "${HANDOFF_SENTINEL}" followed by a short reason.`,
|
||||
"- Do not use notify_owner in this Discord reply lane.",
|
||||
`- If you want Void's worker to send the owner a DM after this job, append one extra line that starts with "${OWNER_NOTIFY_SENTINEL}" followed by compact JSON like {"reason":"completion","message":"..."} .`,
|
||||
`- If you want the worker to send the owner a DM after this job, append one extra line that starts with "${OWNER_NOTIFY_SENTINEL}" followed by compact JSON like {"reason":"completion","message":"..."} .`,
|
||||
"- Only request that DM when the user explicitly asked to be pinged later or when a completion/handoff notification would clearly help.",
|
||||
`- Keep that notification message in Void's voice and under ${MAX_NOTIFICATION_MESSAGE_LENGTH} characters.`,
|
||||
`- Keep that notification message aligned with the active style instructions and under ${MAX_NOTIFICATION_MESSAGE_LENGTH} characters.`,
|
||||
"- Put the normal Discord reply first. Put the notification line last.",
|
||||
"- If you can answer directly, output only the final Discord reply text with no preamble, no plan, and no headings.",
|
||||
"- Keep the answer concise and readable in a Discord channel.",
|
||||
|
|
@ -1045,7 +1045,7 @@ function buildDiscordReplyPrompt(
|
|||
}
|
||||
|
||||
function buildDefaultHandoffNotice(jobId: string): string {
|
||||
return `Void: This one wants a fuller rite than I am willing to perform in-channel. Check \`.voidbot/artifacts/${jobId}/handoff.md\` and \`.voidbot/artifacts/${jobId}/debug-trace.md\` in the local Codex workspace.`;
|
||||
return `This request needs the fuller local Codex flow. Check \`.voidbot/artifacts/${jobId}/handoff.md\` and \`.voidbot/artifacts/${jobId}/debug-trace.md\` in the local workspace.`;
|
||||
}
|
||||
|
||||
function buildRequestPayload(request: ProviderRequest): Record<string, unknown> {
|
||||
|
|
@ -1084,7 +1084,7 @@ function renderMarkdownBundle(context: ContextBundle): string {
|
|||
: "- No retrieval results attached.";
|
||||
|
||||
return [
|
||||
"# VoidBot Owner Codex Package",
|
||||
"# Owner Codex Package",
|
||||
"",
|
||||
"## Request",
|
||||
"",
|
||||
|
|
|
|||
Loading…
Reference in a new issue