diff --git a/python/mirascope/llm/providers/google/model_info.py b/python/mirascope/llm/providers/google/model_info.py index d792790e48..3e7a4944dc 100644 --- a/python/mirascope/llm/providers/google/model_info.py +++ b/python/mirascope/llm/providers/google/model_info.py @@ -21,6 +21,7 @@ "google/gemini-2.5-flash-lite-preview-09-2025", "google/gemini-2.5-flash-preview-09-2025", "google/gemini-2.5-pro", + "google/gemini-3-flash-preview", "google/gemini-3-pro-image-preview", "google/gemini-3-pro-preview", "google/gemini-flash-latest", diff --git a/python/scripts/model_features/data/anthropic.yaml b/python/scripts/model_features/data/anthropic.yaml index 3b43566fc6..112fefc08f 100644 --- a/python/scripts/model_features/data/anthropic.yaml +++ b/python/scripts/model_features/data/anthropic.yaml @@ -112,4 +112,4 @@ models: strict_structured_output: status: supported tested_at: '2025-12-15T15:40:34.228188' -last_discovery: '2025-12-15T15:40:13.290920' +last_discovery: '2026-01-08T23:03:02.705418' diff --git a/python/scripts/model_features/data/google.yaml b/python/scripts/model_features/data/google.yaml index 732cf2ab7c..cb33c28f06 100644 --- a/python/scripts/model_features/data/google.yaml +++ b/python/scripts/model_features/data/google.yaml @@ -422,6 +422,21 @@ models: reason: unmet_dependencies failed_dependencies: - chat_model + gemini-3-flash-preview: + owned_by: google + deprecated: false + discovered_at: '2026-01-08T22:59:46.316610' + metadata: + display_name: Gemini 3 Flash Preview + features: + chat_model: + status: supported + tested_at: '2026-01-08T22:59:47.327767' + structured_output_with_tools: + status: supported + tested_at: '2026-01-08T22:59:48.732013' + metadata: + called_tool: true gemini-3-pro-image-preview: owned_by: google deprecated: false @@ -926,4 +941,4 @@ models: reason: unmet_dependencies failed_dependencies: - chat_model -last_discovery: '2025-12-16T15:16:15.591396' +last_discovery: '2026-01-08T23:03:00.506074' diff --git a/python/scripts/model_features/data/openai.yaml b/python/scripts/model_features/data/openai.yaml index 8803c49874..cfd54fe65b 100644 --- a/python/scripts/model_features/data/openai.yaml +++ b/python/scripts/model_features/data/openai.yaml @@ -4293,4 +4293,4 @@ models: reason: unmet_dependencies failed_dependencies: - completions_api -last_discovery: '2025-12-18T11:37:47.379462' +last_discovery: '2026-01-08T23:03:01.901516' diff --git a/python/scripts/model_features/update_all.py b/python/scripts/model_features/update_all.py new file mode 100644 index 0000000000..6d72351a94 --- /dev/null +++ b/python/scripts/model_features/update_all.py @@ -0,0 +1,143 @@ +"""Run all model feature tests and code generation for all providers. + +This script runs the test and codegen scripts for all supported providers: +- Google +- OpenAI +- Anthropic + +For each provider, it: +1. Runs the test script to discover models and test feature support +2. Runs the codegen script to generate model_info.py files + +Usage: + uv run python -m scripts.model_features.update_all [options] + +Options: + --test-only Only run tests, skip code generation + --codegen-only Only run code generation, skip tests + --providers NAMES Comma-separated list of providers (default: all) + Valid providers: google, openai, anthropic + +Requires API keys for each provider (loaded from .env if present): +- GOOGLE_API_KEY +- OPENAI_API_KEY +- ANTHROPIC_API_KEY +""" + +import argparse +import subprocess +import sys +from pathlib import Path + + +def run_command(cmd: list[str], description: str) -> bool: + """Run a command and return whether it succeeded. + + Args: + cmd: Command to run as list of strings + description: Description of what the command does + + Returns: + True if command succeeded, False otherwise + """ + print(f"\n{'=' * 80}") + print(f"{description}") + print(f"{'=' * 80}") + print(f"Running: {' '.join(cmd)}\n") + + result = subprocess.run(cmd, cwd=Path(__file__).parent.parent.parent) + + if result.returncode != 0: + print(f"\n❌ Failed: {description}") + return False + + print(f"\n✅ Success: {description}") + return True + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Run all model feature tests and code generation" + ) + parser.add_argument( + "--test-only", action="store_true", help="Only run tests, skip code generation" + ) + parser.add_argument( + "--codegen-only", + action="store_true", + help="Only run code generation, skip tests", + ) + parser.add_argument( + "--providers", + type=str, + default="google,openai,anthropic", + help="Comma-separated list of providers (default: all)", + ) + + args = parser.parse_args() + + # Parse providers + valid_providers = {"google", "openai", "anthropic"} + providers = [p.strip().lower() for p in args.providers.split(",")] + + # Validate providers + invalid = set(providers) - valid_providers + if invalid: + print(f"Error: Invalid providers: {', '.join(invalid)}") + print(f"Valid providers: {', '.join(sorted(valid_providers))}") + return 1 + + # Track overall success + all_succeeded = True + + # Run tests for each provider + if not args.codegen_only: + for provider in providers: + success = run_command( + [ + "uv", + "run", + "python", + "-m", + f"scripts.model_features.test_{provider}", + ], + f"Testing {provider.upper()} models", + ) + if not success: + all_succeeded = False + print(f"\n⚠️ Warning: Test for {provider} failed, continuing anyway...") + + # Run codegen for each provider + if not args.test_only: + for provider in providers: + success = run_command( + [ + "uv", + "run", + "python", + "-m", + f"scripts.model_features.codegen_{provider}", + ], + f"Generating code for {provider.upper()}", + ) + if not success: + all_succeeded = False + print( + f"\n⚠️ Warning: Codegen for {provider} failed, continuing anyway..." + ) + + # Print summary + print(f"\n{'=' * 80}") + print("SUMMARY") + print(f"{'=' * 80}") + + if all_succeeded: + print("✅ All operations completed successfully!") + return 0 + else: + print("⚠️ Some operations failed. See output above for details.") + return 1 + + +if __name__ == "__main__": + sys.exit(main())