import os
import re
from pathlib import Path
FIELDS_TO_FIX = {
'FineTuningJob': ['error'],
'MessageObject': ['incomplete_details'],
'RunObject': ['required_action', 'last_error', 'incomplete_details'],
'RunStepObject': ['last_error'],
'ThreadObject': ['tool_resources'],
'VectorStoreFileObject': ['last_error'],
}
def snake_to_field(name):
return name
def fix_boxed_field_to_option(file_path, field_names):
with open(file_path, 'r') as f:
content = f.read()
original_content = content
for field_name in field_names:
snake_field = re.sub(r'(?<!^)(?=[A-Z])', '_', field_name).lower()
field_pattern = rf'(\n\s+pub {snake_field}:\s+)(Box<[^>]+>)'
def replacement(match):
box_type = match.group(2)
if 'Option<' in match.group(0):
return match.group(0)
return f"{match.group(1)}Option<{box_type}>"
content = re.sub(field_pattern, replacement, content)
serde_pattern = rf'(#\[serde\(rename = "{snake_field}")\]\s*\n\s*pub {snake_field}:\s+Option<'
if re.search(serde_pattern, content):
serde_with_skip = rf'(#\[serde\(rename = "{snake_field}")'
if f'rename = "{snake_field}"' in content and 'skip_serializing_if' not in content:
content = re.sub(serde_with_skip, rf'\1, skip_serializing_if = "Option::is_none"', content)
new_func_pattern = r'(pub fn new\([^)]+\) -> \w+ \{[\s\S]+?\n \})'
new_func_match = re.search(new_func_pattern, content)
if new_func_match:
new_func = new_func_match.group(1)
modified_func = new_func
for field_name in field_names:
snake_field = re.sub(r'(?<!^)(?=[A-Z])', '_', field_name).lower()
body_pattern = rf'(\n\s+{snake_field}:\s+)Some\(Box::new\({snake_field}\)\)'
modified_func = re.sub(body_pattern, rf'\1{snake_field}.map(Box::new)', modified_func)
content = content.replace(new_func, modified_func)
if content != original_content:
with open(file_path, 'w') as f:
f.write(content)
return True
return False
def main():
if len(os.sys.argv) < 2:
print("Usage: fix_boxed_nullable_fields.py <root_dir>")
os.sys.exit(1)
root_dir = Path(os.sys.argv[1])
models_dir = root_dir / 'src' / 'models'
if not models_dir.exists():
print(f"Models directory not found: {models_dir}")
os.sys.exit(1)
print("Fixing boxed nullable fields...")
fixed_count = 0
for struct_name, fields in FIELDS_TO_FIX.items():
file_name = re.sub(r'(?<!^)(?=[A-Z])', '_', struct_name).lower() + '.rs'
file_path = models_dir / file_name
if not file_path.exists():
print(f"Warning: File {file_path} not found")
continue
print(f"Fixing {struct_name} fields: {fields}")
if fix_boxed_field_to_option(file_path, fields):
fixed_count += 1
print(f" Fixed {struct_name}")
print(f"Fixed {fixed_count} structs")
if __name__ == '__main__':
main()