Codemod db pass-through calls: messages + runs + approvals + company (C1 part 2/3)

Rewrite ~376 call sites for messages, runs, approvalsMod, and company
domains and delete the corresponding pass-through methods on
AppDatabase / AppDatabaseBase. Structural type references
(ReturnType<HandlerDeps["db"]["getRun"]>) and SweepStaleReviewsDeps-style
mocks are updated to route through the owning sub-module.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-20 13:20:15 -04:00
1 parent 5e9b7acbc6
commit a69fbb053b
86 files changed
+393 -454

No files matched your search

+1 -1
View File
@@ -45,7 +45,7 @@ export class CostWriter {
);
}
this.deps.db.recordCostEntry({
this.deps.db.runs.recordCostEntry({
runId: input.runId,
companyId: input.companyId,
agentId: input.agentId,
+1 -1
View File
@@ -134,7 +134,7 @@ function checkOperationalApprovalBlock(
toolName: string,
): BeforeToolCallRpcResult {
try {
const blocking = deps.db.getBlockingApproval(ctx.companyId, ctx.agentId, ctx.taskId);
const blocking = deps.db.approvalsMod.getBlockingApproval(ctx.companyId, ctx.agentId, ctx.taskId);
if (!blocking) return { block: false, reason: null };
if (!OPERATIONAL_APPROVAL_TYPES.has(blocking.type as ApprovalType)) {
return { block: false, reason: null };
+1 -1
View File
@@ -573,7 +573,7 @@ export class RuntimeBridge {
// `?unreadOnly=true`, so agents posted status comments instead of
// replies. The explicit read endpoint is the sole signal.
const store = this.getOrCreateStore(payload.taskSessionId);
const inboxRecords = this.deps.db.listAgentInboxUnread(payload.companyId, payload.agentId);
const inboxRecords = this.deps.db.messages.listAgentInboxUnread(payload.companyId, payload.agentId);
if (inboxRecords.length > 0) {
this.deps.db.withTransaction(() => {
for (const record of inboxRecords) {
+2 -2
View File
@@ -31,7 +31,7 @@ export function registerAgentControlRoutes(server: AgentApiServer) {
});
const parsed = wakeSchema.safeParse(body);
const reason = parsed.success ? parsed.data.reason : "peer_request";
const alreadyActive = db.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId });
const alreadyActive = db.runs.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId });
const runId = onWakeAgent(targetAgentId, token.companyId, reason);
if (runId) {
server.json(res, 200, { ok: true, runId, message: `Wake started for agent ${targetAgentId}` });
@@ -65,7 +65,7 @@ export function registerAgentControlRoutes(server: AgentApiServer) {
server.json(res, 403, { error: "Current agent is not allowed to trigger heartbeat for this agent" });
return;
}
const alreadyActive = db.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId });
const alreadyActive = db.runs.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId });
const runId = onWakeAgent(targetAgentId, token.companyId, "peer_request");
if (runId) {
server.json(res, 200, { ok: true, runId, message: `Heartbeat triggered for agent ${targetAgentId}` });
+3 -3
View File
@@ -35,15 +35,15 @@ export function registerAgentStandupRoute(server: AgentApiServer): void {
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
const recentComments = db.listRecentTaskComments([...allRelevantTaskIds], twoHoursAgo, 20);
const myPendingApprovals = db.listAgentPendingApprovals(token.companyId, token.agentId);
const myResolvedApprovals = db.listAgentResolvedApprovals(token.companyId, token.agentId, 5);
const myPendingApprovals = db.approvalsMod.listAgentPendingApprovals(token.companyId, token.agentId);
const myResolvedApprovals = db.approvalsMod.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 unreadInbox = db.messages.listAgentInboxUnread(token.companyId, token.agentId);
const senderIds = new Set(unreadInbox.map((m) => m.fromAgentId));
const senderNames = senderIds.size > 0
? new Map(db.agents.listAgentNamesByIds(token.companyId, Array.from(senderIds)).map((row) => [row.id, row.name]))
+3 -3
View File
@@ -29,7 +29,7 @@ export function registerAgentRoutes(server: AgentApiServer) {
// and the standup module is registered separately in api-server/index.ts.
server.addRoute("GET", "/api/agents/me/metrics", (_req, res, _params, token) => {
const companyMetrics = db.getCompanyMetrics(token.companyId, 30);
const companyMetrics = db.company.getCompanyMetrics(token.companyId, 30);
const agentMetric = companyMetrics.agentMetrics.find(m => m.agentId === token.agentId);
if (!agentMetric) {
server.json(res, 404, { error: "Metrics not found" });
@@ -45,7 +45,7 @@ export function registerAgentRoutes(server: AgentApiServer) {
server.json(res, 404, { error: "Agent not found" });
return;
}
const companyMetrics = db.getCompanyMetrics(token.companyId, 30);
const companyMetrics = db.company.getCompanyMetrics(token.companyId, 30);
const agentMetric = companyMetrics.agentMetrics.find((metric) => metric.agentId === agentId);
if (!agentMetric) {
server.json(res, 404, { error: "Metrics not found" });
@@ -190,7 +190,7 @@ export function registerAgentRoutes(server: AgentApiServer) {
return;
}
// Also check pending hire approvals with the same name to prevent concurrent duplicate requests
const pendingHires = db.listPendingHireApprovalPayloads(companyId);
const pendingHires = db.approvalsMod.listPendingHireApprovalPayloads(companyId);
for (const pending of pendingHires) {
try {
const payload = pending.payloadJson ? JSON.parse(pending.payloadJson) as Record<string, unknown> : {};
+15 -15
View File
@@ -48,7 +48,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
// Reject the request at the API boundary so the model cannot
// circumvent the ordering by resubmitting.
if (input.type === "approve_ceo_strategy") {
const companyHireApprovals = db.listCompanyApprovalsByType(companyId, "hire_agent");
const companyHireApprovals = db.approvalsMod.listCompanyApprovalsByType(companyId, "hire_agent");
if (companyHireApprovals.length === 0) {
server.json(res, 409, {
error: "approve_ceo_strategy requires at least one hire_agent approval to exist first. Submit the intended hires, then file the strategy.",
@@ -56,7 +56,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
});
return;
}
const existingStrategy = db.listCompanyApprovalsByType(companyId, "approve_ceo_strategy")
const existingStrategy = db.approvalsMod.listCompanyApprovalsByType(companyId, "approve_ceo_strategy")
.find((a) => a.state === "pending" || a.state === "approved");
if (existingStrategy) {
server.json(res, 409, {
@@ -70,7 +70,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
let id: string;
try {
id = db.requestApproval({
id = db.approvalsMod.requestApproval({
companyId,
type: input.type,
relatedTaskId: input.relatedTaskId ?? null,
@@ -139,7 +139,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
return;
}
const statuses = parsedQuery.data.status?.split(",").filter(Boolean) ?? null;
const approvals = db.listApprovalsForApi(companyId, {
const approvals = db.approvalsMod.listApprovalsForApi(companyId, {
requestedByAgentId: parsedQuery.data.requestedByAgentId,
relatedTaskId: parsedQuery.data.relatedTaskId,
statuses,
@@ -148,7 +148,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
});
server.addRoute("GET", "/api/approvals/:approvalId", (_req, res, params, token) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
const approval = db.approvalsMod.findApprovalById(requireParam(params, "approvalId"));
if (!approval || approval.companyId !== token.companyId) {
server.json(res, 404, { error: "Approval not found" });
return;
@@ -162,21 +162,21 @@ export function registerApprovalRoutes(server: AgentApiServer) {
server.addRoute("GET", "/api/approvals/:approvalId/comments", (_req, res, params, token) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
const approval = db.approvalsMod.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const comments = db.listApprovalComments(approvalId, approval.companyId);
const comments = db.approvalsMod.listApprovalComments(approvalId, approval.companyId);
server.json(res, 200, comments);
});
server.addRoute("POST", "/api/approvals/:approvalId/comments", (_req, res, params, token, body) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
const approval = db.approvalsMod.findApprovalById(requireParam(params, "approvalId"));
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const data = body as Record<string, unknown>;
const commentBody = typeof data.body === "string" ? data.body.trim() : "";
if (!commentBody) { server.json(res, 400, { error: "Comment body is required" }); return; }
const commentId = db.addApprovalComment({
const commentId = db.approvalsMod.addApprovalComment({
companyId: approval.companyId,
approvalId: approval.id,
authorAgentId: token.agentId ?? null,
@@ -194,7 +194,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
});
server.addRoute("POST", "/api/approvals/:approvalId/resubmit", (_req, res, params, token) => {
const approval = db.findApprovalById(requireParam(params, "approvalId"));
const approval = db.approvalsMod.findApprovalById(requireParam(params, "approvalId"));
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
if (approval.state !== "revision_requested") {
@@ -205,23 +205,23 @@ export function registerApprovalRoutes(server: AgentApiServer) {
server.json(res, 403, { error: "Only the requesting agent can resubmit this approval" });
return;
}
db.resubmitApproval(approval.id, approval.companyId);
db.approvalsMod.resubmitApproval(approval.id, approval.companyId);
onDomainChanged();
server.json(res, 200, { resubmitted: true });
});
server.addRoute("GET", "/api/approvals/:approvalId/tasks", (_req, res, params, token) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
const approval = db.approvalsMod.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const taskIds = db.listTasksForApproval(approvalId);
const taskIds = db.approvalsMod.listTasksForApproval(approvalId);
server.json(res, 200, taskIds);
});
server.addRoute("POST", "/api/approvals/:approvalId/tasks", (_req, res, params, token, body) => {
const approvalId = requireParam(params, "approvalId");
const approval = db.findApprovalById(approvalId);
const approval = db.approvalsMod.findApprovalById(approvalId);
if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; }
if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; }
const data = body as Record<string, unknown>;
@@ -232,7 +232,7 @@ export function registerApprovalRoutes(server: AgentApiServer) {
server.json(res, 400, { error: `Task ${taskId} does not belong to this company` }); return;
}
}
db.linkManyTasksToApproval(approvalId, taskIds, token.companyId, token.agentId ?? null);
db.approvalsMod.linkManyTasksToApproval(approvalId, taskIds, token.companyId, token.agentId ?? null);
onDomainChanged();
server.json(res, 200, { linked: taskIds.length });
});
+4 -4
View File
@@ -142,7 +142,7 @@ export function registerMessageRoutes(server: AgentApiServer) {
return;
}
const messages = db.listAgentMessages(companyId, {
const messages = db.messages.listAgentMessages(companyId, {
agentId: token.agentId,
channel: channelParam ?? undefined,
channelTargetId: channelTargetId && channelTargetId.length > 0 ? channelTargetId : undefined,
@@ -158,12 +158,12 @@ export function registerMessageRoutes(server: AgentApiServer) {
server.json(res, 403, { error: "Company mismatch" });
return;
}
const message = db.getAgentMessage(requireParam(params, "messageId"), companyId);
const message = db.messages.getAgentMessage(requireParam(params, "messageId"), companyId);
if (!message) {
server.json(res, 404, { error: "Message not found" });
return;
}
const visibleToAgent = db.listAgentMessages(companyId, {
const visibleToAgent = db.messages.listAgentMessages(companyId, {
agentId: token.agentId,
messageId: message.id,
limit: 1,
@@ -172,7 +172,7 @@ export function registerMessageRoutes(server: AgentApiServer) {
server.json(res, 403, { error: "This message is not visible to the current agent" });
return;
}
db.markMessageReadForReader(requireParam(params, "messageId"), companyId, token.agentId);
db.messages.markMessageReadForReader(requireParam(params, "messageId"), companyId, token.agentId);
onDomainChanged();
server.json(res, 200, { ok: true });
});
+2 -2
View File
@@ -42,7 +42,7 @@ export function registerMiscRoutes(server: AgentApiServer) {
const postActions = ["post", "reply", "dm"];
if (account.requireApproval && postActions.includes(input.actionType)) {
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
type: "dangerous_command",
relatedTaskId: null,
@@ -142,7 +142,7 @@ export function registerMiscRoutes(server: AgentApiServer) {
const contentPreview = parsed.data.content.slice(0, 120) + (parsed.data.content.length > 120 ? "..." : "");
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
requestedByAgentId: token.agentId,
type: "social_post",
+3 -3
View File
@@ -16,7 +16,7 @@ function parsePositiveInt(value: string | null, fallback: number) {
}
function resolveAuthorizedRun(server: AgentApiServer, token: TokenPayload, runId: string) {
const runState = server.db.getRunAuthState(runId);
const runState = server.db.runs.getRunAuthState(runId);
if (!runState || runState.companyId !== token.companyId || runState.agentId !== token.agentId) {
return null;
}
@@ -40,7 +40,7 @@ export function registerRunRoutes(server: AgentApiServer) {
const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`);
const offset = parsePositiveInt(url.searchParams.get("offset"), 0);
const limit = Math.min(parsePositiveInt(url.searchParams.get("limit"), DEFAULT_EVENT_LIMIT), MAX_EVENT_LIMIT);
const events = server.db.listRunEvents(runId, token.companyId, { offset, limit });
const events = server.db.runs.listRunEvents(runId, token.companyId, { offset, limit });
server.json(res, 200, { events, nextOffset: offset + events.length });
});
@@ -66,7 +66,7 @@ export function registerRunRoutes(server: AgentApiServer) {
const flushPendingEvents = () => {
while (true) {
const events = server.db.listRunEventsAfter(runId, token.companyId, cursor, SSE_BATCH_LIMIT);
const events = server.db.runs.listRunEventsAfter(runId, token.companyId, cursor, SSE_BATCH_LIMIT);
if (events.length === 0) return;
for (const event of events) {
writeSse(res, "run-event", event);
+1 -1
View File
@@ -136,7 +136,7 @@ export function registerTaskRoutes(server: AgentApiServer) {
});
const reviewerAgent = db.entityCrud.getAgent(token.agentId);
const docTitles = docs.map((d) => d.title).join(", ");
db.requestApproval({
db.approvalsMod.requestApproval({
companyId: task.companyId,
relatedTaskId: task.id,
requestedByAgentId: token.agentId,
+1 -1
View File
@@ -256,7 +256,7 @@ export function registerWorkGraphRoutes(server: AgentApiServer) {
server.json(res, 403, { error: "Company mismatch" });
return;
}
const { agents, tasks, recentActivity } = db.getDashboardSnapshot(companyId);
const { agents, tasks, recentActivity } = db.company.getDashboardSnapshot(companyId);
const tasksByStatus: Record<string, number> = {};
for (const t of tasks) {
+1 -1
View File
@@ -217,7 +217,7 @@ export class AgentApiServer {
if (typeof claimedRunId !== "string" || claimedRunId.trim() !== token.runId) {
return { ok: false, status: 401, error: "Missing or mismatched X-Agent-Company-Run-Id header" };
}
const runState = this._db.getRunAuthState(token.runId);
const runState = this._db.runs.getRunAuthState(token.runId);
if (!runState || runState.companyId !== token.companyId || runState.agentId !== token.agentId) {
return { ok: false, status: 403, error: "Token references an unknown or mismatched run" };
}
+1 -1
View File
@@ -20,7 +20,7 @@ export function resolveApprovalDecision({
actor?: string;
}) {
const note = decisionNote ?? "";
db.decideApproval({
db.approvalsMod.decideApproval({
companyId,
approvalId,
state,
+2 -2
View File
@@ -208,7 +208,7 @@ export function executeAutomationAction(
}
case "create_approval": {
const approvalType = (config.approvalType as string) ?? "document_review";
db.requestApproval({
db.approvalsMod.requestApproval({
companyId: ctx.companyId,
relatedTaskId: ctx.taskId ?? null,
requestedByAgentId: ctx.agentId ?? null,
@@ -340,7 +340,7 @@ export function executeAutomationAction(
(approval) => approval.companyId === ctx.companyId && approval.state === "pending",
);
for (const approval of pendingApprovals.slice(0, 5)) {
db.decideApproval({
db.approvalsMod.decideApproval({
companyId: ctx.companyId,
approvalId: approval.id,
state: "approved",
@@ -181,7 +181,7 @@ function createDeliverableReviewApproval(
): string {
const { db, logger, publishDomainChanged, notify } = deps;
const docTitles = docs.map((d) => d.title).join(", ");
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
relatedTaskId: taskId,
requestedByAgentId: agentId,
@@ -232,9 +232,9 @@ function decideTerminalStatus(
companyId: string,
): "in_review" | "done" {
if (agent.reportsTo !== null) return "in_review";
const mode = db.getCompanyExecutionMode(companyId);
const mode = db.company.getCompanyExecutionMode(companyId);
if (mode !== "ai_ceo") return "in_review";
const settings = db.getCompanyApprovalSettings(companyId);
const settings = db.company.getCompanyApprovalSettings(companyId);
return settings?.reviewDeliverables ? "in_review" : "done";
}
+1 -1
View File
@@ -160,7 +160,7 @@ export async function runWorkflowPipeline(
const { config, ctx } = buildWorkflowActionContext(companyId, step, actor);
if (step.requiresApproval) {
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
requestedByAgentId: actor?.id ?? null,
relatedTaskId: ctx.taskId ?? null,
@@ -21,7 +21,7 @@ export function emitCrashRecoveryNotification(deps: RecoverInterruptedTasksDeps)
const interruptedCount = deps.db.lastInterruptedCount;
if (interruptedCount <= 0) return;
deps.logger.warn(`[bootstrap] Detected ${interruptedCount} interrupted runs from previous session. Sending recovery notification.`);
const interruptedRuns = deps.db.getInterruptedRunsForRecovery();
const interruptedRuns = deps.db.runs.getInterruptedRunsForRecovery();
if (interruptedRuns.length === 0) return;
deps.emitEvent({ type: "recovery-needed", interruptedRuns });
deps.notify({
+2 -2
View File
@@ -27,9 +27,9 @@ export function createBrowserActionService({
* missing. Isolates the "approval row disappeared" case so the caller does
* not need to nest a try/catch around the state machine.
*/
function getApprovalOrNull(approvalId: string): ReturnType<typeof db.getApprovalRecord> | null {
function getApprovalOrNull(approvalId: string): ReturnType<typeof db.approvalsMod.getApprovalRecord> | null {
try {
return db.getApprovalRecord(approvalId);
return db.approvalsMod.getApprovalRecord(approvalId);
} catch (err) {
const classified = classifyUnknownError(err, {
kind: "recoverable",
+4 -4
View File
@@ -27,7 +27,7 @@ interface CheckpointDeps {
}
export function getCompanyExecutionMode(db: AppDatabase, companyId: string): ExecutionMode {
return db.getCompanyExecutionMode(companyId) as ExecutionMode;
return db.company.getCompanyExecutionMode(companyId) as ExecutionMode;
}
export function createCheckpointEngine(deps: CheckpointDeps) {
@@ -60,7 +60,7 @@ export function createCheckpointEngine(deps: CheckpointDeps) {
// the moment delegation starts.
if (task.parentId) return null;
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
relatedTaskId: taskId,
requestedByAgentId: agentId,
@@ -107,7 +107,7 @@ export function createCheckpointEngine(deps: CheckpointDeps) {
? "strategy_review"
: "draft_review";
const approvalId = db.requestApproval({
const approvalId = db.approvalsMod.requestApproval({
companyId,
relatedTaskId: taskId,
requestedByAgentId: authorAgentId,
@@ -154,7 +154,7 @@ export function createCheckpointEngine(deps: CheckpointDeps) {
}
// Check for pending approvals related to this agent's tasks
return db.hasPendingReviewApprovalForAgent(companyId, agentId);
return db.approvalsMod.hasPendingReviewApprovalForAgent(companyId, agentId);
} catch (err) {
logger.error(`[checkpoint] shouldPauseHeartbeat failed: ${err instanceof Error ? err.message : String(err)}`);
return false;
-56
View File
@@ -250,19 +250,6 @@ export class AppDatabaseBase {
listSnapshot(options: { companyId?: string | null } = {}): ProfileSnapshot { return this.snap.listSnapshot(options); }
listRendererSnapshot(): ProfileSnapshot { return this.snap.listRendererSnapshot(); }
// ─── Company ───────────────────────────────────────────────────────────────
saveCompany(input: { id?: string | null; name: string; description: string; status: string; autoApproveHires?: boolean; reviewDeliverables?: boolean; executionMode?: string }) { return this.company.saveCompany(input); }
deleteCompany(id: string) { return this.company.deleteCompany(id); }
getCompanyStatus(companyId: string) { return this.company.getCompanyStatus(companyId); }
getCompanyBasic(companyId: string) { return this.company.getCompanyBasic(companyId); }
getCompanyExecutionMode(companyId: string) { return this.company.getCompanyExecutionMode(companyId); }
getCompanyApprovalSettings(companyId: string) { return this.company.getCompanyApprovalSettings(companyId); }
listActiveCompanyIds() { return this.company.listActiveCompanyIds(); }
getCompanyMetrics(companyId: string, days: number = 30) { return this.company.getCompanyMetrics(companyId, days); }
getStandupReport(companyId: string) { return this.company.getStandupReport(companyId); }
getDashboardSnapshot(companyId: string) { return this.company.getDashboardSnapshot(companyId); }
// ─── Connectors ────────────────────────────────────────────────────────────
saveConnector(input: { id: ConnectorId; model: string | null; envBindingText: string; notes: string }) { this.connectorsCrud.saveConnector(input); }
@@ -270,49 +257,6 @@ export class AppDatabaseBase {
getConnector(id: ConnectorId) { return this.connectorsCrud.getConnector(id); }
findConnector(id: ConnectorId) { return this.connectorsCrud.findConnector(id); }
// ─── Runs ──────────────────────────────────────────────────────────────────
getRun(id: string) { return this.runs.getRun(id); }
getRunAuthState(runId: string) { return this.runs.getRunAuthState(runId); }
createRun(input: { id?: string; companyId: string; taskId: string | null; agentId: string; workspaceId: string | null; connectorId: ConnectorId }) { return this.runs.createRun(input); }
appendRunLog(runId: string, stream: "stdout" | "stderr", chunk: string) { return this.runs.appendRunLog(runId, stream, chunk); }
readRunLog(runId: string) { return this.runs.readRunLog(runId); }
readRunLogChunk(runId: string, offset = 0, limit = 65_536) { return this.runs.readRunLogChunk(runId, offset, limit); }
markRunStatus(runId: string, status: RunStatus, message: string) { return this.runs.markRunStatus(runId, status, message); }
finishRun(input: { runId: string; status: RunStatus; summary: string | null; errorMessage: string | null; exitCode: number | null; signal: string | null; model: string | null; unattributedCost: boolean }) { return this.runs.finishRun(input); }
recordCostEntry(input: { runId: string; companyId: string; agentId: string; taskId: string | null; connectorId: string; amountUsd: number | null; unattributed: boolean }) { return this.runs.recordCostEntry(input); }
hasActiveRun(filter: { companyId: string; taskId?: string; agentId?: string }) { return this.runs.hasActiveRun(filter); }
listQueuedRuns() { return this.runs.listQueuedRuns(); }
getInterruptedRunsForRecovery() { return this.runs.getInterruptedRunsForRecovery(); }
appendRunEvent(input: { companyId: string; runId: string; agentId: string; eventType: string; stream?: string | null; level?: string | null; message?: string | null; payload?: Record<string, unknown> | null }) { return this.runs.appendRunEvent(input); }
listRunEvents(runId: string, companyId: string, opts?: { offset?: number; limit?: number }) { return this.runs.listRunEvents(runId, companyId, opts); }
listRunEventsAfter(runId: string, companyId: string, afterSeq: number, limit: number) { return this.runs.listRunEventsAfter(runId, companyId, afterSeq, limit); }
updateRunActor(runId: string, actorType: string, actorId: string | null) { return this.runs.updateRunActor(runId, actorType, actorId); }
// ─── Approvals ─────────────────────────────────────────────────────────────
requestApproval(input: { companyId: string; relatedTaskId?: string | null; requestedByAgentId?: string | null; relatedAgentId?: string | null; type: string; payloadSummary: string; impactSummary: string; payloadJson?: string | null }) { return this.approvalsMod.requestApproval(input); }
decideApproval(input: { companyId?: string | null; approvalId: string; state: string; decisionNote: string }) { return this.approvalsMod.decideApproval(input); }
getApprovalRecord(id: string) { return this.approvalsMod.getApprovalRecord(id); }
findApprovalById(id: string) { return this.approvalsMod.findApprovalById(id); }
deleteApproval(id: string, companyId: string) { this.approvalsMod.deleteApproval(id, companyId); }
getBlockingApproval(companyId: string, agentId: string, taskId: string | null) { return this.approvalsMod.getBlockingApproval(companyId, agentId, taskId); }
resubmitApproval(approvalId: string, companyId: string) { this.approvalsMod.resubmitApproval(approvalId, companyId); }
addApprovalComment(input: { companyId: string; approvalId: string; authorAgentId?: string | null; authorUserId?: string | null; body: string }) { return this.approvalsMod.addApprovalComment(input); }
listApprovalComments(approvalId: string, companyId: string) { return this.approvalsMod.listApprovalComments(approvalId, companyId); }
linkTaskToApproval(taskId: string, approvalId: string, companyId: string, linkedByAgentId?: string | null) { this.approvalsMod.linkTaskToApproval(taskId, approvalId, companyId, linkedByAgentId); }
unlinkTaskFromApproval(taskId: string, approvalId: string) { this.approvalsMod.unlinkTaskFromApproval(taskId, approvalId); }
listApprovalsForTask(taskId: string) { return this.approvalsMod.listApprovalsForTask(taskId); }
listTasksForApproval(approvalId: string) { return this.approvalsMod.listTasksForApproval(approvalId); }
linkManyTasksToApproval(approvalId: string, taskIds: string[], companyId: string, linkedByAgentId?: string | null) { this.approvalsMod.linkManyTasksToApproval(approvalId, taskIds, companyId, linkedByAgentId); }
listAgentPendingApprovals(companyId: string, agentId: string) { return this.approvalsMod.listAgentPendingApprovals(companyId, agentId); }
listAgentResolvedApprovals(companyId: string, agentId: string, limit?: number) { return this.approvalsMod.listAgentResolvedApprovals(companyId, agentId, limit); }
listPendingHireApprovalPayloads(companyId: string) { return this.approvalsMod.listPendingHireApprovalPayloads(companyId); }
listApprovalsForApi(companyId: string, filters: { requestedByAgentId?: string; relatedTaskId?: string; statuses?: string[] | null }) { return this.approvalsMod.listApprovalsForApi(companyId, filters); }
findPendingApprovalForTask(companyId: string, taskId: string) { return this.approvalsMod.findPendingApprovalForTask(companyId, taskId); }
hasPendingReviewApprovalForAgent(companyId: string, agentId: string) { return this.approvalsMod.hasPendingReviewApprovalForAgent(companyId, agentId); }
listCompanyApprovalsByType(companyId: string, type: string) { return this.approvalsMod.listCompanyApprovalsByType(companyId, type); }
// ─── Workspaces ────────────────────────────────────────────────────────────
saveWorkspace(input: { id?: string | null; companyId: string; name: string; localPath: string; repoUrl: string; repoRef: string; projectId?: string | null; isPrimary: boolean }) { return this.workspacesMod.saveWorkspace(input); }
-9
View File
@@ -12,15 +12,6 @@ export class AppDatabase extends AppDatabaseBase {
listComments(taskId: string) { return this.activityMod.listComments(taskId); }
// ─── Messages ──────────────────────────────────────────────────────────────
sendAgentMessage(input: { companyId: string; fromAgentId: string; toAgentId?: string | null; channel?: string; channelTargetId?: string | null; subject: string; body: string; priority?: string; parentMessageId?: string | null; attachmentsJson?: string; senderKind?: "agent" | "human" | "system"; mentionedAgentIds?: readonly string[] }) { return this.messages.sendAgentMessage(input); }
getAgentMessage(messageId: string, companyId: string) { return this.messages.getAgentMessage(messageId, companyId); }
listAgentMessages(companyId: string, opts?: { agentId?: string; messageId?: string; channel?: string; channelTargetId?: string | null; unreadOnly?: boolean; limit?: number }) { return this.messages.listAgentMessages(companyId, opts); }
searchMessages(companyId: string, query: string, opts?: { channel?: string; channelTargetId?: string | null; limit?: number }) { return this.messages.searchMessages(companyId, query, opts); }
markMessageReadForReader(messageId: string, companyId: string, readerAgentId?: string | null) { return this.messages.markMessageReadForReader(messageId, companyId, readerAgentId); }
listAgentInboxUnread(companyId: string, agentId: string) { return this.messages.listAgentInboxUnread(companyId, agentId); }
// ─── Social & Browser Actions ──────────────────────────────────────────────
saveSocialAccount(input: { id?: string | null; companyId: string; platform: string; accountName: string; displayName?: string; profileUrl?: string; credentialSecretId?: string | null; status?: string; requireApproval?: boolean; metadataJson?: string }) { return this.social.saveSocialAccount(input); }
+4 -4
View File
@@ -164,7 +164,7 @@ function deriveTaskIdFromRun(
): string | null {
if (!runId) return null;
try {
const run = db.getRun(runId);
const run = db.runs.getRun(runId);
if (run.companyId !== companyId) return null;
return run.taskId ?? null;
} catch (error) {
@@ -187,12 +187,12 @@ function maybeRaiseDeliverableReviewApproval(
documentId: string,
taskId: string | null,
): string | null {
const companySettings = deps.db.getCompanyApprovalSettings(input.companyId);
const companySettings = deps.db.company.getCompanyApprovalSettings(input.companyId);
if (!companySettings?.reviewDeliverables) return null;
if (deps.db.getCompanyExecutionMode(input.companyId) === "ai_cofounder") return null;
if (deps.db.company.getCompanyExecutionMode(input.companyId) === "ai_cofounder") return null;
if (deps.db.tasks.hasPendingDeliverableReviews(input.companyId)) return null;
const approvalId = deps.db.requestApproval({
const approvalId = deps.db.approvalsMod.requestApproval({
companyId: input.companyId,
relatedTaskId: taskId,
requestedByAgentId: input.authorAgentId ?? "",
+2 -2
View File
@@ -54,7 +54,7 @@ export function shouldAutoApprove(
companyId: string,
approvalType: string,
): boolean {
const rawMode = db.getCompanyExecutionMode(companyId);
const rawMode = db.company.getCompanyExecutionMode(companyId);
assertExecutionMode(rawMode);
const mode = rawMode;
@@ -68,7 +68,7 @@ export function shouldAutoApprove(
return false;
}
const settings = db.getCompanyApprovalSettings(companyId);
const settings = db.company.getCompanyApprovalSettings(companyId);
if (!settings?.autoApproveHires) return false;
// When reviewDeliverables is ON, CEO strategy needs human review
+4 -4
View File
@@ -56,7 +56,7 @@ export function registerAgentCoordinationHandlers({
const parsed = markMessageReadSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
const message = db.getAgentMessage(parsed.messageId, parsed.companyId);
const message = db.messages.getAgentMessage(parsed.messageId, parsed.companyId);
if (!message) {
return fail("MESSAGE_NOT_FOUND", "Message not found in the current company.");
}
@@ -64,7 +64,7 @@ export function registerAgentCoordinationHandlers({
return fail("INVALID_COMPANY_REFERENCE", "The selected message reader does not belong to the current company.");
}
if (parsed.readerAgentId) {
const visibleToReader = db
const visibleToReader = db.messages
.listAgentMessages(parsed.companyId, {
agentId: parsed.readerAgentId,
messageId: parsed.messageId,
@@ -75,7 +75,7 @@ export function registerAgentCoordinationHandlers({
return fail("MESSAGE_NOT_VISIBLE", "This message is not visible to the selected reader.");
}
}
db.markMessageReadForReader(parsed.messageId, parsed.companyId, parsed.readerAgentId ?? null);
db.messages.markMessageReadForReader(parsed.messageId, parsed.companyId, parsed.readerAgentId ?? null);
publishDomainChanged();
return ok(true);
});
@@ -84,7 +84,7 @@ export function registerAgentCoordinationHandlers({
const parsed = searchMessagesSchema.parse(payload);
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
return ok(db.searchMessages(parsed.companyId, parsed.query, {
return ok(db.messages.searchMessages(parsed.companyId, parsed.query, {
channel: parsed.channel,
channelTargetId: parsed.channelTargetId,
limit: parsed.limit,
+4 -4
View File
@@ -46,11 +46,11 @@ export function registerCoreAdminHandlers({
>) {
registerHandle(IPC_CHANNELS.saveCompany, async (_event, payload) => {
const parsed = companyInputSchema.parse(payload);
const previousMode = parsed.id ? db.getCompanyExecutionMode(parsed.id) : parsed.executionMode;
const previousMode = parsed.id ? db.company.getCompanyExecutionMode(parsed.id) : parsed.executionMode;
const previousApprovalSettings = parsed.id
? db.getCompanyApprovalSettings(parsed.id)
? db.company.getCompanyApprovalSettings(parsed.id)
: { autoApproveHires: parsed.autoApproveHires, reviewDeliverables: parsed.reviewDeliverables };
const id = db.saveCompany(parsed);
const id = db.company.saveCompany(parsed);
reconcileExecutionModeChange({
db,
companyId: id,
@@ -159,7 +159,7 @@ export function registerCoreAdminHandlers({
if (!db.hasCompany(companyId)) {
return fail("COMPANY_NOT_FOUND", "Company not found.");
}
db.deleteCompany(companyId);
db.company.deleteCompany(companyId);
publishDomainChanged();
return ok(true);
});
+2 -2
View File
@@ -298,14 +298,14 @@ export function registerCoreAgentGraphHandlers({
if (!db.belongsToCompany("approvals", parsed.id, parsed.companyId)) {
return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company.");
}
const approval = db.getApprovalRecord(parsed.id);
const approval = db.approvalsMod.getApprovalRecord(parsed.id);
if (approval.state === "pending" && approval.type === "hire_agent") {
return fail(
"APPROVAL_DELETE_BLOCKED",
"Pending hire approvals cannot be deleted. Reject the hire request instead so the linked agent record stays consistent.",
);
}
db.deleteApproval(parsed.id, parsed.companyId);
db.approvalsMod.deleteApproval(parsed.id, parsed.companyId);
db.addActivity({
companyId: parsed.companyId,
actor: "board",
+4 -4
View File
@@ -56,7 +56,7 @@ export function registerCoreOperationHandlers({
}
let id: string;
try {
id = db.requestApproval(parsed);
id = db.approvalsMod.requestApproval(parsed);
} catch (error) {
return fail("APPROVAL_INVALID", error instanceof Error ? error.message : "Approval could not be created.");
}
@@ -109,7 +109,7 @@ export function registerCoreOperationHandlers({
if (!db.belongsToCompany("approvals", parsed.approvalId, parsed.companyId)) {
return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company.");
}
const approval = db.getApprovalRecord(parsed.approvalId);
const approval = db.approvalsMod.getApprovalRecord(parsed.approvalId);
if (!approval || approval.companyId !== parsed.companyId) {
return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company.");
}
@@ -154,7 +154,7 @@ export function registerCoreOperationHandlers({
if (!db.belongsToCompany("runs", parsed.runId, parsed.companyId)) {
return fail("RUN_NOT_FOUND", "Run not found in the current company.");
}
return ok(db.readRunLog(parsed.runId));
return ok(db.runs.readRunLog(parsed.runId));
});
registerHandle(IPC_CHANNELS.getRunLogChunk, (_event, payload) => {
@@ -164,7 +164,7 @@ export function registerCoreOperationHandlers({
if (!db.belongsToCompany("runs", parsed.runId, parsed.companyId)) {
return fail("RUN_NOT_FOUND", "Run not found in the current company.");
}
return ok(db.readRunLogChunk(parsed.runId, parsed.offset, parsed.limit));
return ok(db.runs.readRunLogChunk(parsed.runId, parsed.offset, parsed.limit));
});
registerHandle(IPC_CHANNELS.addComment, async (_event, payload) => {
+4 -4
View File
@@ -149,14 +149,14 @@ export function registerCoreReadHandlers({
const input = metricsQuerySchema.parse(payload);
const err = ensureCompanyExists(input.companyId);
if (err) return err;
return ok(db.getCompanyMetrics(input.companyId, input.days));
return ok(db.company.getCompanyMetrics(input.companyId, input.days));
});
registerHandle(IPC_CHANNELS.getStandupReport, (_event, payload) => {
const companyId = z.string().uuid().parse(payload);
const err = ensureCompanyExists(companyId);
if (err) return err;
return ok(db.getStandupReport(companyId));
return ok(db.company.getStandupReport(companyId));
});
// --- Entity getters for granular IPC updates ---
@@ -194,7 +194,7 @@ export function registerCoreReadHandlers({
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const run = db.getRun(parsed.id);
const run = db.runs.getRun(parsed.id);
if (run.companyId !== parsed.companyId) return fail("RUN_NOT_FOUND", "Run not found in current company.");
return ok(run);
} catch (err) {
@@ -208,7 +208,7 @@ export function registerCoreReadHandlers({
const companyError = ensureCompanyExists(parsed.companyId);
if (companyError) return companyError;
try {
const approval = db.getApprovalRecord(parsed.id);
const approval = db.approvalsMod.getApprovalRecord(parsed.id);
if (approval.companyId !== parsed.companyId) return fail("APPROVAL_NOT_FOUND", "Approval not found in current company.");
return ok(approval);
} catch (err) {
+3 -3
View File
@@ -184,7 +184,7 @@ export function validateAgentMessageInput(
}
if (input.parentMessageId) {
const parentMessage = db.getAgentMessage(input.parentMessageId, input.companyId);
const parentMessage = db.messages.getAgentMessage(input.parentMessageId, input.companyId);
if (!parentMessage) {
return {
code: "PARENT_MESSAGE_NOT_FOUND",
@@ -317,8 +317,8 @@ export function dispatchAgentMessage(
const persistedMessage = normalized.channel === "direct"
? { ...normalized, senderKind, mentionedAgentIds }
: { ...normalized, toAgentId: null, senderKind, mentionedAgentIds };
const id = deps.db.sendAgentMessage(persistedMessage);
const message = deps.db.getAgentMessage(id, normalized.companyId);
const id = deps.db.messages.sendAgentMessage(persistedMessage);
const message = deps.db.messages.getAgentMessage(id, normalized.companyId);
if (message && deps.emitEvent) {
deps.emitEvent({ type: "new-message", message });
}
+1 -1
View File
@@ -220,7 +220,7 @@ export function createOnboardingService({
const connectors = db.listSnapshot({ companyId: null }).connectors;
const selectedConnectorId = resolveOnboardingConnector(connectors, input.connectorId);
const companyId = db.saveCompany({
const companyId = db.company.saveCompany({
name: input.companyName.trim(),
description: input.companyDescription.trim(),
status: "active",
+6 -6
View File
@@ -66,7 +66,7 @@ export function createHeartbeat(
const isMessageWake = trigger === "message";
const isCommunicationWake = isMessageWake || trigger === "peer_request";
if (!hasWorkerReady()) return SKIPPED("worker_not_ready");
const companyStatus = db.getCompanyStatus(companyId);
const companyStatus = db.company.getCompanyStatus(companyId);
if (companyStatus !== "active") return SKIPPED("company_inactive");
const agent = db.entityCrud.getAgent(agentId);
if (agent.companyId !== companyId) {
@@ -131,8 +131,8 @@ export function createHeartbeat(
}
if (db.agents.isAgentPendingApproval(agentId)) return SKIPPED("pending_approval");
const companyMode = db.getCompanyExecutionMode(companyId);
const approvalSettings = db.getCompanyApprovalSettings(companyId);
const companyMode = db.company.getCompanyExecutionMode(companyId);
const approvalSettings = db.company.getCompanyApprovalSettings(companyId);
const shouldEnforceHumanReview =
companyMode === "ai_cofounder" || approvalSettings?.reviewDeliverables === true;
@@ -207,7 +207,7 @@ export function createHeartbeat(
`[heartbeat] Workspace resolution for ${agent.name}: task.workspaceId=${task?.workspaceId ?? "null"}, agent.workspaceId=${agent.workspaceId ?? "null"}, projectId=${task?.projectId ?? "null"}, source=${workspaceResolution.source}, mode=${workspaceResolution.lockMode}, resolved=${workspace?.name ?? "NONE"}, localPath=${workspace?.localPath ?? "NONE"}`,
);
const run = db.createRun({
const run = db.runs.createRun({
id: runId,
companyId,
taskId: task?.id ?? null,
@@ -216,7 +216,7 @@ export function createHeartbeat(
connectorId: connector.id,
});
const companyBasic = db.getCompanyBasic(companyId);
const companyBasic = db.company.getCompanyBasic(companyId);
dispatchRunToWorker({
runId: run.id,
companyId,
@@ -238,7 +238,7 @@ export function createHeartbeat(
try {
const actorType = trigger === "timer" || trigger === "bootstrap" ? "system" : "agent";
const actorId = trigger === "timer" || trigger === "bootstrap" ? null : trigger;
db.updateRunActor(run.id, actorType, actorId);
db.runs.updateRunActor(run.id, actorType, actorId);
} catch (error) {
logger.warn(
`[heartbeat] updateRunActor failed for run ${run.id}: ${error instanceof Error ? error.message : String(error)}`,
+1 -1
View File
@@ -8,7 +8,7 @@ export function createOrchestrationService(deps: OrchestrationDependencies) {
const { db } = deps;
function hasActiveRun(filter: { taskId?: string; agentId?: string; companyId: string }) {
return db.hasActiveRun(filter);
return db.runs.hasActiveRun(filter);
}
const runDispatch = createRunDispatch(deps);
+1 -1
View File
@@ -44,7 +44,7 @@ export function resolveInitialUserTurn(
}
if (trigger === "message" || trigger === "peer_request") {
const unread = deps.db.listAgentInboxUnread(companyId, agentId);
const unread = deps.db.messages.listAgentInboxUnread(companyId, agentId);
if (unread.length > 0) {
return buildCommunicationTurn(trigger, unread, deps.db);
}
+1 -1
View File
@@ -83,7 +83,7 @@ export function createRunDispatch(deps: OrchestrationDependencies) {
params.workspace &&
!db.claimWorkspaceLock(params.workspace.id, params.runId)
) {
db.finishRun({
db.runs.finishRun({
runId: params.runId,
status: "cancelled",
summary: null,
@@ -67,7 +67,7 @@ export function createHeartbeatScheduler(
try {
if (isQuitting() || !hasWorkerReady()) return;
const activeCompanies = db.listActiveCompanyIds();
const activeCompanies = db.company.listActiveCompanyIds();
const now = Date.now();
for (const company of activeCompanies) {
@@ -27,7 +27,7 @@ export function createHousekeepingScheduler(
try {
if (isQuitting() || !hasWorkerReady()) return;
const activeCompanies = db.listActiveCompanyIds();
const activeCompanies = db.company.listActiveCompanyIds();
for (const company of activeCompanies) {
try {
@@ -52,7 +52,7 @@ export function createHousekeepingScheduler(
dispatchAgentMessage,
resolveApprovalDecision,
notify,
getCompanyExecutionMode: (cId: string) => db.getCompanyExecutionMode(cId),
getCompanyExecutionMode: (cId: string) => db.company.getCompanyExecutionMode(cId),
handleTaskStatusChange: (taskId: string, cId: string, previousStatus: string, newStatus: string) => {
deps.dispatchAutomation("task_status_changed", { companyId: cId, taskId, previousStatus, newStatus });
publishDomainChanged();
@@ -12,7 +12,7 @@ export function createIdleAutomationScheduler(deps: OrchestrationDependencies) {
try {
if (isQuitting() || !hasWorkerReady()) return;
const activeCompanies = db.listActiveCompanyIds();
const activeCompanies = db.company.listActiveCompanyIds();
const now = Date.now();
for (const company of activeCompanies) {
+6 -6
View File
@@ -38,7 +38,7 @@ export function createTaskRunner(
return fail("WORKER_UNAVAILABLE", "Orchestration worker is not ready.");
}
const task = db.entityCrud.getTask(taskId);
const companyStatus = db.getCompanyStatus(task.companyId);
const companyStatus = db.company.getCompanyStatus(task.companyId);
if (companyStatus !== "active") {
return fail("COMPANY_NOT_ACTIVE", "Runs can only start while the company is active.");
}
@@ -78,7 +78,7 @@ export function createTaskRunner(
if (db.agents.isAgentPendingApproval(agent.id)) {
return fail("AGENT_PENDING_APPROVAL", "This agent is pending hire approval and cannot run tasks.");
}
const blockingApproval = db.getBlockingApproval(task.companyId, agent.id, task.id);
const blockingApproval = db.approvalsMod.getBlockingApproval(task.companyId, agent.id, task.id);
if (blockingApproval) {
return fail(
"APPROVAL_GATE_BLOCKED",
@@ -99,7 +99,7 @@ export function createTaskRunner(
return fail("WORKSPACE_COMPANY_MISMATCH", "The selected workspace does not belong to the task company.");
}
const run = db.createRun({
const run = db.runs.createRun({
id: runId,
companyId: task.companyId,
taskId: task.id,
@@ -108,7 +108,7 @@ export function createTaskRunner(
connectorId: connector.id,
});
const companyBasic = db.getCompanyBasic(task.companyId);
const companyBasic = db.company.getCompanyBasic(task.companyId);
dispatchRunToWorker({
runId: run.id,
companyId: task.companyId,
@@ -163,7 +163,7 @@ export function createTaskRunner(
const snapshot = db.listSnapshot();
const companiesById = new Map(snapshot.companies.map((company) => [company.id, company]));
for (const run of db.listQueuedRuns()) {
for (const run of db.runs.listQueuedRuns()) {
const company = companiesById.get(run.companyId);
if (!company || company.status !== "active") {
continue;
@@ -186,7 +186,7 @@ export function createTaskRunner(
const eligibilityFailure = getRunEligibilityFailure(agent, connector, task?.projectId ?? null);
if (eligibilityFailure) {
if (eligibilityFailure === "CONNECTOR_MODEL_NOT_ALLOWED") {
db.finishRun({
db.runs.finishRun({
runId: run.id,
status: "failed",
summary: "Queued run rejected during recovery because the agent model is disabled or invalid for its connector.",
+2 -2
View File
@@ -288,7 +288,7 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
task,
companyName,
locale: snapshot.locale,
executionMode: db.getCompanyExecutionMode(companyId) as ExecutionMode,
executionMode: db.company.getCompanyExecutionMode(companyId) as ExecutionMode,
goals: snapshot.goals.filter((goal) => goal.companyId === companyId),
projects: snapshot.projects.filter((project) => project.companyId === companyId),
directReports: db.agents.getDirectReports(agent.id, companyId),
@@ -354,7 +354,7 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
systemPrompt,
trigger,
taskSessionId: taskSessionId ?? runId,
executionMode: db.getCompanyExecutionMode(companyId) as "ai_ceo" | "ai_cofounder",
executionMode: db.company.getCompanyExecutionMode(companyId) as "ai_ceo" | "ai_cofounder",
initialUserTurn,
};
}
+1 -1
View File
@@ -214,7 +214,7 @@ export function sweepStaleReviews(
const chain = deps.db.agents.getChainOfCommand(reviewer.id);
const escalationTarget = chain.length > 0 ? chain[0] : null;
const pendingApproval = deps.db.findPendingApprovalForTask(companyId, task.id);
const pendingApproval = deps.db.approvalsMod.findPendingApprovalForTask(companyId, task.id);
// In ai_cofounder mode, ALL approvals require human decision — never auto-advance.
if (isCofounderMode && pendingApproval) {
+4 -4
View File
@@ -69,7 +69,7 @@ export function createThreadIntegration({ db, logger, emitEvent, publishDomainCh
// In co-founder mode, set wait state when task enters review
if (newStatus === "in_review") {
const mode = db.getCompanyExecutionMode(companyId) as ExecutionMode;
const mode = db.company.getCompanyExecutionMode(companyId) as ExecutionMode;
if (mode === "ai_cofounder") {
const reason = `@Board review needed: Task "${task.title}" is ready for your review.`;
db.setThreadWaitState({
@@ -104,7 +104,7 @@ export function createThreadIntegration({ db, logger, emitEvent, publishDomainCh
*/
onApprovalCreated(approvalId: string, companyId: string, taskId: string | null, approvalType: string, summary: string): void {
try {
const approval = db.getApprovalRecord(approvalId);
const approval = db.approvalsMod.getApprovalRecord(approvalId);
const task = taskId ? db.entityCrud.getTask(taskId) : null;
const thread = task
? ensureTaskThread(db, task.id, companyId, task.title)
@@ -127,7 +127,7 @@ export function createThreadIntegration({ db, logger, emitEvent, publishDomainCh
db.subscribe({ threadId: thread.id, subscriberId: "user", subscriberType: "user" });
// In co-founder mode, set wait state for user approval
const mode = db.getCompanyExecutionMode(companyId) as ExecutionMode;
const mode = db.company.getCompanyExecutionMode(companyId) as ExecutionMode;
if (mode === "ai_cofounder") {
const approvalReason = `@Board approval needed: ${approvalType}`;
db.setThreadWaitState({
@@ -247,7 +247,7 @@ export function createThreadIntegration({ db, logger, emitEvent, publishDomainCh
// In co-founder mode, successful runs create a user_reply wait state
// so the heartbeat pauses until the human reviews the output
if (status === "succeeded") {
const mode = db.getCompanyExecutionMode(companyId) as ExecutionMode;
const mode = db.company.getCompanyExecutionMode(companyId) as ExecutionMode;
if (mode === "ai_cofounder") {
const task = db.entityCrud.getTask(taskId);
const completionReason = `@Board review needed: Agent completed work on "${task.title}" — awaiting your review.`;
@@ -150,7 +150,7 @@ export function announceApprovalToBoard(
);
if (!target) return;
const messageId = db.sendAgentMessage({
const messageId = db.messages.sendAgentMessage({
companyId: approval.companyId,
fromAgentId: approval.requestedByAgentId,
channel: target.channel,
@@ -160,7 +160,7 @@ export function announceApprovalToBoard(
priority: "urgent",
senderKind: "agent",
});
const message = db.getAgentMessage(messageId, approval.companyId);
const message = db.messages.getAgentMessage(messageId, approval.companyId);
if (message) {
deps.emitEvent({ type: "new-message", message });
}
+1 -1
View File
@@ -183,7 +183,7 @@ export function createWorkerService({
const snapshot = db.listSnapshot();
for (const run of snapshot.runs) {
if (run.status === "running" || run.status === "queued") {
db.finishRun({
db.runs.finishRun({
runId: run.id,
status: "interrupted",
summary: "Application shut down.",
+2 -2
View File
@@ -33,7 +33,7 @@ export function handleWorkerExit(
for (const run of snapshot.runs) {
if (run.status === "running") {
db.finishRun({
db.runs.finishRun({
runId: run.id,
status: "interrupted",
summary: "Worker process crashed.",
@@ -119,7 +119,7 @@ export function handleWorkerExit(
});
} catch (error) {
logger.warn(`[worker] Failed to re-enqueue run ${candidate.id}: ${error instanceof Error ? error.message : String(error)}`);
db.finishRun({
db.runs.finishRun({
runId: candidate.id,
status: "interrupted",
summary: "Could not re-enqueue after worker restart.",
@@ -6,13 +6,13 @@ import type { workerMessageSchema } from "../entry/types";
import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context";
type RunFinishedEvent = Extract<WorkerMessageEvent, { type: "run-finished" }>;
type RunRecord = ReturnType<HandlerDeps["db"]["getRun"]>;
type RunRecord = ReturnType<HandlerDeps["db"]["runs"]["getRun"]>;
type TaskRecord = ReturnType<HandlerDeps["db"]["entityCrud"]["getTask"]>;
export interface RunFinishedContext {
run: RunRecord;
task: TaskRecord | null;
runOutcome: ReturnType<HandlerDeps["db"]["finishRun"]>;
runOutcome: ReturnType<HandlerDeps["db"]["runs"]["finishRun"]>;
}
export function finalizeRun(
@@ -25,7 +25,7 @@ export function finalizeRun(
let run: RunRecord;
try {
run = db.getRun(event.runId);
run = db.runs.getRun(event.runId);
} catch (error) {
logger.warn(
`[finalizeRun] getRun(${event.runId}) failed; run may have been deleted: ${error instanceof Error ? error.message : String(error)}`,
@@ -66,7 +66,7 @@ export function finalizeRun(
}
leaseRenewalMap.delete(event.runId);
const runOutcome = db.finishRun(event);
const runOutcome = db.runs.finishRun(event);
if (run.workspaceId) {
db.releaseWorkspaceLock(run.workspaceId, run.id);
}
@@ -350,7 +350,7 @@ function hasUnfinishedTeamBuilding(
if (activeReports.length > 0) return false;
const goalCount = db.countActiveGoalsForCompany(companyId);
if (goalCount === 0) return false;
const pendingHires = db
const pendingHires = db.approvalsMod
.listCompanyApprovalsByType(companyId, "hire_agent")
.filter((a) => a.state === "pending");
return pendingHires.length === 0;
+3 -3
View File
@@ -16,8 +16,8 @@ export async function handleRunLog(
const filtered = filterRunLogChunk(event.stream, event.chunk);
if (filtered === null) return;
await db.appendRunLog(event.runId, event.stream, filtered);
const runState = db.getRunAuthState(event.runId);
await db.runs.appendRunLog(event.runId, event.stream, filtered);
const runState = db.runs.getRunAuthState(event.runId);
if (runState) {
persistRunEvent(db, logger, {
companyId: runState.companyId,
@@ -36,7 +36,7 @@ export async function handleRunLog(
const lastRenewal = leaseRenewalMap.get(event.runId) ?? 0;
if (now - lastRenewal >= LEASE_RENEWAL_INTERVAL_MS) {
try {
const run = db.getRun(event.runId);
const run = db.runs.getRun(event.runId);
if (run.taskId) {
db.tasks.renewTaskLease(run.taskId, run.id);
}
@@ -9,8 +9,8 @@ export function handleRunStatus(
): void {
const { db, logger, emitEvent, onRunStarted } = deps;
const runState = db.getRunAuthState(event.runId);
db.markRunStatus(event.runId, event.status, event.message);
const runState = db.runs.getRunAuthState(event.runId);
db.runs.markRunStatus(event.runId, event.status, event.message);
if (runState) {
persistRunEvent(db, logger, {
companyId: runState.companyId,
@@ -30,7 +30,7 @@ export function handleRunStatus(
// dispatchRunToWorker before enqueue. Only lease renewal and
// run-started housekeeping run here.
try {
const run = db.getRun(event.runId);
const run = db.runs.getRun(event.runId);
if (run.taskId) {
db.tasks.renewTaskLease(run.taskId, run.id);
}
@@ -22,7 +22,7 @@ export function persistRunEvent(
input: PersistInput,
) {
try {
db.appendRunEvent(input);
db.runs.appendRunEvent(input);
} catch (error) {
logger.warn(
`[run-events] Failed to append ${input.eventType} for ${input.runId}: ${