NODEDC_1C/llm_normalizer/backend/src/services/assistantMcpDiscoveryDebugA...

159 lines
7.9 KiB
TypeScript

import type { AssistantMcpDiscoveryRuntimeEntryPointContract } from "./assistantMcpDiscoveryRuntimeEntryPoint";
import type { AssistantMcpRouteCandidateContract } from "./assistantMcpDiscoveryRuntimeBridge";
import type { AssistantEvidencePlannerContract } from "./assistantEvidencePlanner";
export interface AssistantMcpDiscoveryDebugAttachmentFields {
assistant_mcp_discovery_entry_point_v1: AssistantMcpDiscoveryRuntimeEntryPointContract | null;
mcp_discovery_entry_status: string | null;
mcp_discovery_attempted: boolean;
mcp_discovery_hot_runtime_wired: false;
mcp_discovery_bridge_status: string | null;
mcp_discovery_selected_chain_id: string | null;
mcp_discovery_evidence_plan_v1: AssistantEvidencePlannerContract | null;
mcp_discovery_evidence_plan_status: string | null;
mcp_discovery_evidence_plan_answer_mode: string | null;
mcp_discovery_evidence_plan_missing_axes: string[];
mcp_discovery_evidence_plan_expected_coverage: string | null;
mcp_discovery_catalog_chain_template_matches: string[];
mcp_discovery_catalog_chain_alignment_status: string | null;
mcp_discovery_catalog_chain_top_match: string | null;
mcp_discovery_catalog_chain_selected_matches_top: boolean;
mcp_discovery_route_candidate_v1: AssistantMcpRouteCandidateContract | null;
mcp_discovery_route_candidate_status: string | null;
mcp_discovery_route_candidate_fact_family: string | null;
mcp_discovery_route_candidate_action_family: string | null;
mcp_discovery_route_candidate_proof_expectation: string | null;
mcp_discovery_route_candidate_missing_axes: string[];
mcp_discovery_route_candidate_provided_axes: string[];
mcp_discovery_route_candidate_executable_now: boolean;
mcp_discovery_route_candidate_enablement_reason: string | null;
mcp_discovery_route_candidate_next_action: string | null;
mcp_discovery_answer_mode: string | null;
mcp_discovery_business_fact_answer_allowed: boolean;
mcp_discovery_user_facing_response_allowed: boolean;
mcp_discovery_requires_clarification: boolean;
}
export interface AttachAssistantMcpDiscoveryDebugInput {
entryPoint?: unknown;
addressRuntimeMeta?: Record<string, unknown> | null;
}
function toRecordObject(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value as Record<string, unknown>;
}
function toNonEmptyString(value: unknown): string | null {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function toStringArray(value: unknown): string[] {
if (!Array.isArray(value)) {
return [];
}
const result: string[] = [];
for (const item of value) {
const text = toNonEmptyString(item);
if (text && !result.includes(text)) {
result.push(text);
}
}
return result;
}
function isMcpDiscoveryEntryPointContract(value: unknown): value is AssistantMcpDiscoveryRuntimeEntryPointContract {
const record = toRecordObject(value);
return (
record?.schema_version === "assistant_mcp_discovery_runtime_entry_point_v1" &&
record?.policy_owner === "assistantMcpDiscoveryRuntimeEntryPoint"
);
}
function isRouteCandidateContract(value: unknown): value is AssistantMcpRouteCandidateContract {
const record = toRecordObject(value);
return (
record?.schema_version === "assistant_mcp_route_candidate_v1" &&
record?.policy_owner === "assistantMcpDiscoveryRuntimeBridge"
);
}
function isEvidencePlannerContract(value: unknown): value is AssistantEvidencePlannerContract {
const record = toRecordObject(value);
return record?.schema_version === "assistant_evidence_planner_v1" && record?.policy_owner === "assistantEvidencePlanner";
}
function resolveEntryPoint(input: AttachAssistantMcpDiscoveryDebugInput): AssistantMcpDiscoveryRuntimeEntryPointContract | null {
if (isMcpDiscoveryEntryPointContract(input.entryPoint)) {
return input.entryPoint;
}
const runtimeMetaEntryPoint =
input.addressRuntimeMeta?.mcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistantMcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistant_mcp_discovery_entry_point_v1;
return isMcpDiscoveryEntryPointContract(runtimeMetaEntryPoint) ? runtimeMetaEntryPoint : null;
}
export function buildAssistantMcpDiscoveryDebugAttachmentFields(
input: AttachAssistantMcpDiscoveryDebugInput
): AssistantMcpDiscoveryDebugAttachmentFields {
const entryPoint = resolveEntryPoint(input);
const bridge = toRecordObject(entryPoint?.bridge);
const planner = toRecordObject(bridge?.planner);
const evidencePlan = isEvidencePlannerContract(planner?.evidence_plan) ? planner.evidence_plan : null;
const evidencePlanAxes = toRecordObject(evidencePlan?.evidence_axes);
const evidencePlanCoverageGate = toRecordObject(evidencePlan?.coverage_gate);
const evidencePlanAnswerContract = toRecordObject(evidencePlan?.answer_contract);
const chainAlignment = toRecordObject(planner?.catalog_chain_template_alignment);
const routeCandidate = isRouteCandidateContract(bridge?.route_candidate) ? bridge.route_candidate : null;
const answerDraft = toRecordObject(bridge?.answer_draft);
return {
assistant_mcp_discovery_entry_point_v1: entryPoint,
mcp_discovery_entry_status: toNonEmptyString(entryPoint?.entry_status),
mcp_discovery_attempted: Boolean(entryPoint?.discovery_attempted),
mcp_discovery_hot_runtime_wired: false,
mcp_discovery_bridge_status: toNonEmptyString(bridge?.bridge_status),
mcp_discovery_selected_chain_id: toNonEmptyString(planner?.selected_chain_id),
mcp_discovery_evidence_plan_v1: evidencePlan,
mcp_discovery_evidence_plan_status: toNonEmptyString(evidencePlan?.planner_status),
mcp_discovery_evidence_plan_answer_mode: toNonEmptyString(evidencePlanAnswerContract?.answer_mode),
mcp_discovery_evidence_plan_missing_axes: toStringArray(evidencePlanAxes?.missing_axes),
mcp_discovery_evidence_plan_expected_coverage: toNonEmptyString(evidencePlanCoverageGate?.expected_coverage),
mcp_discovery_catalog_chain_template_matches: toStringArray(planner?.catalog_chain_template_matches),
mcp_discovery_catalog_chain_alignment_status: toNonEmptyString(chainAlignment?.alignment_status),
mcp_discovery_catalog_chain_top_match: toNonEmptyString(chainAlignment?.top_chain_template_match),
mcp_discovery_catalog_chain_selected_matches_top: chainAlignment?.selected_chain_matches_top === true,
mcp_discovery_route_candidate_v1: routeCandidate,
mcp_discovery_route_candidate_status: toNonEmptyString(routeCandidate?.candidate_status),
mcp_discovery_route_candidate_fact_family: toNonEmptyString(routeCandidate?.business_fact_family),
mcp_discovery_route_candidate_action_family: toNonEmptyString(routeCandidate?.action_family),
mcp_discovery_route_candidate_proof_expectation: toNonEmptyString(routeCandidate?.proof_expectation),
mcp_discovery_route_candidate_missing_axes: toStringArray(routeCandidate?.missing_axes),
mcp_discovery_route_candidate_provided_axes: toStringArray(routeCandidate?.provided_axes),
mcp_discovery_route_candidate_executable_now: routeCandidate?.executable_now === true,
mcp_discovery_route_candidate_enablement_reason: toNonEmptyString(routeCandidate?.enablement_reason),
mcp_discovery_route_candidate_next_action: toNonEmptyString(routeCandidate?.recommended_next_action),
mcp_discovery_answer_mode: toNonEmptyString(answerDraft?.answer_mode),
mcp_discovery_business_fact_answer_allowed: bridge?.business_fact_answer_allowed === true,
mcp_discovery_user_facing_response_allowed: bridge?.user_facing_response_allowed === true,
mcp_discovery_requires_clarification: bridge?.requires_user_clarification === true
};
}
export function attachAssistantMcpDiscoveryDebug<T extends Record<string, unknown>>(
debugPayload: T,
input: AttachAssistantMcpDiscoveryDebugInput
): T & AssistantMcpDiscoveryDebugAttachmentFields {
return {
...debugPayload,
...buildAssistantMcpDiscoveryDebugAttachmentFields(input)
};
}