mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 13:26:10 +00:00
fix(mcp): isolate optional observation adapter failures (#838)
This commit is contained in:
1 parent
78f4848d70
commit
be3cfbffdf
31 files changed
+741
-102
No files matched your search
@@ -1,4 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import type {
|
||||
OptionalProviderLoadFailures,
|
||||
OptionalProviderLoadFailure,
|
||||
} from "./OptionalObservationProviders.js";
|
||||
|
||||
import {
|
||||
providerCapability,
|
||||
@@ -28,6 +32,7 @@ type ToolAvailabilityReason = "available" | ToolUnavailabilityReason;
|
||||
type ProviderDescriptor = ProviderCapability;
|
||||
export type AvailabilityPolicy = {
|
||||
readonly processCaptureEnabled: boolean;
|
||||
readonly optionalProviderLoadFailures?: OptionalProviderLoadFailures;
|
||||
readonly firmwareInspectionEnabled?: boolean;
|
||||
readonly firmwareExtractionEnabled?: boolean;
|
||||
readonly androidAnalysisEnabled?: boolean;
|
||||
@@ -186,6 +191,12 @@ const availabilityFor = (context: AvailabilityContext): Availability => {
|
||||
return navigationContextAvailability(context.descriptors);
|
||||
const javascriptApplication = javascriptApplicationAvailability(context);
|
||||
if (javascriptApplication !== null) return javascriptApplication;
|
||||
const failure = optionalProviderFailureFor(context);
|
||||
if (failure !== undefined)
|
||||
return {
|
||||
reason: "provider_unavailable",
|
||||
remediation: `Adapter ${failure.providerId} could not load: ${failure.reason}. Repair the adapter installation and restart REA; other capabilities remain available.`,
|
||||
};
|
||||
const workflowAvailability = workflowAvailabilityFor(context);
|
||||
if (workflowAvailability !== null) return workflowAvailability;
|
||||
const targetDecision = targetAvailability(context);
|
||||
@@ -193,6 +204,23 @@ const availabilityFor = (context: AvailabilityContext): Availability => {
|
||||
return providerAvailability(context);
|
||||
};
|
||||
|
||||
const optionalProviderFailureFor = ({
|
||||
name,
|
||||
kind,
|
||||
policy,
|
||||
}: AvailabilityContext): OptionalProviderLoadFailure | undefined => {
|
||||
const failures = policy.optionalProviderLoadFailures;
|
||||
if (name === "capture_browser_scenario")
|
||||
return failures?.browserScenarioCapture;
|
||||
if (kind === "browser-provider") return failures?.browserObservation;
|
||||
if (name === "capture_electron_scenario")
|
||||
return failures?.electronActiveObservation;
|
||||
if (kind === "electron-provider") return failures?.electronObservation;
|
||||
if (kind === "runtime-provider")
|
||||
return failures?.javascriptRuntimeObservation;
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const javascriptApplicationAvailability = ({
|
||||
name,
|
||||
}: AvailabilityContext): Availability | null => {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { BrowserObservationPort } from "./BrowserObservationPort.js";
|
||||
import type { BrowserScenarioCapturePort } from "./BrowserScenarioCapturePort.js";
|
||||
import type { ElectronObservationPort } from "./ElectronObservationPort.js";
|
||||
import type { ElectronActiveObservationPort } from "./ElectronActiveObservationPort.js";
|
||||
import type { JavaScriptRuntimeObservationPort } from "./JavaScriptRuntimeObservationPort.js";
|
||||
import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
|
||||
|
||||
/** Existing observation ports loaded independently at MCP startup. */
|
||||
export interface OptionalObservationProviders {
|
||||
readonly browserObservation?: BrowserObservationPort;
|
||||
readonly browserScenarioCapture?: BrowserScenarioCapturePort;
|
||||
readonly electronObservation?: ElectronObservationPort;
|
||||
readonly electronActiveObservation?: ElectronActiveObservationPort;
|
||||
readonly javascriptRuntimeObservation?: JavaScriptRuntimeObservationPort;
|
||||
}
|
||||
|
||||
/** A module failed before its port could be constructed; no engine was opened. */
|
||||
export interface OptionalProviderLoadFailure {
|
||||
readonly providerId: string;
|
||||
readonly reason: string;
|
||||
}
|
||||
|
||||
export type OptionalProviderLoadFailures = Readonly<
|
||||
Partial<
|
||||
Record<keyof OptionalObservationProviders, OptionalProviderLoadFailure>
|
||||
>
|
||||
>;
|
||||
|
||||
/** Successful ports and failed peers from one independent loading attempt. */
|
||||
export interface OptionalProviderLoadResult extends OptionalObservationProviders {
|
||||
readonly optionalProviderLoadFailures?: OptionalProviderLoadFailures;
|
||||
}
|
||||
|
||||
/** Preserve the module's failure reason through the existing tool error algebra. */
|
||||
export const optionalProviderUnavailable = (
|
||||
failure: OptionalProviderLoadFailure,
|
||||
operation: string,
|
||||
): AnalysisCapabilityUnavailableError =>
|
||||
new AnalysisCapabilityUnavailableError(
|
||||
failure.providerId,
|
||||
operation,
|
||||
`Adapter could not load: ${failure.reason}`,
|
||||
);
|
||||
Reference in new issue
Block a user