refactor(prompt-builder): convert 11-key wake reason map to data table

- New src/main/prompt-builder/wake-reasons/en.ts: WAKE_REASONS record of
  { title, steps(vars) } entries + renderWakeReason() formatter that
  numbers the steps and composes the final block
- buildTaskPrompt in prompt-builder/index.ts collapses 100-line inline
  reasonMap into a single renderWakeReason call
- index.ts shrinks from 161 to 77 lines; each wake reason's semantic
  content (title text + numbered action steps + embedded curl hints)
  preserved verbatim
This commit is contained in:
ZacharyZhang-NY committed 2026-04-16 23:37:42 -04:00
1 parent 75022f82c5
commit d75389c418
2 files changed
+153 -89

No files matched your search

+5 -89
View File
@@ -1,6 +1,7 @@
import type { AgentRecord, AgentMessageRecord, ApprovalRecord, DocumentRecord, ExecutionMode, GoalRecord, KnowledgeEntryRecord, MeetingRecord, ProjectRecord, SprintRecord, TaskRecord } from "@shared/types";
import type { AppLocale } from "@shared/locale";
import { buildSystemPrompt } from "./system-prompt";
import { renderWakeReason } from "./wake-reasons/en";
export interface PromptContext {
agent: AgentRecord;
@@ -50,95 +51,10 @@ export function buildTaskPrompt(ctx: PromptContext): string {
const parts: string[] = [systemPrompt];
if (ctx.wakeReason) {
const reasonMap: Record<string, string> = {
timer: `Regular heartbeat check-in. This is your periodic wake.
Action required:
1. Call GET /api/agents/me/standup to get your full briefing
2. Review all your assigned tasks and their statuses
3. Take action on the most important item: reviews > unblocking > new work
4. If nothing needs attention, post a brief status update on your current task`,
manual: `You were manually triggered by the human operator (Board).
Action required:
1. Check your assigned tasks for any new assignments or updated instructions
2. Check your messages for any direct communications
3. Execute any pending work with high priority — the Board is watching`,
assignment: `You have been assigned a new task.
Action required:
1. GET /api/companies/${ctx.agent.companyId}/issues?assigneeAgentId=${ctx.agent.id}&status=todo to find your new assignment
2. Review the task title, description, and any existing comments
3. POST /api/issues/{issueId}/checkout to claim the task
4. Begin working on it immediately according to your Operating Instructions`,
goal_activated: `A goal you own has been activated.
Action required:
1. GET /api/companies/${ctx.agent.companyId}/goals to find the newly activated goal
2. Decompose the goal into projects (POST /api/companies/${ctx.agent.companyId}/projects)
3. Break projects into actionable tasks and assign to your team
4. Leave a planning comment on each task explaining the approach`,
approval_resolved: `An approval you requested has been decided.
Action required:
1. GET /api/companies/${ctx.agent.companyId}/approvals?requestedByAgentId=${ctx.agent.id} to check the result
2. If APPROVED: proceed with the action you were waiting on (hiring, credential access, etc.)
3. If DENIED or REVISION_REQUESTED: read the feedback, adjust your approach, and resubmit if appropriate
4. Update the related task with the outcome`,
subtask_completed: `A subtask you delegated has been completed or moved to review.
Action required:
1. Check tasks with status "in_review" from your reports
2. Read ALL comments on the completed subtask (GET /api/issues/{issueId}/comments)
3. Review the work quality against the acceptance criteria you set
4. If acceptable: PATCH /api/issues/{issueId} with status "done" and an approving comment
5. If changes needed: PATCH /api/issues/{issueId} with status "in_progress" and specific feedback
6. Check if the parent task can now progress`,
comment: `A new comment has been posted on one of your tasks.
Action required:
1. Check your recent comments in the briefing above
2. If someone asked you a question: respond via POST /api/issues/{issueId}/comments
3. If your manager left feedback: address it and update the task
4. If it's a status update from a collaborator: acknowledge and adjust your work if needed`,
report_blocked: `One of your reports is blocked and needs your help.
Action required:
1. GET /api/companies/${ctx.agent.companyId}/issues?status=blocked to find blocked tasks under your reports
2. Read the blocker comments to understand what they need
3. Take action to unblock them:
- If they need credentials: create a secret_access approval via POST /api/companies/${ctx.agent.companyId}/approvals
- If they need cross-department help: send a message to the relevant department lead
- If they need clarification: post a comment with clear direction
4. After unblocking, wake the agent: POST /api/agents/{agentId}/wake with reason "blocker resolved"`,
report_failed: `A run by one of your reports has failed.
Action required:
1. Check your reports' task statuses for failed or stalled items
2. Investigate: read the task comments and any error information
3. Decide on next steps:
- If the task should be retried: set status back to "todo" with a comment explaining what to do differently
- If the task should be reassigned: change the assigneeAgentId to another capable report
- If the task is no longer needed: set status to "cancelled" with explanation
4. Wake the relevant agent to take action`,
message: `You received a direct message from another agent.
Action required:
1. GET /api/companies/${ctx.agent.companyId}/messages?unreadOnly=true to read your new messages
2. Read each message and understand what is being asked
3. Respond to each message using the exact sender and message IDs returned by the API:
- For direct messages, POST /api/companies/${ctx.agent.companyId}/messages with channel="direct", toAgentId set to the original message's fromAgentId, and parentMessageId set to that message's id
- If the sender is Board, the toAgentId is "__board__"
4. Mark messages as read: POST /api/companies/${ctx.agent.companyId}/messages/{messageId}/read
5. If the message requires you to take action on a task, do so`,
peer_request: `A peer agent has requested your attention.
Action required:
1. Check your messages: GET /api/companies/${ctx.agent.companyId}/messages?unreadOnly=true
2. Check for any new task assignments from outside your usual chain
3. Read and respond to the peer's request using the sender's fromAgentId and message id from the API response
4. If cross-department collaboration is needed, coordinate via messages and tasks`,
};
const explanation = reasonMap[ctx.wakeReason] ?? `Trigger: ${ctx.wakeReason}\nAction required: Check your standup briefing and messages for context on why you were woken.`;
const explanation = renderWakeReason(ctx.wakeReason, {
companyId: ctx.agent.companyId,
agentId: ctx.agent.id,
});
parts.push(`\n# Wake Reason\n${explanation}\n`);
}
+148
View File
@@ -0,0 +1,148 @@
export type WakeReason =
| "timer"
| "manual"
| "assignment"
| "goal_activated"
| "approval_resolved"
| "subtask_completed"
| "comment"
| "report_blocked"
| "report_failed"
| "message"
| "peer_request";
export interface WakeReasonVars {
companyId: string;
agentId: string;
}
export interface WakeReasonEntry {
title: string;
steps: (v: WakeReasonVars) => string[];
}
export const WAKE_REASONS: Record<WakeReason, WakeReasonEntry> = {
timer: {
title: "Regular heartbeat check-in. This is your periodic wake.",
steps: () => [
"Call GET /api/agents/me/standup to get your full briefing",
"Review all your assigned tasks and their statuses",
"Take action on the most important item: reviews > unblocking > new work",
"If nothing needs attention, post a brief status update on your current task",
],
},
manual: {
title: "You were manually triggered by the human operator (Board).",
steps: () => [
"Check your assigned tasks for any new assignments or updated instructions",
"Check your messages for any direct communications",
"Execute any pending work with high priority — the Board is watching",
],
},
assignment: {
title: "You have been assigned a new task.",
steps: (v) => [
`GET /api/companies/${v.companyId}/issues?assigneeAgentId=${v.agentId}&status=todo to find your new assignment`,
"Review the task title, description, and any existing comments",
"POST /api/issues/{issueId}/checkout to claim the task",
"Begin working on it immediately according to your Operating Instructions",
],
},
goal_activated: {
title: "A goal you own has been activated.",
steps: (v) => [
`GET /api/companies/${v.companyId}/goals to find the newly activated goal`,
`Decompose the goal into projects (POST /api/companies/${v.companyId}/projects)`,
"Break projects into actionable tasks and assign to your team",
"Leave a planning comment on each task explaining the approach",
],
},
approval_resolved: {
title: "An approval you requested has been decided.",
steps: (v) => [
`GET /api/companies/${v.companyId}/approvals?requestedByAgentId=${v.agentId} to check the result`,
"If APPROVED: proceed with the action you were waiting on (hiring, credential access, etc.)",
"If DENIED or REVISION_REQUESTED: read the feedback, adjust your approach, and resubmit if appropriate",
"Update the related task with the outcome",
],
},
subtask_completed: {
title: "A subtask you delegated has been completed or moved to review.",
steps: () => [
'Check tasks with status "in_review" from your reports',
"Read ALL comments on the completed subtask (GET /api/issues/{issueId}/comments)",
"Review the work quality against the acceptance criteria you set",
'If acceptable: PATCH /api/issues/{issueId} with status "done" and an approving comment',
'If changes needed: PATCH /api/issues/{issueId} with status "in_progress" and specific feedback',
"Check if the parent task can now progress",
],
},
comment: {
title: "A new comment has been posted on one of your tasks.",
steps: () => [
"Check your recent comments in the briefing above",
"If someone asked you a question: respond via POST /api/issues/{issueId}/comments",
"If your manager left feedback: address it and update the task",
"If it's a status update from a collaborator: acknowledge and adjust your work if needed",
],
},
report_blocked: {
title: "One of your reports is blocked and needs your help.",
steps: (v) => [
`GET /api/companies/${v.companyId}/issues?status=blocked to find blocked tasks under your reports`,
"Read the blocker comments to understand what they need",
`Take action to unblock them:
- If they need credentials: create a secret_access approval via POST /api/companies/${v.companyId}/approvals
- If they need cross-department help: send a message to the relevant department lead
- If they need clarification: post a comment with clear direction`,
'After unblocking, wake the agent: POST /api/agents/{agentId}/wake with reason "blocker resolved"',
],
},
report_failed: {
title: "A run by one of your reports has failed.",
steps: () => [
"Check your reports' task statuses for failed or stalled items",
"Investigate: read the task comments and any error information",
`Decide on next steps:
- If the task should be retried: set status back to "todo" with a comment explaining what to do differently
- If the task should be reassigned: change the assigneeAgentId to another capable report
- If the task is no longer needed: set status to "cancelled" with explanation`,
"Wake the relevant agent to take action",
],
},
message: {
title: "You received a direct message from another agent.",
steps: (v) => [
`GET /api/companies/${v.companyId}/messages?unreadOnly=true to read your new messages`,
"Read each message and understand what is being asked",
`Respond to each message using the exact sender and message IDs returned by the API:
- For direct messages, POST /api/companies/${v.companyId}/messages with channel="direct", toAgentId set to the original message's fromAgentId, and parentMessageId set to that message's id
- If the sender is Board, the toAgentId is "__board__"`,
`Mark messages as read: POST /api/companies/${v.companyId}/messages/{messageId}/read`,
"If the message requires you to take action on a task, do so",
],
},
peer_request: {
title: "A peer agent has requested your attention.",
steps: (v) => [
`Check your messages: GET /api/companies/${v.companyId}/messages?unreadOnly=true`,
"Check for any new task assignments from outside your usual chain",
"Read and respond to the peer's request using the sender's fromAgentId and message id from the API response",
"If cross-department collaboration is needed, coordinate via messages and tasks",
],
},
};
export function renderWakeReason(
reason: string,
vars: WakeReasonVars,
): string {
const entry = WAKE_REASONS[reason as WakeReason];
if (!entry) {
return `Trigger: ${reason}\nAction required: Check your standup briefing and messages for context on why you were woken.`;
}
const steps = entry.steps(vars)
.map((step, i) => `${i + 1}. ${step}`)
.join("\n");
return `${entry.title}\nAction required:\n${steps}`;
}