|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { |
|
ModelVendor, |
|
SymbolicPrimitive, |
|
GrammarStyle, |
|
SymbolicOperation, |
|
VendorImplementation, |
|
SYMBOLIC_RUNTIME_SCHEMA |
|
} from './universal-symbolics-runtime'; |
|
|
|
import { SymbolicsRegistry } from './universal-symbolics-registry'; |
|
|
|
|
|
|
|
|
|
export interface HarmonizationOptions { |
|
preserveStructure?: boolean; |
|
adaptToCapabilities?: boolean; |
|
includeComments?: boolean; |
|
embedTraceability?: boolean; |
|
formatOutput?: boolean; |
|
handleResidue?: boolean; |
|
fallbackBehavior?: 'omit' | 'emulate' | 'comment'; |
|
} |
|
|
|
|
|
|
|
|
|
export interface HarmonizationResult { |
|
transformed: string; |
|
originalVendor: ModelVendor; |
|
targetVendor: ModelVendor; |
|
operations: { |
|
original: SymbolicPrimitive; |
|
target: SymbolicPrimitive | null; |
|
success: boolean; |
|
message?: string; |
|
}[]; |
|
residue: { |
|
pattern: string; |
|
position: number; |
|
possiblePrimitive?: SymbolicPrimitive; |
|
}[]; |
|
metrics: { |
|
totalOperations: number; |
|
successfulOperations: number; |
|
unsupportedOperations: number; |
|
adaptedOperations: number; |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class SymbolicHarmonizer { |
|
private registry: SymbolicsRegistry; |
|
|
|
constructor(registry?: SymbolicsRegistry) { |
|
this.registry = registry || new SymbolicsRegistry(); |
|
} |
|
|
|
|
|
|
|
|
|
public harmonize( |
|
content: string, |
|
sourceVendor: ModelVendor, |
|
targetVendor: ModelVendor, |
|
options: HarmonizationOptions = {} |
|
): HarmonizationResult { |
|
|
|
const opts: Required<HarmonizationOptions> = { |
|
preserveStructure: options.preserveStructure !== undefined ? options.preserveStructure : true, |
|
adaptToCapabilities: options.adaptToCapabilities !== undefined ? options.adaptToCapabilities : true, |
|
includeComments: options.includeComments !== undefined ? options.includeComments : false, |
|
embedTraceability: options.embedTraceability !== undefined ? options.embedTraceability : false, |
|
formatOutput: options.formatOutput !== undefined ? options.formatOutput : true, |
|
handleResidue: options.handleResidue !== undefined ? options.handleResidue : true, |
|
fallbackBehavior: options.fallbackBehavior || 'emulate' |
|
}; |
|
|
|
|
|
const result: HarmonizationResult = { |
|
transformed: '', |
|
originalVendor: sourceVendor, |
|
targetVendor: targetVendor, |
|
operations: [], |
|
residue: [], |
|
metrics: { |
|
totalOperations: 0, |
|
successfulOperations: 0, |
|
unsupportedOperations: 0, |
|
adaptedOperations: 0 |
|
} |
|
}; |
|
|
|
|
|
if (sourceVendor === targetVendor) { |
|
result.transformed = content; |
|
return result; |
|
} |
|
|
|
|
|
if (opts.handleResidue) { |
|
result.residue = this.registry.findSymbolicResidue(content, sourceVendor); |
|
|
|
|
|
if (result.residue.length > 0) { |
|
content = this.registry.repairSymbolicResidue(content, sourceVendor); |
|
} |
|
} |
|
|
|
|
|
const extractedOperations = this.registry.extractAllSymbolicOperations(content, sourceVendor); |
|
result.metrics.totalOperations = extractedOperations.length; |
|
|
|
|
|
const operationPositions = this.mapOperationPositions(content, sourceVendor); |
|
|
|
|
|
const operationResults: { primitive: SymbolicPrimitive, params: any, success: boolean, message?: string, transformed?: string }[] = []; |
|
|
|
for (const { primitive, params } of extractedOperations) { |
|
const operationResult = this.transformOperation(primitive, params, sourceVendor, targetVendor, opts); |
|
operationResults.push({ |
|
primitive, |
|
params, |
|
success: operationResult.success, |
|
message: operationResult.message, |
|
transformed: operationResult.transformed |
|
}); |
|
|
|
|
|
if (operationResult.success) { |
|
result.metrics.successfulOperations++; |
|
|
|
if (operationResult.adapted) { |
|
result.metrics.adaptedOperations++; |
|
} |
|
} else { |
|
result.metrics.unsupportedOperations++; |
|
} |
|
|
|
|
|
result.operations.push({ |
|
original: primitive, |
|
target: operationResult.targetPrimitive, |
|
success: operationResult.success, |
|
message: operationResult.message |
|
}); |
|
} |
|
|
|
|
|
result.transformed = this.generateTransformedContent( |
|
content, |
|
operationPositions, |
|
operationResults, |
|
sourceVendor, |
|
targetVendor, |
|
opts |
|
); |
|
|
|
|
|
if (opts.formatOutput) { |
|
result.transformed = this.formatOutput(result.transformed, targetVendor); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
private transformOperation( |
|
primitive: SymbolicPrimitive, |
|
params: any, |
|
sourceVendor: ModelVendor, |
|
targetVendor: ModelVendor, |
|
options: Required<HarmonizationOptions> |
|
): { |
|
success: boolean; |
|
message?: string; |
|
transformed?: string; |
|
targetPrimitive: SymbolicPrimitive | null; |
|
adapted: boolean; |
|
} { |
|
|
|
const targetSupport = this.registry.vendorSupports(targetVendor, primitive); |
|
|
|
|
|
let targetPrimitive = primitive; |
|
let adapted = false; |
|
|
|
if (!targetSupport && options.adaptToCapabilities) { |
|
const alternativePrimitive = this.findAlternativePrimitive(primitive, targetVendor); |
|
|
|
if (alternativePrimitive) { |
|
targetPrimitive = alternativePrimitive; |
|
adapted = true; |
|
} |
|
} |
|
|
|
|
|
const finalSupport = this.registry.vendorSupports(targetVendor, targetPrimitive); |
|
|
|
if (!finalSupport) { |
|
|
|
switch (options.fallbackBehavior) { |
|
case 'omit': |
|
return { |
|
success: false, |
|
message: `Operation ${primitive} not supported by ${targetVendor} and omitted`, |
|
targetPrimitive: null, |
|
adapted: false |
|
}; |
|
|
|
case 'comment': |
|
return { |
|
success: false, |
|
message: `Operation ${primitive} not supported by ${targetVendor}`, |
|
transformed: this.generateCommentForUnsupported(primitive, params, sourceVendor, targetVendor), |
|
targetPrimitive: null, |
|
adapted: false |
|
}; |
|
|
|
case 'emulate': |
|
|
|
const emulatedTransformation = this.emulateOperation(primitive, params, sourceVendor, targetVendor); |
|
|
|
if (emulatedTransformation) { |
|
return { |
|
success: true, |
|
message: `Operation ${primitive} emulated for ${targetVendor}`, |
|
transformed: emulatedTransformation, |
|
targetPrimitive: targetPrimitive, |
|
adapted: true |
|
}; |
|
} |
|
|
|
|
|
return { |
|
success: false, |
|
message: `Operation ${primitive} not supported by ${targetVendor} and cannot be emulated`, |
|
transformed: this.generateCommentForUnsupported(primitive, params, sourceVendor, targetVendor), |
|
targetPrimitive: null, |
|
adapted: false |
|
}; |
|
} |
|
} |
|
|
|
|
|
const implementation = this.registry.getVendorImplementation(targetPrimitive, targetVendor); |
|
if (!implementation) { |
|
return { |
|
success: false, |
|
message: `Could not find implementation for ${targetPrimitive} in ${targetVendor}`, |
|
targetPrimitive: null, |
|
adapted: false |
|
}; |
|
} |
|
|
|
|
|
let adaptedParams = params; |
|
if (adapted) { |
|
adaptedParams = this.adaptParameters(params, primitive, targetPrimitive); |
|
} |
|
|
|
|
|
const transformed = this.generateTransformation(targetPrimitive, adaptedParams, implementation); |
|
|
|
|
|
let finalTransformed = transformed; |
|
|
|
if (options.includeComments) { |
|
finalTransformed = this.addComments(transformed, primitive, sourceVendor, targetPrimitive, targetVendor, adapted); |
|
} |
|
|
|
if (options.embedTraceability) { |
|
finalTransformed = this.embedTraceability(finalTransformed, primitive, sourceVendor, targetVendor); |
|
} |
|
|
|
return { |
|
success: true, |
|
message: adapted ? `Operation ${primitive} adapted to ${targetPrimitive} for ${targetVendor}` : undefined, |
|
transformed: finalTransformed, |
|
targetPrimitive: targetPrimitive, |
|
adapted: adapted |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
private mapOperationPositions(content: string, vendor: ModelVendor): Map<SymbolicPrimitive, number[]> { |
|
const positions = new Map<SymbolicPrimitive, number[]>(); |
|
|
|
|
|
for (const primitive of Object.values(SymbolicPrimitive)) { |
|
positions.set(primitive, []); |
|
} |
|
|
|
|
|
switch (vendor) { |
|
case ModelVendor.ANTHROPIC: |
|
|
|
for (const primitive of Object.values(SymbolicPrimitive)) { |
|
const implementation = this.registry.getVendorImplementation(primitive, vendor); |
|
if (!implementation || implementation.style !== GrammarStyle.XML_TAGS) continue; |
|
|
|
if (implementation.prefix && implementation.suffix) { |
|
const regex = new RegExp(`${escapeRegExp(implementation.prefix)}[\\s\\S]*?${escapeRegExp(implementation.suffix)}`, 'g'); |
|
let match; |
|
const primitivePositions = positions.get(primitive) || []; |
|
|
|
while ((match = regex.exec(content)) !== null) { |
|
primitivePositions.push(match.index); |
|
} |
|
|
|
positions.set(primitive, primitivePositions); |
|
} |
|
} |
|
break; |
|
|
|
case ModelVendor.QWEN: |
|
case ModelVendor.OPENAI: |
|
|
|
for (const primitive of Object.values(SymbolicPrimitive)) { |
|
const implementation = this.registry.getVendorImplementation(primitive, vendor); |
|
if (!implementation || implementation.style !== GrammarStyle.SLASH_COMMANDS) continue; |
|
|
|
if (implementation.prefix) { |
|
const regex = new RegExp(`${escapeRegExp(implementation.prefix)}\\s+[^\\n]*`, 'g'); |
|
let match; |
|
const primitivePositions = positions.get(primitive) || []; |
|
|
|
while ((match = regex.exec(content)) !== null) { |
|
primitivePositions.push(match.index); |
|
} |
|
|
|
positions.set(primitive, primitivePositions); |
|
} |
|
} |
|
break; |
|
|
|
|
|
} |
|
|
|
return positions; |
|
} |
|
|