NODEDC_1C/llm_normalizer/backend/src/services/assistantCapabilityRuntimeB...

395 lines
14 KiB
TypeScript

import {
ASSISTANT_CAPABILITY_RUNTIME_BINDING_SCHEMA_VERSION,
type AssistantCapabilityBindingAction,
type AssistantCapabilityBindingStatus,
type AssistantCapabilityBindingViolation,
type AssistantCapabilityRuntimeBindingContract,
type AssistantRuntimeContractShadowDecision,
type AssistantRuntimeLane,
type AssistantStateTransitionRuntimeContract,
type AssistantTruthAnswerPolicyRuntimeContract
} from "../types/assistantRuntimeContracts";
import { getAssistantCapabilityContract } from "./assistantRuntimeContractRegistry";
import { resolveAssistantRuntimeContractShadow } from "./assistantRuntimeContractResolver";
import { resolveAssistantStateTransitionRuntime } from "./assistantStateTransitionRuntimeAdapter";
import { resolveAssistantTruthAnswerPolicyRuntime } from "./assistantTruthAnswerPolicyRuntimeAdapter";
export interface ResolveAssistantCapabilityRuntimeBindingInput {
addressDebug?: Record<string, unknown> | null;
addressRuntimeMeta?: Record<string, unknown> | null;
groundingStatus?: unknown;
coverageReport?: Record<string, unknown> | null;
replyType?: unknown;
runtimeContractShadow?: AssistantRuntimeContractShadowDecision | null;
truthAnswerPolicy?: AssistantTruthAnswerPolicyRuntimeContract | null;
stateTransition?: AssistantStateTransitionRuntimeContract | null;
}
export interface AssistantCapabilityRuntimeBindingFields {
assistant_capability_binding_v1: AssistantCapabilityRuntimeBindingContract;
capability_binding_contract: AssistantCapabilityRuntimeBindingContract;
capability_binding_status: AssistantCapabilityBindingStatus;
capability_binding_action: AssistantCapabilityBindingAction;
capability_binding_violations: AssistantCapabilityBindingViolation[];
}
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 toStringList(value: unknown): string[] {
if (!Array.isArray(value)) {
return [];
}
return value
.map((item) => toNonEmptyString(item))
.filter((item): item is string => Boolean(item));
}
function uniqueStrings(values: string[]): string[] {
return Array.from(new Set(values.filter((item) => item.trim().length > 0)));
}
function addViolation(target: AssistantCapabilityBindingViolation[], violation: AssistantCapabilityBindingViolation): void {
if (!target.includes(violation)) {
target.push(violation);
}
}
function resolveShadow(
input: ResolveAssistantCapabilityRuntimeBindingInput,
debug: Record<string, unknown>
): AssistantRuntimeContractShadowDecision {
return (
input.runtimeContractShadow ??
(toRecordObject(debug.assistant_runtime_contract_v1) as AssistantRuntimeContractShadowDecision | null) ??
resolveAssistantRuntimeContractShadow({
addressDebug: debug,
addressRuntimeMeta: input.addressRuntimeMeta,
groundingStatus: input.groundingStatus
})
);
}
function resolveTruthPolicy(
input: ResolveAssistantCapabilityRuntimeBindingInput,
debug: Record<string, unknown>
): AssistantTruthAnswerPolicyRuntimeContract {
return (
input.truthAnswerPolicy ??
(toRecordObject(debug.assistant_truth_answer_policy_v1) as AssistantTruthAnswerPolicyRuntimeContract | null) ??
resolveAssistantTruthAnswerPolicyRuntime({
addressDebug: debug,
addressRuntimeMeta: input.addressRuntimeMeta,
groundingStatus: input.groundingStatus,
coverageReport: input.coverageReport,
replyType: input.replyType
})
);
}
function resolveStateTransition(
input: ResolveAssistantCapabilityRuntimeBindingInput,
debug: Record<string, unknown>
): AssistantStateTransitionRuntimeContract {
return (
input.stateTransition ??
(toRecordObject(debug.assistant_state_transition_v1) as AssistantStateTransitionRuntimeContract | null) ??
resolveAssistantStateTransitionRuntime({
addressDebug: debug,
addressRuntimeMeta: input.addressRuntimeMeta,
groundingStatus: input.groundingStatus,
coverageReport: input.coverageReport,
replyType: input.replyType,
runtimeContractShadow: input.runtimeContractShadow,
truthAnswerPolicy: input.truthAnswerPolicy
})
);
}
function hasValue(value: unknown): boolean {
return toNonEmptyString(value) !== null;
}
function collectProvidedAnchors(debug: Record<string, unknown>): string[] {
const anchors: string[] = [];
const filters = toRecordObject(debug.extracted_filters);
const semanticFrame = toRecordObject(debug.semantic_frame);
const rootFrame = toRecordObject(debug.address_root_frame_context);
const anchorType = toNonEmptyString(debug.anchor_type);
const anchorValue = toNonEmptyString(debug.anchor_value_resolved) ?? toNonEmptyString(debug.anchor_value_raw);
if (filters) {
for (const [key, value] of Object.entries(filters)) {
if (hasValue(value)) {
anchors.push(key);
}
}
}
if (anchorType && anchorType !== "unknown" && anchorValue) {
anchors.push(anchorType);
}
if (semanticFrame) {
const anchorKind = toNonEmptyString(semanticFrame.anchor_kind);
const anchorValueFromFrame = toNonEmptyString(semanticFrame.anchor_value);
if (anchorKind && anchorKind !== "none" && (anchorValueFromFrame || semanticFrame.selected_object_scope_detected === true)) {
anchors.push(anchorKind);
}
if (semanticFrame.selected_object_scope_detected === true) {
anchors.push("selected_object");
}
}
if (toNonEmptyString(rootFrame?.current_frame_kind)?.includes("drilldown")) {
anchors.push("selected_object");
}
return uniqueStrings(anchors);
}
function anchorSatisfied(requiredAnchor: string, providedAnchors: string[], debug: Record<string, unknown>): boolean {
const filters = toRecordObject(debug.extracted_filters);
if (providedAnchors.includes(requiredAnchor)) {
return true;
}
if (requiredAnchor === "item") {
return (
providedAnchors.includes("selected_object") ||
providedAnchors.includes("anchor_item") ||
hasValue(filters?.item) ||
toNonEmptyString(debug.anchor_type) === "item"
);
}
if (requiredAnchor === "supplier") {
return providedAnchors.includes("counterparty") || hasValue(filters?.supplier) || hasValue(filters?.counterparty);
}
return false;
}
function runtimeLaneObserved(debug: Record<string, unknown>): AssistantRuntimeLane | "unknown" {
const capabilityRouteMode = toNonEmptyString(debug.capability_route_mode);
const capabilityLayer = toNonEmptyString(debug.capability_layer);
const detectedMode = toNonEmptyString(debug.detected_mode);
if (capabilityRouteMode === "exact" && (capabilityLayer === "compute" || detectedMode === "address_query")) {
return "address_exact";
}
if (detectedMode === "assistant_data_scope") {
return "assistant_data_scope";
}
if (capabilityLayer === "conversational") {
return "chat";
}
return "unknown";
}
function focusObjectBindingStatus(input: {
requiresFocusObject: boolean;
providedAnchors: string[];
missingAnchors: string[];
}): AssistantCapabilityRuntimeBindingContract["focus_object_binding_status"] {
if (!input.requiresFocusObject) {
return "not_required";
}
if (input.providedAnchors.includes("selected_object")) {
return "bound";
}
if (!input.missingAnchors.includes("item") && input.providedAnchors.includes("item")) {
return "inferred_from_anchor";
}
return "missing";
}
function truthFallbackAllowed(
contractTruthFallbacks: string[],
truthMode: AssistantTruthAnswerPolicyRuntimeContract["truth_gate"]["truth_mode"]
): boolean {
return truthMode === "confirmed" || contractTruthFallbacks.includes(truthMode);
}
function bindingStatusFor(input: {
hasCapabilityId: boolean;
hasContract: boolean;
violations: AssistantCapabilityBindingViolation[];
truthMode: AssistantTruthAnswerPolicyRuntimeContract["truth_gate"]["truth_mode"];
}): AssistantCapabilityBindingStatus {
if (!input.hasCapabilityId) {
return "not_applicable";
}
if (!input.hasContract) {
return "contract_missing";
}
if (
input.violations.includes("transition_not_supported_by_capability") ||
input.violations.includes("required_anchor_missing") ||
input.violations.includes("focus_object_required_but_unbound") ||
input.violations.includes("runtime_lane_mismatch")
) {
return "blocked";
}
if (input.violations.length > 0 || input.truthMode !== "confirmed") {
return "bound_with_limits";
}
return "bound";
}
function bindingActionFor(status: AssistantCapabilityBindingStatus, missingAnchors: string[]): AssistantCapabilityBindingAction {
if (status === "not_applicable" || status === "contract_missing") {
return "observe_only";
}
if (status === "blocked" && missingAnchors.length > 0) {
return "clarify";
}
if (status === "blocked") {
return "block";
}
if (status === "bound_with_limits") {
return "limit";
}
return "allow";
}
export function resolveAssistantCapabilityRuntimeBinding(
input: ResolveAssistantCapabilityRuntimeBindingInput
): AssistantCapabilityRuntimeBindingContract {
const debug = toRecordObject(input.addressDebug) ?? {};
const shadow = resolveShadow(input, debug);
const truthPolicy = resolveTruthPolicy(input, debug);
const stateTransition = resolveStateTransition(input, debug);
const capabilityId =
shadow.capability_contract_id ??
toNonEmptyString(debug.capability_contract_id) ??
toNonEmptyString(debug.capability_id) ??
truthPolicy.answer_shape.capability_contract_id;
const capabilityContract = capabilityId ? getAssistantCapabilityContract(capabilityId) : null;
const violations: AssistantCapabilityBindingViolation[] = [];
if (capabilityId && !capabilityContract) {
addViolation(violations, "capability_contract_missing");
}
const transitionAllowed =
capabilityContract && stateTransition.transition_id
? capabilityContract.supported_transition_classes.includes(stateTransition.transition_id)
: capabilityContract
? null
: false;
if (capabilityContract && stateTransition.transition_id && !transitionAllowed) {
addViolation(violations, "transition_not_supported_by_capability");
}
const providedAnchors = collectProvidedAnchors(debug);
const requiredAnchors = capabilityContract?.required_anchors ?? [];
const missingAnchors = requiredAnchors.filter((anchor) => !anchorSatisfied(anchor, providedAnchors, debug));
if (missingAnchors.length > 0) {
addViolation(violations, "required_anchor_missing");
}
const focusStatus = focusObjectBindingStatus({
requiresFocusObject: capabilityContract?.requires_focus_object ?? false,
providedAnchors,
missingAnchors
});
if (capabilityContract?.requires_focus_object && focusStatus === "missing") {
addViolation(violations, "focus_object_required_but_unbound");
}
const observedLane = runtimeLaneObserved(debug);
const laneMatches = !capabilityContract || observedLane === "unknown" || capabilityContract.runtime_lane === observedLane;
if (capabilityContract && !laneMatches) {
addViolation(violations, "runtime_lane_mismatch");
}
const truthAllowed = capabilityContract
? truthFallbackAllowed(capabilityContract.truth_mode_fallbacks, truthPolicy.truth_gate.truth_mode)
: null;
if (truthAllowed === false) {
addViolation(violations, "truth_fallback_not_declared");
}
const answerShapeCompatible =
capabilityContract && truthPolicy.answer_shape.capability_contract_id
? truthPolicy.answer_shape.capability_contract_id === capabilityContract.capability_id
: capabilityContract
? null
: false;
if (answerShapeCompatible === false && capabilityContract) {
addViolation(violations, "answer_shape_capability_mismatch");
}
const status = bindingStatusFor({
hasCapabilityId: Boolean(capabilityId),
hasContract: Boolean(capabilityContract),
violations,
truthMode: truthPolicy.truth_gate.truth_mode
});
const action = bindingActionFor(status, missingAnchors);
return {
schema_version: ASSISTANT_CAPABILITY_RUNTIME_BINDING_SCHEMA_VERSION,
binding_owner: "assistantCapabilityRuntimeBindingAdapter",
capability_id: capabilityId,
capability_contract_id: capabilityContract?.capability_id ?? null,
binding_status: status,
binding_action: action,
runtime_lane_expected: capabilityContract?.runtime_lane ?? null,
runtime_lane_observed: observedLane,
execution_adapter: capabilityContract?.execution_adapter ?? null,
transition_id: stateTransition.transition_id,
transition_allowed: transitionAllowed,
required_anchors: requiredAnchors,
provided_anchors: providedAnchors,
missing_anchors: missingAnchors,
requires_focus_object: capabilityContract?.requires_focus_object ?? false,
focus_object_binding_status: focusStatus,
result_shape: capabilityContract?.result_shape ?? null,
answer_object_shape: capabilityContract?.answer_object_shape ?? null,
truth_gate_behavior: capabilityContract?.coverage_gate_behavior ?? null,
truth_fallback_allowed: truthAllowed,
answer_shape_compatible: answerShapeCompatible,
violations,
reason_codes: uniqueStrings([
`binding_status_${status}`,
`binding_action_${action}`,
...violations,
...stateTransition.reason_codes,
...truthPolicy.truth_gate.reason_codes,
...shadow.capability_contract_reason
]).slice(0, 48)
};
}
export function buildAssistantCapabilityRuntimeBindingFields(
input: ResolveAssistantCapabilityRuntimeBindingInput
): AssistantCapabilityRuntimeBindingFields {
const binding = resolveAssistantCapabilityRuntimeBinding(input);
return {
assistant_capability_binding_v1: binding,
capability_binding_contract: binding,
capability_binding_status: binding.binding_status,
capability_binding_action: binding.binding_action,
capability_binding_violations: binding.violations
};
}
export function attachAssistantCapabilityRuntimeBinding<T extends Record<string, unknown>>(
debugPayload: T,
input: Omit<ResolveAssistantCapabilityRuntimeBindingInput, "addressDebug">
): T & AssistantCapabilityRuntimeBindingFields {
return {
...debugPayload,
...buildAssistantCapabilityRuntimeBindingFields({
...input,
addressDebug: debugPayload
})
};
}