mirror of
https://github.com/morluto/rea.git
synced 2026-10-30 19:35:56 +00:00
feat(browser): retain compact scenario summaries and selected views (#7120)
Retain complete browser scenario Evidence while delivering compact summaries and selected step, event, transaction and text views through shared CLI/MCP workflows. Preserve initial CLI failures across cleanup retries and validate with real Chromium/TodoMVC. Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
19 files changed
+2297
-90
No files matched your search
@@ -1290,6 +1290,7 @@ const registerObservationTools = ({
|
||||
});
|
||||
registerBrowserScenarioTool(server, {
|
||||
...common,
|
||||
evidenceById,
|
||||
provider: options.browserScenarioCapture,
|
||||
loadFailure: options.optionalProviderLoadFailures?.browserScenarioCapture,
|
||||
});
|
||||
|
||||
@@ -1,82 +1,67 @@
|
||||
import type { EvidenceMcpServer } from "./EvidenceMcpServer.js";
|
||||
import type { EvidenceWriter } from "../application/investigation/InvestigationRecordPort.js";
|
||||
import type { EvidenceLookup } from "../application/EvidenceInputResolver.js";
|
||||
import {
|
||||
optionalProviderUnavailable,
|
||||
type OptionalProviderLoadFailure,
|
||||
} from "../application/OptionalObservationProviders.js";
|
||||
import { err } from "../domain/result.js";
|
||||
|
||||
import { browserScenarioSchema } from "../domain/browserScenario.js";
|
||||
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
||||
import type { BrowserScenarioCapturePort } from "../application/BrowserScenarioCapturePort.js";
|
||||
import { captureBrowserScenario } from "../application/BrowserScenarioCaptureService.js";
|
||||
import { toolContract } from "../contracts/toolContracts.js";
|
||||
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
||||
import { browserScenarioSchema } from "../domain/browserScenario.js";
|
||||
import type { Logger } from "pino";
|
||||
import { logToolExecution } from "./toolLogging.js";
|
||||
import { toolRegistrationOptions } from "./toolRegistrationOptions.js";
|
||||
import type { WithAdmittedAnalysis } from "./analysisAdmission.js";
|
||||
import { runAdmittedToolOperation } from "./admittedToolOperation.js";
|
||||
import { deliverEvidenceResult } from "./contractToolHandler.js";
|
||||
import { createRetainedSummaryToolHandler } from "./contractToolHandler.js";
|
||||
|
||||
interface BrowserScenarioToolRegistration {
|
||||
readonly logger: Logger;
|
||||
readonly loadFailure?: OptionalProviderLoadFailure | undefined;
|
||||
readonly provider: BrowserScenarioCapturePort | undefined;
|
||||
readonly recordEvidence: EvidenceWriter["recordEvidence"] | undefined;
|
||||
readonly evidenceById?: EvidenceLookup | undefined;
|
||||
readonly withAdmittedAnalysis?: WithAdmittedAnalysis;
|
||||
}
|
||||
|
||||
/** Register the browser scenario tool with execution-time provider diagnostics. */
|
||||
/** Validate one scenario, then share complete/retained delivery with other analyses. */
|
||||
export const registerBrowserScenarioTool = (
|
||||
server: EvidenceMcpServer,
|
||||
options: BrowserScenarioToolRegistration,
|
||||
): void => {
|
||||
const contract = toolContract("capture_browser_scenario");
|
||||
const handler = createRetainedSummaryToolHandler(
|
||||
server,
|
||||
contract,
|
||||
async (input, execution) => {
|
||||
// The SDK admits the advertised structure. The canonical semantic parser
|
||||
// owns field-path diagnostics, shared with the CLI rather than flattened
|
||||
// into the SDK's pre-handler validation message.
|
||||
const scenario = browserScenarioSchema.safeParse(input);
|
||||
if (!scenario.success)
|
||||
return err(
|
||||
analysisInputErrorFromIssues(
|
||||
contract.name,
|
||||
scenario.error.issues,
|
||||
input,
|
||||
{ cause: scenario.error },
|
||||
),
|
||||
);
|
||||
return options.loadFailure === undefined
|
||||
? captureBrowserScenario(options.provider, scenario.data, execution)
|
||||
: err(optionalProviderUnavailable(options.loadFailure, contract.name));
|
||||
},
|
||||
options.logger,
|
||||
{
|
||||
recordEvidence: options.recordEvidence,
|
||||
evidenceById: options.evidenceById,
|
||||
},
|
||||
options.withAdmittedAnalysis,
|
||||
);
|
||||
server.registerTool(
|
||||
contract.name,
|
||||
toolRegistrationOptions(contract),
|
||||
async (input, context) => {
|
||||
const parsedScenario = browserScenarioSchema.safeParse(input);
|
||||
if (!parsedScenario.success)
|
||||
return server.delivery.toCallToolResult(
|
||||
err(
|
||||
analysisInputErrorFromIssues(
|
||||
contract.name,
|
||||
parsedScenario.error.issues,
|
||||
input,
|
||||
{ cause: parsedScenario.error },
|
||||
),
|
||||
),
|
||||
contract,
|
||||
);
|
||||
const scenario = parsedScenario.data;
|
||||
if (options.loadFailure !== undefined)
|
||||
return server.delivery.toCallToolResult(
|
||||
err(optionalProviderUnavailable(options.loadFailure, contract.name)),
|
||||
contract,
|
||||
);
|
||||
return runAdmittedToolOperation(
|
||||
server,
|
||||
options.withAdmittedAnalysis,
|
||||
contract.name,
|
||||
context.mcpReq.signal,
|
||||
async () => {
|
||||
const result = await logToolExecution(
|
||||
options.logger,
|
||||
contract.name,
|
||||
() =>
|
||||
captureBrowserScenario(options.provider, scenario, {
|
||||
signal: context.mcpReq.signal,
|
||||
}),
|
||||
);
|
||||
return deliverEvidenceResult(
|
||||
server,
|
||||
result,
|
||||
contract,
|
||||
options.recordEvidence,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
handler,
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user