Surface unread inbox in the standup briefing
Pre-fix the agent had to make a second `?unreadOnly=true` API call after standup to see what peers and managers had said. The model frequently skipped that second call — the standup briefing already covered "what's happening" so it felt complete — and the prompt told the agent to "respond to ALL unread messages" against an empty list. Result: one-way CEO chatter, employees posting heartbeat status comments instead of replying. The standup endpoint now returns `unreadMessages` (with sender display name, channel, subject, body preview, priority, parent message id, createdAt) and a `summary.unreadMessages` count. The IC and CEO operating prompts no longer ask for a separate API call — they walk the standup field directly and explicitly require both a real reply AND a mark-read POST. The CEO prompt also adds a cross-check against `recentDocuments` / `recentWorkProducts` so the "I wrote X" narration without persistence pattern stops sliding by.
This commit is contained in:
1 parent
f30ec740d8
commit
4eaad1f91a
3 files changed
+30
-5
No files matched your search
@@ -38,6 +38,17 @@ export function registerAgentStandupRoute(server: AgentApiServer): void {
|
|||||||
const myPendingApprovals = db.listAgentPendingApprovals(token.companyId, token.agentId);
|
const myPendingApprovals = db.listAgentPendingApprovals(token.companyId, token.agentId);
|
||||||
const myResolvedApprovals = db.listAgentResolvedApprovals(token.companyId, token.agentId, 5);
|
const myResolvedApprovals = db.listAgentResolvedApprovals(token.companyId, token.agentId, 5);
|
||||||
|
|
||||||
|
// Unread inbox lives in the standup briefing as the agent's
|
||||||
|
// canonical view of pending communication. Pre-fix the agent had
|
||||||
|
// to make a second API call to /messages?unreadOnly=true that the
|
||||||
|
// model frequently skipped, so messages from peers and managers
|
||||||
|
// sat dark while the agent posted heartbeat status comments.
|
||||||
|
const unreadInbox = db.listAgentInboxUnread(token.companyId, token.agentId);
|
||||||
|
const senderIds = new Set(unreadInbox.map((m) => m.fromAgentId));
|
||||||
|
const senderNames = senderIds.size > 0
|
||||||
|
? new Map(db.listAgentNamesByIds(token.companyId, Array.from(senderIds)).map((row) => [row.id, row.name]))
|
||||||
|
: new Map<string, string>();
|
||||||
|
|
||||||
const reportNameMap = new Map(directReports.map((a) => [a.id, a.name]));
|
const reportNameMap = new Map(directReports.map((a) => [a.id, a.name]));
|
||||||
const taskTitleMap = new Map<string, string>([
|
const taskTitleMap = new Map<string, string>([
|
||||||
...myTasks.map<[string, string]>((t) => [t.id, t.title]),
|
...myTasks.map<[string, string]>((t) => [t.id, t.title]),
|
||||||
@@ -48,6 +59,7 @@ export function registerAgentStandupRoute(server: AgentApiServer): void {
|
|||||||
server.json(res, 200, {
|
server.json(res, 200, {
|
||||||
agent: { id: agent.id, name: agent.name, role: agent.role, status: agent.status },
|
agent: { id: agent.id, name: agent.name, role: agent.role, status: agent.status },
|
||||||
summary: {
|
summary: {
|
||||||
|
unreadMessages: unreadInbox.length,
|
||||||
tasksAwaitingReview: tasksAwaitingMyReview.length,
|
tasksAwaitingReview: tasksAwaitingMyReview.length,
|
||||||
blockedReportTasks: blockedReportTasks.length,
|
blockedReportTasks: blockedReportTasks.length,
|
||||||
myBlockedTasks: myBlockedTasks.length,
|
myBlockedTasks: myBlockedTasks.length,
|
||||||
@@ -56,6 +68,18 @@ export function registerAgentStandupRoute(server: AgentApiServer): void {
|
|||||||
pendingApprovals: myPendingApprovals.length,
|
pendingApprovals: myPendingApprovals.length,
|
||||||
directReports: directReports.length,
|
directReports: directReports.length,
|
||||||
},
|
},
|
||||||
|
unreadMessages: unreadInbox.map((m) => ({
|
||||||
|
id: m.id,
|
||||||
|
from: senderNames.get(m.fromAgentId) ?? m.fromAgentId,
|
||||||
|
fromAgentId: m.fromAgentId,
|
||||||
|
channel: m.channel,
|
||||||
|
channelTargetId: m.channelTargetId,
|
||||||
|
subject: m.subject,
|
||||||
|
bodyPreview: m.body.slice(0, 240),
|
||||||
|
priority: m.priority,
|
||||||
|
parentMessageId: m.parentMessageId,
|
||||||
|
createdAt: m.createdAt,
|
||||||
|
})),
|
||||||
tasksAwaitingReview: tasksAwaitingMyReview.map((t) => ({
|
tasksAwaitingReview: tasksAwaitingMyReview.map((t) => ({
|
||||||
id: t.id,
|
id: t.id,
|
||||||
title: t.title,
|
title: t.title,
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ You are the top executive running a fully automated company. You make real decis
|
|||||||
|
|
||||||
## Priority 1: Standup & Situational Assessment (EVERY wake)
|
## Priority 1: Standup & Situational Assessment (EVERY wake)
|
||||||
Before doing anything else, assess the state of the company:
|
Before doing anything else, assess the state of the company:
|
||||||
1. GET /api/agents/me/standup — get your full briefing in one call
|
1. GET /api/agents/me/standup — your full briefing in ONE call. The response carries `unreadMessages`, `recentDocuments`, and `recentWorkProducts` alongside the existing task / approval / report sections, so you do not need a separate `?unreadOnly=true` request.
|
||||||
2. **CHECK MESSAGES FIRST**: GET /api/companies/{{companyId}}/messages?unreadOnly=true&limit=20 — read and respond to ALL unread messages from your team. Messages from department heads are high priority.
|
2. **MESSAGES FIRST**: walk `unreadMessages` from the standup. For each row, send a real reply (POST /api/companies/{{companyId}}/messages with channel="direct", toAgentId = `fromAgentId`, parentMessageId = `id`) AND mark it read (POST /api/companies/{{companyId}}/messages/{messageId}/read). Status comments do not count as replies. Department-head messages are top priority.
|
||||||
3. GET /api/companies/{{companyId}}/issues?status=in_review — check for work awaiting YOUR review
|
3. GET /api/companies/{{companyId}}/issues?status=in_review — check for work awaiting YOUR review
|
||||||
4. GET /api/companies/{{companyId}}/issues?status=blocked — check for blocked tasks needing escalation
|
4. GET /api/companies/{{companyId}}/issues?status=blocked — check for blocked tasks needing escalation
|
||||||
5. Check your pending approvals for any resolved items
|
5. Check your pending approvals for any resolved items
|
||||||
6. Read recent comments on your owned tasks
|
6. Read recent comments on your owned tasks
|
||||||
7. Assess company health: Are goals progressing? Are teams blocked? Is anyone idle?
|
7. Cross-check `recentDocuments` and `recentWorkProducts`: if a task says "I wrote X" but X is not in either list, the persistence call was missed — re-do the POST before reporting completion.
|
||||||
|
8. Assess company health: Are goals progressing? Are teams blocked? Is anyone idle?
|
||||||
|
|
||||||
If there are NO active goals, this is your top priority — create strategic goals:
|
If there are NO active goals, this is your top priority — create strategic goals:
|
||||||
curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/goals" \
|
curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/goals" \
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ export function icInstructions(companyId: string, agentId: string): string[] {
|
|||||||
You are an individual contributor — a skilled specialist in an automated company. You do real work and take real actions via the API. Follow these SOPs:
|
You are an individual contributor — a skilled specialist in an automated company. You do real work and take real actions via the API. Follow these SOPs:
|
||||||
|
|
||||||
## Priority 1: Check for Feedback & New Assignments (EVERY wake — SOP-001)
|
## Priority 1: Check for Feedback & New Assignments (EVERY wake — SOP-001)
|
||||||
1. GET /api/agents/me/standup — get your full briefing
|
1. GET /api/agents/me/standup — get your full briefing in ONE call. The response includes \`unreadMessages\`, \`recentDocuments\`, \`recentWorkProducts\`, and every other state you need to plan this turn.
|
||||||
2. **CHECK MESSAGES FIRST**: GET /api/companies/${companyId}/messages?unreadOnly=true&limit=20 — read and respond to ALL unread messages. If a colleague or manager needs something from you, prioritize it.
|
2. **MESSAGES FIRST**: walk \`unreadMessages\` from the standup. For each row, post a real reply (POST /api/companies/${companyId}/messages with channel="direct", toAgentId set to that row's \`fromAgentId\`, parentMessageId set to that row's \`id\`) AND mark it read (POST /api/companies/${companyId}/messages/{messageId}/read). Status comments do not count as replies.
|
||||||
3. Read ALL new comments on your assigned tasks (GET /api/issues/{issueId}/comments)
|
3. Read ALL new comments on your assigned tasks (GET /api/issues/{issueId}/comments)
|
||||||
4. If your manager has set a task back to "in_progress": read their feedback and address it FIRST
|
4. If your manager has set a task back to "in_progress": read their feedback and address it FIRST
|
||||||
5. If there are new comments with questions: respond promptly via POST /api/issues/{issueId}/comments
|
5. If there are new comments with questions: respond promptly via POST /api/issues/{issueId}/comments
|
||||||
|
|||||||
Reference in new issue
Block a user