diff --git a/src/main/api-server/routes-agents-standup.ts b/src/main/api-server/routes-agents-standup.ts index 35731ac3..cf0c8526 100644 --- a/src/main/api-server/routes-agents-standup.ts +++ b/src/main/api-server/routes-agents-standup.ts @@ -49,6 +49,23 @@ export function registerAgentStandupRoute(server: AgentApiServer): void { ? new Map(db.listAgentNamesByIds(token.companyId, Array.from(senderIds)).map((row) => [row.id, row.name])) : new Map(); + // Recent outputs the AGENT itself produced — closes the + // trust-but-verify loop. Without this view the model could + // narrate "I wrote the spec doc" in its assistant text without + // ever calling the persistence API, and we'd never catch it. + // Filter scope: documents the agent authored, work_products on + // any task the agent has worked on (assigned tasks). Taskless + // run outputs are intentionally out of scope here — the smaller + // surface keeps the briefing readable. + const RECENT_OUTPUT_LIMIT = 20; + const myTaskIds = new Set(myTasks.map((t) => t.id)); + const recentDocuments = db.listDocuments(token.companyId) + .filter((doc) => doc.authorAgentId === token.agentId) + .slice(0, RECENT_OUTPUT_LIMIT); + const recentWorkProducts = db.listWorkProductsForCompany(token.companyId) + .filter((wp) => wp.taskId !== null && myTaskIds.has(wp.taskId)) + .slice(0, RECENT_OUTPUT_LIMIT); + const reportNameMap = new Map(directReports.map((a) => [a.id, a.name])); const taskTitleMap = new Map([ ...myTasks.map<[string, string]>((t) => [t.id, t.title]), @@ -80,6 +97,26 @@ export function registerAgentStandupRoute(server: AgentApiServer): void { parentMessageId: m.parentMessageId, createdAt: m.createdAt, })), + recentDocuments: recentDocuments.map((d) => ({ + id: d.id, + type: d.type, + title: d.title, + status: d.status, + version: d.version, + updatedAt: d.updatedAt, + })), + recentWorkProducts: recentWorkProducts.map((wp) => ({ + id: wp.id, + type: wp.type, + provider: wp.provider, + title: wp.title, + externalId: wp.externalId, + url: wp.url, + status: wp.status, + taskId: wp.taskId, + taskTitle: wp.taskId ? (taskTitleMap.get(wp.taskId) ?? "") : "", + updatedAt: wp.updatedAt, + })), tasksAwaitingReview: tasksAwaitingMyReview.map((t) => ({ id: t.id, title: t.title, diff --git a/src/main/database.ts b/src/main/database.ts index bd1a2835..aa0c41a3 100644 --- a/src/main/database.ts +++ b/src/main/database.ts @@ -96,6 +96,7 @@ export class AppDatabase extends AppDatabaseBase { createWorkProduct(input: { companyId: string; taskId: string | null; projectId?: string | null; workspaceId?: string | null; type: string; provider: string; externalId?: string | null; title: string; url?: string | null; status?: string; reviewState?: string; isPrimary?: boolean; summary?: string | null; metadataJson?: string | null; createdByRunId?: string | null }) { return this.documentsMod.createWorkProduct(input); } updateWorkProduct(id: string, companyId: string, patch: Parameters["updateWorkProduct"]>[2]) { return this.documentsMod.updateWorkProduct(id, companyId, patch); } listWorkProductsForTask(taskId: string, companyId: string) { return this.documentsMod.listWorkProductsForTask(taskId, companyId); } + listWorkProductsForCompany(companyId: string, limit?: number) { return this.documentsMod.listWorkProductsForCompany(companyId, limit); } findWorkProductByExternalId(companyId: string, provider: string, externalId: string, workspaceId: string | null) { return this.documentsMod.findWorkProductByExternalId(companyId, provider, externalId, workspaceId); } resolveWorkProductTarget(workProductId: string, companyId: string) { return this.documentsMod.resolveWorkProductTarget(workProductId, companyId); } deleteWorkProduct(id: string, companyId: string) { return this.documentsMod.deleteWorkProduct(id, companyId); }