ostruct-cli 0.7.2__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. ostruct/cli/__init__.py +21 -3
  2. ostruct/cli/base_errors.py +1 -1
  3. ostruct/cli/cli.py +66 -1983
  4. ostruct/cli/click_options.py +460 -28
  5. ostruct/cli/code_interpreter.py +238 -0
  6. ostruct/cli/commands/__init__.py +32 -0
  7. ostruct/cli/commands/list_models.py +128 -0
  8. ostruct/cli/commands/quick_ref.py +50 -0
  9. ostruct/cli/commands/run.py +137 -0
  10. ostruct/cli/commands/update_registry.py +71 -0
  11. ostruct/cli/config.py +277 -0
  12. ostruct/cli/cost_estimation.py +134 -0
  13. ostruct/cli/errors.py +310 -6
  14. ostruct/cli/exit_codes.py +1 -0
  15. ostruct/cli/explicit_file_processor.py +548 -0
  16. ostruct/cli/field_utils.py +69 -0
  17. ostruct/cli/file_info.py +42 -9
  18. ostruct/cli/file_list.py +301 -102
  19. ostruct/cli/file_search.py +455 -0
  20. ostruct/cli/file_utils.py +47 -13
  21. ostruct/cli/mcp_integration.py +541 -0
  22. ostruct/cli/model_creation.py +150 -1
  23. ostruct/cli/model_validation.py +204 -0
  24. ostruct/cli/progress_reporting.py +398 -0
  25. ostruct/cli/registry_updates.py +14 -9
  26. ostruct/cli/runner.py +1418 -0
  27. ostruct/cli/schema_utils.py +113 -0
  28. ostruct/cli/services.py +626 -0
  29. ostruct/cli/template_debug.py +748 -0
  30. ostruct/cli/template_debug_help.py +162 -0
  31. ostruct/cli/template_env.py +15 -6
  32. ostruct/cli/template_filters.py +55 -3
  33. ostruct/cli/template_optimizer.py +474 -0
  34. ostruct/cli/template_processor.py +1080 -0
  35. ostruct/cli/template_rendering.py +69 -34
  36. ostruct/cli/token_validation.py +286 -0
  37. ostruct/cli/types.py +78 -0
  38. ostruct/cli/unattended_operation.py +269 -0
  39. ostruct/cli/validators.py +386 -3
  40. {ostruct_cli-0.7.2.dist-info → ostruct_cli-0.8.0.dist-info}/LICENSE +2 -0
  41. ostruct_cli-0.8.0.dist-info/METADATA +633 -0
  42. ostruct_cli-0.8.0.dist-info/RECORD +69 -0
  43. {ostruct_cli-0.7.2.dist-info → ostruct_cli-0.8.0.dist-info}/WHEEL +1 -1
  44. ostruct_cli-0.7.2.dist-info/METADATA +0 -370
  45. ostruct_cli-0.7.2.dist-info/RECORD +0 -45
  46. {ostruct_cli-0.7.2.dist-info → ostruct_cli-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,113 @@
1
+ """Schema utilities for ostruct CLI."""
2
+
3
+ import json
4
+ import logging
5
+ from pathlib import Path
6
+ from typing import Any, Dict, Optional
7
+
8
+ from openai_model_registry import ModelRegistry
9
+
10
+ from .errors import SchemaFileError
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def make_strict(obj: Any) -> None:
16
+ """Transform Pydantic schema for Responses API strict mode.
17
+
18
+ This function recursively adds 'additionalProperties: false' to all object types
19
+ in a JSON schema to make it compatible with OpenAI's strict mode requirement.
20
+
21
+ Args:
22
+ obj: The schema object to transform (modified in-place)
23
+ """
24
+ if isinstance(obj, dict):
25
+ if obj.get("type") == "object" and "additionalProperties" not in obj:
26
+ obj["additionalProperties"] = False
27
+ for value in obj.values():
28
+ make_strict(value)
29
+ elif isinstance(obj, list):
30
+ for item in obj:
31
+ make_strict(item)
32
+
33
+
34
+ def supports_structured_output(model: str) -> bool:
35
+ """Check if model supports structured output."""
36
+ try:
37
+ registry = ModelRegistry.get_instance()
38
+ capabilities = registry.get_capabilities(model)
39
+ return getattr(capabilities, "supports_structured_output", True)
40
+ except Exception:
41
+ return True
42
+
43
+
44
+ def validate_schema_file(
45
+ schema_path: str, schema_context: Optional[Dict[str, Any]] = None
46
+ ) -> Dict[str, Any]:
47
+ """Validate and load schema file.
48
+
49
+ Args:
50
+ schema_path: Path to schema file
51
+ schema_context: Optional context for error reporting
52
+
53
+ Returns:
54
+ Dict containing the loaded schema
55
+
56
+ Raises:
57
+ SchemaFileError: If schema file is invalid or cannot be read
58
+ """
59
+ try:
60
+ with Path(schema_path).open("r") as f:
61
+ schema_data = json.load(f)
62
+
63
+ # Validate basic schema structure
64
+ if not isinstance(schema_data, dict):
65
+ raise SchemaFileError(
66
+ f"Schema file must contain a JSON object, got {type(schema_data).__name__}",
67
+ schema_path=schema_path,
68
+ context=schema_context,
69
+ )
70
+
71
+ # Must have either "schema" key or be a direct schema
72
+ if "schema" in schema_data:
73
+ # Wrapped schema format
74
+ actual_schema = schema_data["schema"]
75
+ else:
76
+ # Direct schema format
77
+ actual_schema = schema_data
78
+
79
+ if not isinstance(actual_schema, dict):
80
+ raise SchemaFileError(
81
+ f"Schema must be a JSON object, got {type(actual_schema).__name__}",
82
+ schema_path=schema_path,
83
+ context=schema_context,
84
+ )
85
+
86
+ # Validate that root type is object for structured output
87
+ if actual_schema.get("type") != "object":
88
+ raise SchemaFileError(
89
+ f"Schema root type must be 'object', got '{actual_schema.get('type')}'",
90
+ schema_path=schema_path,
91
+ context=schema_context,
92
+ )
93
+
94
+ return schema_data
95
+
96
+ except json.JSONDecodeError as e:
97
+ raise SchemaFileError(
98
+ f"Invalid JSON in schema file: {e}",
99
+ schema_path=schema_path,
100
+ context=schema_context,
101
+ ) from e
102
+ except FileNotFoundError as e:
103
+ raise SchemaFileError(
104
+ f"Schema file not found: {schema_path}",
105
+ schema_path=schema_path,
106
+ context=schema_context,
107
+ ) from e
108
+ except Exception as e:
109
+ raise SchemaFileError(
110
+ f"Error reading schema file: {e}",
111
+ schema_path=schema_path,
112
+ context=schema_context,
113
+ ) from e