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:
1 parent
75022f82c5
commit
d75389c418
2 files changed
+153
-89
No files matched your search
@@ -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`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
Reference in new issue
Block a user