feat(06-02): wire session handoff injection into prompt builder and orchestration dispatch

- Add sessionHandoff field to PromptContext interface and Session Handoff section in buildSystemPrompt
- Add getSessionHandoff dependency to orchestration service, load handoff before prompt build
- Update orchestration to prefer task_sessions table over legacy tasks.session_json (SESS-01)
- Wire getSessionHandoff through ServiceGraph into createOrchestrationService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-26 23:05:16 -04:00
1 parent 5271f7ee5d
commit a1d361b947
3 files changed
+39 -1

No files matched your search

+21 -1
View File
@@ -66,6 +66,7 @@ interface OrchestrationDependencies {
isQuitting: () => boolean;
listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => Array<{ runtimeName: string; sourcePath: string }>;
budgetService: ReturnType<typeof createBudgetEnforcementService>;
getSessionHandoff?: (taskId: string) => string | null;
}
export function createOrchestrationService({
@@ -81,6 +82,7 @@ export function createOrchestrationService({
isQuitting,
listRuntimeSkillEntries,
budgetService,
getSessionHandoff,
}: OrchestrationDependencies) {
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
const scheduleLastFiredMap = new Map<string, number>();
@@ -229,6 +231,16 @@ export function createOrchestrationService({
createdAt: comment.createdAt,
}));
// D-07: Load handoff from previous rotated session
let sessionHandoff: string | null = null;
if (getSessionHandoff) {
try {
sessionHandoff = getSessionHandoff(task.id);
} catch (err) {
logger.warn(`[run] Failed to load session handoff for task ${task.id}: ${err instanceof Error ? err.message : String(err)}`);
}
}
const systemPrompt = apiUrl ? buildTaskPrompt({
agent,
apiUrl,
@@ -280,6 +292,7 @@ export function createOrchestrationService({
.filter((document) => document.companyId === companyId && (document.authorAgentId === agent.id || document.reviewerAgentId === agent.id || document.status === "in_review"))
.slice(0, 5),
allConnectors: snapshot.connectors.map((c) => ({ id: c.id, label: c.label, status: c.status })),
sessionHandoff,
}) : null;
if (apiUrl) {
@@ -292,7 +305,14 @@ export function createOrchestrationService({
env.AGENT_COMPANY_WAKE_REASON = trigger;
}
const taskSession = db.getTaskSession(task.id);
// SESS-01: Prefer task_sessions table, fall back to legacy tasks.session_json
const activeSession = db.getActiveTaskSession(task.id);
const taskSession = activeSession
? {
sessionParams: activeSession.sessionParamsJson ? JSON.parse(activeSession.sessionParamsJson) as Record<string, unknown> : null,
sessionDisplayId: activeSession.sessionDisplayId,
}
: db.getTaskSession(task.id);
let thinkingEffort: string | null = null;
try {
const meta = JSON.parse(agent.metadataJson || "{}");
+11
View File
@@ -31,6 +31,8 @@ interface PromptContext {
activeSprint?: SprintRecord | null;
recentDocuments?: DocumentRecord[];
allConnectors?: Array<{ id: string; label: string; status: string }>;
/** D-07: Handoff markdown from a rotated session, injected as context for the agent */
sessionHandoff?: string | null;
}
export function buildSystemPrompt(ctx: PromptContext): string {
@@ -195,6 +197,15 @@ ${relevantProjects.map((p) => `- [${p.id}] ${p.name}: ${p.description || ""} (st
`);
}
// D-07: Inject handoff context from previous rotated session
if (ctx.sessionHandoff) {
sections.push(`# Session Handoff
The following context was preserved from your previous session on this task:
${ctx.sessionHandoff}
`);
}
if (ctx.task) {
sections.push(`# Current Task
- ID: ${ctx.task.id}
+7
View File
@@ -234,6 +234,13 @@ export function createServiceGraph({
};
})(),
budgetService: getOrCreateBudgetEnforcementService(),
getSessionHandoff: (taskId: string) => {
try {
return getOrCreateSessionManagementService().getHandoffContext(taskId);
} catch {
return null;
}
},
});
workerService.createWorker();