update
This commit is contained in:
1 parent
806200b3d1
commit
5547c29491
216 files changed
+5043
-3352
No files matched your search
@@ -2,14 +2,8 @@
|
||||
* Heartbeat task title conventions.
|
||||
*
|
||||
* Heartbeat tasks are synthesized by the orchestrator when an agent wakes with
|
||||
* no actionable work; they carry the `[Heartbeat]` title prefix so the rest of
|
||||
* the system can detect them without a dedicated `kind` column.
|
||||
*
|
||||
* Centralizing the prefix here prevents drift between the writer (heartbeat
|
||||
* dispatch) and readers (automation, escalation, route filters).
|
||||
* no actionable work. The `tasks.is_heartbeat` column is the authoritative
|
||||
* flag; the `[Heartbeat]` title prefix remains only for human-readable display
|
||||
* so existing runs, logs, and UI affordances stay stable.
|
||||
*/
|
||||
export const HEARTBEAT_TASK_TITLE_PREFIX = "[Heartbeat]";
|
||||
|
||||
export function isHeartbeatTaskTitle(title: string | null | undefined): boolean {
|
||||
return !!title && title.startsWith(HEARTBEAT_TASK_TITLE_PREFIX);
|
||||
}
|
||||
@@ -212,7 +212,11 @@ export function createHeartbeat(
|
||||
const actorType = trigger === "timer" || trigger === "bootstrap" ? "system" : "agent";
|
||||
const actorId = trigger === "timer" || trigger === "bootstrap" ? null : trigger;
|
||||
db.updateRunActor(run.id, actorType, actorId);
|
||||
} catch { /* Non-fatal */ }
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`[heartbeat] updateRunActor failed for run ${run.id}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
|
||||
db.addActivity({
|
||||
companyId,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { buildTaskPrompt } from "../prompt-builder";
|
||||
import type { AppDatabase } from "../database";
|
||||
import type { RuntimeSkillEntry } from "../skill-types";
|
||||
import type { ProjectedSkill } from "../skill-types";
|
||||
import type { ConnectorId, ExecutionMode } from "@shared/types";
|
||||
import type { WorkspaceLockMode, EnqueueRunPayload } from "./types";
|
||||
import { normalizeMessagesForPrompt, normalizeCommentsForPrompt } from "../message-normalize";
|
||||
@@ -33,7 +33,7 @@ export interface TurnContextDeps {
|
||||
logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void };
|
||||
getApiPort: () => number;
|
||||
createRunToken: (agentId: string, companyId: string, runId: string) => string;
|
||||
listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => RuntimeSkillEntry[];
|
||||
listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => ProjectedSkill[];
|
||||
getSessionHandoff?: (taskId: string) => string | null;
|
||||
evaluatePreRunSessionRotation?: (taskId: string, connectorId: string) => {
|
||||
rotated: boolean;
|
||||
@@ -109,7 +109,7 @@ function resolveSkills(
|
||||
connectorId: string,
|
||||
agentName: string,
|
||||
deps: Pick<TurnContextDeps, "listRuntimeSkillEntries" | "logger">,
|
||||
): RuntimeSkillEntry[] {
|
||||
): ProjectedSkill[] {
|
||||
try {
|
||||
return deps.listRuntimeSkillEntries(companyId, agentId, connectorId);
|
||||
} catch (err) {
|
||||
@@ -162,13 +162,21 @@ function resolveSession(
|
||||
return { taskSession, sessionHandoff: finalHandoff };
|
||||
}
|
||||
|
||||
function extractThinkingEffort(metadataJson: string | null): string | null {
|
||||
function extractThinkingEffort(
|
||||
metadataJson: string | null,
|
||||
logger: TurnContextDeps["logger"],
|
||||
agentId: string,
|
||||
): string | null {
|
||||
try {
|
||||
const meta = JSON.parse(metadataJson || "{}");
|
||||
if (typeof meta.thinkingEffort === "string" && meta.thinkingEffort) {
|
||||
return meta.thinkingEffort;
|
||||
}
|
||||
} catch { /* malformed metadata */ }
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`[run] malformed agent metadataJson for ${agentId}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -251,13 +259,10 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
|
||||
const assignedTasks = db.listAgentTasks(agent.id, companyId, ["todo", "in_progress", "blocked"]);
|
||||
const reviewTasks = db.listReviewTasksForManager(agent.id, companyId);
|
||||
const recentComments = assembleRecentComments(assignedTasks, reviewTasks, snapshot);
|
||||
let sessionHandoff = resolveSessionHandoff(task.id, deps);
|
||||
const initialHandoff = resolveSessionHandoff(task.id, deps);
|
||||
const { taskSession, sessionHandoff } = resolveSession(db, task, connector.id, initialHandoff, deps);
|
||||
const skills = resolveSkills(companyId, agent.id, connector.id, agent.name, deps);
|
||||
|
||||
const skillNames = skills
|
||||
.map((s) => s.name ?? s.runtimeName)
|
||||
.filter(Boolean);
|
||||
|
||||
const systemPrompt = apiUrl ? buildTaskPrompt({
|
||||
agent,
|
||||
apiUrl,
|
||||
@@ -293,14 +298,7 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
|
||||
recentDocuments: filterRecentDocuments(snapshot.documents, companyId, agent.id),
|
||||
allConnectors: buildConnectorCatalog(db, snapshot.connectors),
|
||||
sessionHandoff,
|
||||
skillNames,
|
||||
skillEntries: skills.map((s) => ({
|
||||
name: s.name ?? s.runtimeName,
|
||||
whenToUse: s.whenToUse,
|
||||
allowedTools: s.allowedTools,
|
||||
effort: s.effort,
|
||||
contextMode: s.contextMode,
|
||||
})),
|
||||
skills,
|
||||
companySkillCatalog: db.listCompanySkills(companyId).map((skill) => ({
|
||||
name: skill.name,
|
||||
slug: skill.slug,
|
||||
@@ -312,12 +310,7 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
|
||||
companyDocuments: snapshot.documents.filter((d) => d.companyId === companyId),
|
||||
}) : null;
|
||||
|
||||
const { taskSession, sessionHandoff: finalHandoff } = resolveSession(db, task, connector.id, sessionHandoff, deps);
|
||||
if (finalHandoff !== sessionHandoff && systemPrompt && finalHandoff) {
|
||||
sessionHandoff = finalHandoff;
|
||||
}
|
||||
|
||||
const thinkingEffort = extractThinkingEffort(agent.metadataJson);
|
||||
const thinkingEffort = extractThinkingEffort(agent.metadataJson, deps.logger, agent.id);
|
||||
const modelSelection = validateConnectorModelSelection(db, connector.id, agent.model);
|
||||
if (!modelSelection.ok) {
|
||||
throw new Error(modelSelection.error);
|
||||
@@ -342,7 +335,6 @@ export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps
|
||||
sessionParams: taskSession.sessionParams,
|
||||
systemPrompt,
|
||||
trigger,
|
||||
managedSkills: skills.map((s) => ({ runtimeName: s.runtimeName, sourcePath: s.sourcePath })),
|
||||
taskSessionId: taskSession.id ?? runId,
|
||||
executionMode: db.getCompanyExecutionMode(companyId) as "ai_ceo" | "ai_cofounder",
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { AppDatabase } from "../database";
|
||||
import type { DesktopEvent } from "@shared/types";
|
||||
import type { NotificationOptions } from "../notification-service";
|
||||
import type { createBudgetEnforcementService } from "../budget-enforcement-service";
|
||||
import type { RuntimeSkillEntry } from "../skill-types";
|
||||
import type { ProjectedSkill } from "../skill-types";
|
||||
|
||||
export type WorkspaceLockMode = "exclusive" | "shared" | "none";
|
||||
|
||||
@@ -43,7 +43,6 @@ export interface EnqueueRunPayload {
|
||||
sessionParams: Record<string, unknown> | null;
|
||||
systemPrompt: string | null;
|
||||
trigger: string | null;
|
||||
managedSkills: Array<{ runtimeName: string; sourcePath: string }>;
|
||||
/** Task session id used by SqliteSessionStore to load/append messages. */
|
||||
taskSessionId: string;
|
||||
/** Execution mode from the owning company. */
|
||||
@@ -67,7 +66,7 @@ export interface OrchestrationDependencies {
|
||||
hasWorkerReady: () => boolean;
|
||||
enqueueWorkerRun: (payload: EnqueueRunPayload) => void;
|
||||
isQuitting: () => boolean;
|
||||
listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => RuntimeSkillEntry[];
|
||||
listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => ProjectedSkill[];
|
||||
budgetService: ReturnType<typeof createBudgetEnforcementService>;
|
||||
/** Checkpoint engine for unified co-founder mode pause decisions. */
|
||||
checkpointEngine?: { shouldPauseHeartbeat: (companyId: string, agentId: string) => boolean };
|
||||
|
||||
Reference in new issue
Block a user