Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 55 additions & 5 deletions src/always-on/runtime/DiscoveryFire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Gateway, GatewayChannelKey, GatewayEvent } from "../../gateway/ind
import { getPilotProjectChatDir } from "../../pilot/paths.js";
import { buildChatDigest } from "../context/ChatDigestBuilder.js";
import type { AlwaysOnConfig } from "../config/parseAlwaysOnConfig.js";
import { buildFallbackReport, type ReportMetadata } from "../contracts/ReportContract.js";
import { buildFallbackReport, parseReportMarkdown, type ReportMetadata } from "../contracts/ReportContract.js";
import { AlwaysOnError } from "../protocol/errors.js";
import type {
AlwaysOnDiscoveryOutcome,
Expand Down Expand Up @@ -458,24 +458,44 @@ export class DiscoveryFire {
};
this.deps.runContexts.register(reportCtx);

let reportEvents: GatewayEvent[] = [];
let reportError: { code?: string; message: string } | undefined;
try {
const events = await this.drainTurn({
reportEvents = await this.drainTurn({
sessionKey: reportSessionKey,
channelKey: REPORT_CHANNEL,
runId: `${runId}.report`,
message: buildReportPrompt({ plan: planRecord, planMarkdown, workspaceCwd: workspace.cwd, workspaceStrategy: workspace.strategy, language: this.deps.config.language }),
mode: "bypassPermissions",
persistEvents: true,
});
reportError = pickFirstError(events);
reportError = pickFirstError(reportEvents);
} finally {
this.deps.runContexts.unregister(reportSessionKey);
this.deps.sessionOverrides.delete(reportSessionKey);
await this.deps.gateway.closeSession({ sessionKey: reportSessionKey, reason: "always-on/done" }).catch(() => undefined);
}

const finishedAt = this.deps.now();

if (!reportCtx.report && !reportError) {
const assistantText = extractAssistantText(reportEvents);
if (assistantText) {
const metadata: ReportMetadata = {
runId,
planId,
startedAt: startedAt.toISOString(),
finishedAt: finishedAt.toISOString(),
outcome: "executed",
workspaceStrategy: workspace.strategy === "git-worktree" ? "git-worktree" : "snapshot-copy",
workspaceHandle: workspace.cwd,
};
const parsed = parseReportMarkdown(assistantText, metadata);
const filePath = await this.deps.reportStore.writeReport(runId, parsed.rawContent);
reportCtx.report = { markdown: parsed.rawContent, filePath, finishedAt };
}
}

const outcome: AlwaysOnDiscoveryOutcome = reportCtx.report && !reportError ? "executed" : "failed";

if (reportCtx.report && !reportError) {
Expand Down Expand Up @@ -801,9 +821,10 @@ export class DiscoveryFire {
};
this.deps.runContexts.register(reportCtx);

let reportEvents: GatewayEvent[] = [];
let reportError: { code?: string; message: string } | undefined;
try {
const events = await this.drainTurn({
reportEvents = await this.drainTurn({
sessionKey: reportSessionKey,
channelKey: REPORT_CHANNEL,
runId: `${runId}.report`,
Expand All @@ -817,7 +838,7 @@ export class DiscoveryFire {
mode: "bypassPermissions",
persistEvents: true,
});
reportError = pickFirstError(events);
reportError = pickFirstError(reportEvents);
} finally {
this.deps.runContexts.unregister(reportSessionKey);
this.deps.sessionOverrides.delete(reportSessionKey);
Expand All @@ -827,6 +848,25 @@ export class DiscoveryFire {
}

const finishedAt = this.deps.now();

if (!reportCtx.report && !reportError) {
const assistantText = extractAssistantText(reportEvents);
if (assistantText) {
const metadata: ReportMetadata = {
runId,
planId: planRecord.id,
startedAt: startedAt.toISOString(),
finishedAt: finishedAt.toISOString(),
outcome: "executed",
workspaceStrategy: workspace.strategy === "git-worktree" ? "git-worktree" : "snapshot-copy",
workspaceHandle: workspace.cwd,
};
const parsed = parseReportMarkdown(assistantText, metadata);
const filePath = await this.deps.reportStore.writeReport(runId, parsed.rawContent);
reportCtx.report = { markdown: parsed.rawContent, filePath, finishedAt };
}
}

const outcome: AlwaysOnDiscoveryOutcome = reportCtx.report && !reportError ? "executed" : "failed";

if (reportCtx.report && !reportError) {
Expand Down Expand Up @@ -1116,3 +1156,13 @@ function pickFirstError(events: GatewayEvent[]): { code?: string; message: strin
}
return undefined;
}

function extractAssistantText(events: GatewayEvent[]): string {
let text = "";
for (const event of events) {
if (event.type === "assistant_text_delta") {
text += event.text;
}
}
return text.trim();
Comment on lines +1160 to +1167
}