ostruct-cli 0.6.1__py3-none-any.whl → 0.7.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.
- ostruct/cli/__init__.py +2 -0
- ostruct/cli/cli.py +200 -73
- ostruct/cli/errors.py +61 -54
- ostruct/cli/model_creation.py +67 -94
- ostruct/cli/registry_updates.py +162 -0
- ostruct/cli/security/errors.py +1 -1
- ostruct/cli/security/normalization.py +1 -1
- ostruct/cli/security/security_manager.py +48 -7
- ostruct/cli/template_extensions.py +32 -1
- ostruct/cli/template_utils.py +175 -16
- ostruct/cli/utils.py +3 -1
- ostruct/cli/validators.py +6 -2
- {ostruct_cli-0.6.1.dist-info → ostruct_cli-0.7.0.dist-info}/METADATA +71 -165
- {ostruct_cli-0.6.1.dist-info → ostruct_cli-0.7.0.dist-info}/RECORD +17 -16
- {ostruct_cli-0.6.1.dist-info → ostruct_cli-0.7.0.dist-info}/LICENSE +0 -0
- {ostruct_cli-0.6.1.dist-info → ostruct_cli-0.7.0.dist-info}/WHEEL +0 -0
- {ostruct_cli-0.6.1.dist-info → ostruct_cli-0.7.0.dist-info}/entry_points.txt +0 -0
ostruct/cli/template_utils.py
CHANGED
@@ -47,30 +47,189 @@ class TemplateMetadataError(TaskTemplateError):
|
|
47
47
|
|
48
48
|
|
49
49
|
def validate_json_schema(schema: Dict[str, Any]) -> None:
|
50
|
-
"""Validate
|
51
|
-
|
52
|
-
This function checks that the provided dictionary is a valid JSON Schema,
|
53
|
-
following the JSON Schema specification.
|
50
|
+
"""Validate a JSON schema.
|
54
51
|
|
55
52
|
Args:
|
56
|
-
schema:
|
53
|
+
schema: The schema to validate
|
57
54
|
|
58
55
|
Raises:
|
59
56
|
SchemaValidationError: If the schema is invalid
|
60
57
|
"""
|
61
58
|
try:
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
59
|
+
# 1. Quick structural validation
|
60
|
+
if not isinstance(schema, dict):
|
61
|
+
raise SchemaValidationError(
|
62
|
+
"Invalid JSON Schema: Schema must be a JSON object",
|
63
|
+
context={
|
64
|
+
"validation_type": "schema",
|
65
|
+
"found": type(schema).__name__,
|
66
|
+
"tips": ["Ensure your schema is a valid JSON object"],
|
67
|
+
},
|
68
|
+
)
|
69
|
+
|
70
|
+
# 2. Extract and validate schema wrapper
|
71
|
+
schema_to_validate = schema.get("schema", schema)
|
72
|
+
if not isinstance(schema_to_validate, dict):
|
73
|
+
raise SchemaValidationError(
|
74
|
+
"Invalid JSON Schema: Inner schema must be a JSON object",
|
75
|
+
context={
|
76
|
+
"validation_type": "schema",
|
77
|
+
"found": type(schema_to_validate).__name__,
|
78
|
+
"tips": [
|
79
|
+
"If using a schema wrapper, ensure the inner schema is a valid JSON object"
|
80
|
+
],
|
81
|
+
},
|
82
|
+
)
|
83
|
+
|
84
|
+
# 3. Check for circular references with enhanced detection
|
85
|
+
def resolve_ref(ref: str, root: Dict[str, Any]) -> Dict[str, Any]:
|
86
|
+
"""Resolve a JSON reference to its target object."""
|
87
|
+
if not ref.startswith("#/"):
|
88
|
+
raise SchemaValidationError(
|
89
|
+
"Invalid JSON Schema: Only local references are supported",
|
90
|
+
context={
|
91
|
+
"validation_type": "schema",
|
92
|
+
"ref": ref,
|
93
|
+
"tips": [
|
94
|
+
"Use only local references (starting with #/)"
|
95
|
+
],
|
96
|
+
},
|
97
|
+
)
|
98
|
+
|
99
|
+
parts = ref[2:].split("/")
|
100
|
+
current = root
|
101
|
+
for part in parts:
|
102
|
+
if part not in current:
|
103
|
+
raise SchemaValidationError(
|
104
|
+
f"Invalid JSON Schema: Reference {ref} not found",
|
105
|
+
context={
|
106
|
+
"validation_type": "schema",
|
107
|
+
"ref": ref,
|
108
|
+
"tips": [
|
109
|
+
"Check that all references point to existing definitions"
|
110
|
+
],
|
111
|
+
},
|
112
|
+
)
|
113
|
+
current = current[part]
|
114
|
+
return current
|
115
|
+
|
116
|
+
def check_refs(
|
117
|
+
obj: Any,
|
118
|
+
path: List[str],
|
119
|
+
seen_refs: List[str],
|
120
|
+
root: Dict[str, Any],
|
121
|
+
) -> None:
|
122
|
+
"""Check for circular references in the schema."""
|
123
|
+
if isinstance(obj, dict):
|
124
|
+
if "$ref" in obj:
|
125
|
+
ref = obj["$ref"]
|
126
|
+
if ref in seen_refs:
|
127
|
+
raise SchemaValidationError(
|
128
|
+
"Invalid JSON Schema: Circular reference found",
|
129
|
+
context={
|
130
|
+
"validation_type": "schema",
|
131
|
+
"path": "/".join(path),
|
132
|
+
"ref": ref,
|
133
|
+
"found": "circular reference",
|
134
|
+
"tips": [
|
135
|
+
"Remove circular references in your schema",
|
136
|
+
"Use unique identifiers instead of nested references",
|
137
|
+
"Consider flattening your schema structure",
|
138
|
+
],
|
139
|
+
},
|
140
|
+
)
|
141
|
+
|
142
|
+
# Resolve the reference and check its contents
|
143
|
+
seen_refs.append(ref)
|
144
|
+
try:
|
145
|
+
resolved = resolve_ref(ref, root)
|
146
|
+
check_refs(resolved, path, seen_refs.copy(), root)
|
147
|
+
except SchemaValidationError:
|
148
|
+
raise
|
149
|
+
except Exception as e:
|
150
|
+
raise SchemaValidationError(
|
151
|
+
f"Invalid JSON Schema: Failed to resolve reference {ref}",
|
152
|
+
context={
|
153
|
+
"validation_type": "schema",
|
154
|
+
"path": "/".join(path),
|
155
|
+
"ref": ref,
|
156
|
+
"error": str(e),
|
157
|
+
"tips": [
|
158
|
+
"Check that all references are properly formatted"
|
159
|
+
],
|
160
|
+
},
|
161
|
+
)
|
162
|
+
|
163
|
+
for key, value in obj.items():
|
164
|
+
if key != "$ref": # Skip checking the reference itself
|
165
|
+
check_refs(value, path + [key], seen_refs.copy(), root)
|
166
|
+
elif isinstance(obj, list):
|
167
|
+
for i, value in enumerate(obj):
|
168
|
+
check_refs(value, path + [str(i)], seen_refs.copy(), root)
|
169
|
+
|
170
|
+
check_refs(schema_to_validate, [], [], schema_to_validate)
|
171
|
+
|
172
|
+
# 4. Check required root properties
|
173
|
+
if "type" not in schema_to_validate:
|
174
|
+
raise SchemaValidationError(
|
175
|
+
"Invalid JSON Schema: Missing required 'type' property",
|
176
|
+
context={
|
177
|
+
"validation_type": "schema",
|
178
|
+
"tips": ["Add a 'type' property to your schema root"],
|
179
|
+
},
|
180
|
+
)
|
181
|
+
|
182
|
+
# 5. Check for required fields not defined in properties
|
183
|
+
if schema_to_validate.get("type") == "object":
|
184
|
+
required_fields = schema_to_validate.get("required", [])
|
185
|
+
properties = schema_to_validate.get("properties", {})
|
186
|
+
missing_fields = [
|
187
|
+
field for field in required_fields if field not in properties
|
188
|
+
]
|
189
|
+
if missing_fields:
|
190
|
+
raise SchemaValidationError(
|
191
|
+
"Invalid JSON Schema: Required fields must be defined in properties",
|
192
|
+
context={
|
193
|
+
"validation_type": "schema",
|
194
|
+
"missing_fields": missing_fields,
|
195
|
+
"tips": [
|
196
|
+
"Add the following fields to 'properties':",
|
197
|
+
*[f" - {field}" for field in missing_fields],
|
198
|
+
"Or remove them from 'required' if they are not needed",
|
199
|
+
],
|
200
|
+
},
|
201
|
+
)
|
202
|
+
|
203
|
+
# 6. Validate against JSON Schema meta-schema
|
204
|
+
try:
|
205
|
+
validator = jsonschema.validators.validator_for(schema_to_validate)
|
206
|
+
validator.check_schema(schema_to_validate)
|
207
|
+
except jsonschema.exceptions.SchemaError as e:
|
208
|
+
raise SchemaValidationError(
|
209
|
+
f"Invalid JSON Schema: {str(e)}",
|
210
|
+
context={
|
211
|
+
"validation_type": "schema",
|
212
|
+
"path": "/".join(str(p) for p in e.path),
|
213
|
+
"details": e.message,
|
214
|
+
"tips": [
|
215
|
+
"Ensure your schema follows JSON Schema specification",
|
216
|
+
"Check property types and formats",
|
217
|
+
"Validate schema structure",
|
218
|
+
],
|
219
|
+
},
|
220
|
+
)
|
221
|
+
|
222
|
+
except SchemaValidationError:
|
223
|
+
raise # Re-raise SchemaValidationError without wrapping
|
72
224
|
except Exception as e:
|
73
|
-
raise SchemaValidationError(
|
225
|
+
raise SchemaValidationError(
|
226
|
+
f"Invalid JSON Schema: {str(e)}",
|
227
|
+
context={
|
228
|
+
"validation_type": "schema",
|
229
|
+
"error": str(e),
|
230
|
+
"tips": ["Check schema syntax", "Validate JSON structure"],
|
231
|
+
},
|
232
|
+
)
|
74
233
|
|
75
234
|
|
76
235
|
def validate_response(
|
ostruct/cli/utils.py
CHANGED
@@ -12,7 +12,7 @@ def parse_mapping(mapping: str) -> Tuple[str, str]:
|
|
12
12
|
mapping: Mapping string in format 'name=value'
|
13
13
|
|
14
14
|
Returns:
|
15
|
-
Tuple of (name, value)
|
15
|
+
Tuple of (name, value) with whitespace stripped from both parts
|
16
16
|
|
17
17
|
Raises:
|
18
18
|
ValueError: If mapping format is invalid
|
@@ -23,6 +23,8 @@ def parse_mapping(mapping: str) -> Tuple[str, str]:
|
|
23
23
|
raise ValueError("Invalid mapping format")
|
24
24
|
|
25
25
|
name, value = mapping.split("=", 1)
|
26
|
+
name = name.strip()
|
27
|
+
value = value.strip()
|
26
28
|
if not name:
|
27
29
|
raise VariableNameError("Empty name in mapping")
|
28
30
|
if not value:
|
ostruct/cli/validators.py
CHANGED
@@ -49,7 +49,7 @@ def validate_variable(
|
|
49
49
|
value: List of "name=value" strings
|
50
50
|
|
51
51
|
Returns:
|
52
|
-
List of validated (name, value) tuples
|
52
|
+
List of validated (name, value) tuples with whitespace stripped from both parts
|
53
53
|
|
54
54
|
Raises:
|
55
55
|
click.BadParameter: If validation fails
|
@@ -64,6 +64,8 @@ def validate_variable(
|
|
64
64
|
f"Variable must be in format name=value: {var}"
|
65
65
|
)
|
66
66
|
name, val = var.split("=", 1)
|
67
|
+
name = name.strip()
|
68
|
+
val = val.strip()
|
67
69
|
if not name.isidentifier():
|
68
70
|
raise click.BadParameter(f"Invalid variable name: {name}")
|
69
71
|
result.append((name, val))
|
@@ -81,7 +83,7 @@ def validate_json_variable(
|
|
81
83
|
value: List of "name=json_string" values
|
82
84
|
|
83
85
|
Returns:
|
84
|
-
List of validated (name, parsed_json) tuples
|
86
|
+
List of validated (name, parsed_json) tuples with whitespace stripped from name
|
85
87
|
|
86
88
|
Raises:
|
87
89
|
click.BadParameter: If validation fails
|
@@ -96,6 +98,8 @@ def validate_json_variable(
|
|
96
98
|
f'JSON variable must be in format name=\'{"json":"value"}\': {var}'
|
97
99
|
)
|
98
100
|
name, json_str = var.split("=", 1)
|
101
|
+
name = name.strip()
|
102
|
+
json_str = json_str.strip()
|
99
103
|
if not name.isidentifier():
|
100
104
|
raise VariableNameError(f"Invalid variable name: {name}")
|
101
105
|
try:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: ostruct-cli
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0
|
4
4
|
Summary: CLI for OpenAI Structured Output
|
5
5
|
Author: Yaniv Golan
|
6
6
|
Author-email: yaniv@golan.name
|
@@ -16,7 +16,7 @@ Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
16
16
|
Requires-Dist: ijson (>=3.2.3,<4.0.0)
|
17
17
|
Requires-Dist: jsonschema (>=4.23.0,<5.0.0)
|
18
18
|
Requires-Dist: openai (>=1.0.0,<2.0.0)
|
19
|
-
Requires-Dist: openai-structured (>=2.
|
19
|
+
Requires-Dist: openai-structured (>=2.1.0,<3.0.0)
|
20
20
|
Requires-Dist: pydantic (>=2.6.3,<3.0.0)
|
21
21
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
22
22
|
Requires-Dist: tiktoken (==0.9.0)
|
@@ -33,7 +33,9 @@ Description-Content-Type: text/markdown
|
|
33
33
|
[](https://github.com/yaniv-golan/ostruct/actions/workflows/ci.yml)
|
34
34
|
[](https://opensource.org/licenses/MIT)
|
35
35
|
|
36
|
-
|
36
|
+
ostruct tranforms unstructured inputs into structured, usable JSON output using OpenAI APIs.
|
37
|
+
|
38
|
+
ostruct will process a set of plain text files (data, source code, CSV, etc), input variables, a dynamic prompt template, and a JSON schema specifying the desired output format, and will produce the result in JSON format.
|
37
39
|
|
38
40
|
## Features
|
39
41
|
|
@@ -42,6 +44,12 @@ Command-line interface for working with OpenAI models and structured output, pow
|
|
42
44
|
- Automatic token counting and context window management
|
43
45
|
- Streaming support for real-time output
|
44
46
|
- Secure handling of sensitive data
|
47
|
+
- Model registry management with support for updating to the latest OpenAI models
|
48
|
+
- Non-intrusive registry update checks with user notifications
|
49
|
+
|
50
|
+
## Requirements
|
51
|
+
|
52
|
+
- Python 3.10 or higher
|
45
53
|
|
46
54
|
## Installation
|
47
55
|
|
@@ -57,6 +65,16 @@ pip install ostruct-cli
|
|
57
65
|
|
58
66
|
If you plan to contribute to the project, see the [Development Setup](#development-setup) section below for instructions on setting up the development environment with Poetry.
|
59
67
|
|
68
|
+
## Environment Variables
|
69
|
+
|
70
|
+
ostruct-cli respects the following environment variables:
|
71
|
+
|
72
|
+
- `OPENAI_API_KEY`: Your OpenAI API key (required unless provided via command line)
|
73
|
+
- `OPENAI_API_BASE`: Custom API base URL (optional)
|
74
|
+
- `OPENAI_API_VERSION`: API version to use (optional)
|
75
|
+
- `OPENAI_API_TYPE`: API type (e.g., "azure") (optional)
|
76
|
+
- `OSTRUCT_DISABLE_UPDATE_CHECKS`: Set to "1", "true", or "yes" to disable automatic registry update checks
|
77
|
+
|
60
78
|
## Shell Completion
|
61
79
|
|
62
80
|
ostruct-cli supports shell completion for Bash, Zsh, and Fish shells. To enable it:
|
@@ -209,196 +227,84 @@ The command will output:
|
|
209
227
|
}
|
210
228
|
```
|
211
229
|
|
212
|
-
|
230
|
+
## System Prompt Handling
|
213
231
|
|
214
|
-
|
232
|
+
ostruct-cli provides three ways to specify a system prompt, with a clear precedence order:
|
215
233
|
|
216
|
-
|
217
|
-
Extract information about the people from this data:
|
234
|
+
1. Command-line option (`--sys-prompt` or `--sys-file`):
|
218
235
|
|
219
|
-
|
220
|
-
|
236
|
+
```bash
|
237
|
+
# Direct string
|
238
|
+
ostruct run template.j2 schema.json --sys-prompt "You are an expert analyst"
|
221
239
|
|
222
|
-
|
240
|
+
# From file
|
241
|
+
ostruct run template.j2 schema.json --sys-file system_prompt.txt
|
242
|
+
```
|
223
243
|
|
224
|
-
|
225
|
-
```
|
244
|
+
2. Template frontmatter:
|
226
245
|
|
227
|
-
|
246
|
+
```jinja
|
247
|
+
---
|
248
|
+
system_prompt: You are an expert analyst
|
249
|
+
---
|
250
|
+
Extract information from: {{ text }}
|
251
|
+
```
|
228
252
|
|
229
|
-
|
230
|
-
{
|
231
|
-
"type": "object",
|
232
|
-
"properties": {
|
233
|
-
"people": {
|
234
|
-
"type": "array",
|
235
|
-
"items": {
|
236
|
-
"type": "object",
|
237
|
-
"properties": {
|
238
|
-
"name": {
|
239
|
-
"type": "string",
|
240
|
-
"description": "The person's full name"
|
241
|
-
},
|
242
|
-
"age": {
|
243
|
-
"type": "integer",
|
244
|
-
"description": "The person's age"
|
245
|
-
},
|
246
|
-
"occupation": {
|
247
|
-
"type": "string",
|
248
|
-
"description": "The person's job or profession"
|
249
|
-
}
|
250
|
-
},
|
251
|
-
"required": ["name", "age", "occupation"],
|
252
|
-
"additionalProperties": false
|
253
|
-
}
|
254
|
-
}
|
255
|
-
},
|
256
|
-
"required": ["people"],
|
257
|
-
"additionalProperties": false
|
258
|
-
}
|
259
|
-
```
|
253
|
+
3. Default system prompt (built into the CLI)
|
260
254
|
|
261
|
-
|
255
|
+
### Precedence Rules
|
262
256
|
|
263
|
-
|
264
|
-
# Basic usage
|
265
|
-
ostruct run extract_from_profiles.j2 schema.json -p profiles "profiles/*.txt"
|
257
|
+
When multiple system prompts are provided, they are resolved in this order:
|
266
258
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
--model gpt-4o \
|
271
|
-
--sys-prompt "Extract precise information about the person" \
|
272
|
-
--temperature 0.5
|
273
|
-
```
|
259
|
+
1. Command-line options take highest precedence:
|
260
|
+
- If both `--sys-prompt` and `--sys-file` are provided, `--sys-prompt` wins
|
261
|
+
- Use `--ignore-task-sysprompt` to ignore template frontmatter
|
274
262
|
|
275
|
-
|
263
|
+
2. Template frontmatter is used if:
|
264
|
+
- No command-line options are provided
|
265
|
+
- `--ignore-task-sysprompt` is not set
|
276
266
|
|
277
|
-
|
278
|
-
{
|
279
|
-
"people": [
|
280
|
-
{
|
281
|
-
"name": "John Smith",
|
282
|
-
"age": 35,
|
283
|
-
"occupation": "software engineer"
|
284
|
-
},
|
285
|
-
{
|
286
|
-
"name": "Jane Doe",
|
287
|
-
"age": 28,
|
288
|
-
"occupation": "data scientist"
|
289
|
-
}
|
290
|
-
]
|
291
|
-
}
|
292
|
-
```
|
293
|
-
|
294
|
-
### About Template Files
|
295
|
-
|
296
|
-
Template files use the `.j2` extension to indicate they contain Jinja2 template syntax. This convention:
|
297
|
-
|
298
|
-
- Enables proper syntax highlighting in most editors
|
299
|
-
- Makes it clear the file contains template logic
|
300
|
-
- Follows industry standards for Jinja2 templates
|
267
|
+
3. Default system prompt is used only if no other prompts are provided
|
301
268
|
|
302
|
-
|
303
|
-
|
304
|
-
The CLI revolves around a single subcommand called `run`. Basic usage:
|
269
|
+
Example combining multiple sources:
|
305
270
|
|
306
271
|
```bash
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
Common options include:
|
311
|
-
|
312
|
-
- File & Directory Inputs:
|
313
|
-
- `-f <NAME> <PATH>`: Map a single file to a variable name
|
314
|
-
- `-d <NAME> <DIR>`: Map a directory to a variable name
|
315
|
-
- `-p <NAME> <PATTERN>`: Map files matching a glob pattern to a variable name
|
316
|
-
- `-R, --recursive`: Enable recursive directory/pattern scanning
|
317
|
-
|
318
|
-
- Variables:
|
319
|
-
- `-V name=value`: Define a simple string variable
|
320
|
-
- `-J name='{"key":"value"}'`: Define a JSON variable
|
321
|
-
|
322
|
-
- Model Parameters:
|
323
|
-
- `-m, --model MODEL`: Select the OpenAI model (supported: gpt-4o, o1, o3-mini)
|
324
|
-
- `--temperature FLOAT`: Set sampling temperature (0.0-2.0)
|
325
|
-
- `--max-output-tokens INT`: Set maximum output tokens
|
326
|
-
- `--top-p FLOAT`: Set top-p sampling parameter (0.0-1.0)
|
327
|
-
- `--frequency-penalty FLOAT`: Adjust frequency penalty (-2.0-2.0)
|
328
|
-
- `--presence-penalty FLOAT`: Adjust presence penalty (-2.0-2.0)
|
329
|
-
- `--reasoning-effort [low|medium|high]`: Control model reasoning effort
|
330
|
-
|
331
|
-
- System Prompt:
|
332
|
-
- `--sys-prompt TEXT`: Provide system prompt directly
|
333
|
-
- `--sys-file FILE`: Load system prompt from file
|
334
|
-
- `--ignore-task-sysprompt`: Ignore system prompt in template frontmatter
|
335
|
-
|
336
|
-
- API Configuration:
|
337
|
-
- `--api-key KEY`: OpenAI API key (defaults to OPENAI_API_KEY env var)
|
338
|
-
- `--timeout FLOAT`: API timeout in seconds (default: 60.0)
|
339
|
-
|
340
|
-
## Debug Options
|
341
|
-
|
342
|
-
- `--debug-validation`: Show detailed schema validation debugging
|
343
|
-
- `--debug-openai-stream`: Enable low-level debug output for OpenAI streaming
|
344
|
-
- `--progress-level {none,basic,detailed}`: Set progress reporting level
|
345
|
-
- `none`: No progress indicators
|
346
|
-
- `basic`: Show key operation steps (default)
|
347
|
-
- `detailed`: Show all steps with additional info
|
348
|
-
- `--show-model-schema`: Display the generated Pydantic model schema
|
349
|
-
- `--verbose`: Enable verbose logging
|
350
|
-
- `--dry-run`: Validate and render template without making API calls
|
351
|
-
- `--no-progress`: Disable all progress indicators
|
352
|
-
|
353
|
-
All debug and error logs are written to:
|
272
|
+
# Command-line prompt will override template frontmatter
|
273
|
+
ostruct run template.j2 schema.json --sys-prompt "Override prompt"
|
354
274
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
For more detailed documentation and examples, visit our [documentation](https://ostruct.readthedocs.io/).
|
359
|
-
|
360
|
-
## Development
|
361
|
-
|
362
|
-
To contribute or report issues, please visit our [GitHub repository](https://github.com/yaniv-golan/ostruct).
|
363
|
-
|
364
|
-
## Development Setup
|
365
|
-
|
366
|
-
1. Clone the repository:
|
367
|
-
|
368
|
-
```bash
|
369
|
-
git clone https://github.com/yanivgolan/ostruct.git
|
370
|
-
cd ostruct
|
275
|
+
# Ignore template frontmatter and use default
|
276
|
+
ostruct run template.j2 schema.json --ignore-task-sysprompt
|
371
277
|
```
|
372
278
|
|
373
|
-
|
279
|
+
## Model Registry Management
|
374
280
|
|
375
|
-
|
376
|
-
curl -sSL https://install.python-poetry.org | python3 -
|
377
|
-
```
|
281
|
+
ostruct-cli maintains a registry of OpenAI models and their capabilities, which includes:
|
378
282
|
|
379
|
-
|
283
|
+
- Context window sizes for each model
|
284
|
+
- Maximum output token limits
|
285
|
+
- Supported parameters and their constraints
|
286
|
+
- Model version information
|
380
287
|
|
381
|
-
|
382
|
-
poetry install
|
383
|
-
```
|
384
|
-
|
385
|
-
4. Install openai-structured in editable mode:
|
288
|
+
To ensure you're using the latest models and features, you can update the registry:
|
386
289
|
|
387
290
|
```bash
|
388
|
-
|
389
|
-
|
291
|
+
# Update from the official repository
|
292
|
+
ostruct update-registry
|
390
293
|
|
391
|
-
|
294
|
+
# Update from a custom URL
|
295
|
+
ostruct update-registry --url https://example.com/models.yml
|
392
296
|
|
393
|
-
|
394
|
-
|
297
|
+
# Force an update even if the registry is current
|
298
|
+
ostruct update-registry --force
|
395
299
|
```
|
396
300
|
|
397
|
-
|
301
|
+
This is especially useful when:
|
398
302
|
|
399
|
-
|
303
|
+
- New OpenAI models are released
|
304
|
+
- Model capabilities or parameters change
|
305
|
+
- You need to work with custom model configurations
|
400
306
|
|
401
|
-
|
307
|
+
The registry file is stored at `~/.openai_structured/config/models.yml` and is automatically referenced when validating model parameters and token limits.
|
402
308
|
|
403
|
-
|
309
|
+
The update command uses HTTP conditional requests (If-Modified-Since headers) to check if the remote registry has changed before downloading, ensuring efficient updates.
|
404
310
|
|
@@ -1,44 +1,45 @@
|
|
1
1
|
ostruct/__init__.py,sha256=X6zo6V7ZNMv731Wi388aTVQngD1410ExGwGx4J6lpyo,187
|
2
|
-
ostruct/cli/__init__.py,sha256=
|
2
|
+
ostruct/cli/__init__.py,sha256=IfQ68CRqPEeCP4zxV1DxowSEWFKhZiB8swMAOZJOXa8,494
|
3
3
|
ostruct/cli/base_errors.py,sha256=S1cQxoiALbXKPxzgLo6XdSWpzPRb7RKz0QARmu9Zt4g,5987
|
4
4
|
ostruct/cli/cache_manager.py,sha256=ej3KrRfkKKZ_lEp2JswjbJ5bW2ncsvna9NeJu81cqqs,5192
|
5
|
-
ostruct/cli/cli.py,sha256=
|
5
|
+
ostruct/cli/cli.py,sha256=WqVToFC4mt4qXeaW0pGRmakGal8vxxH0ny_BHNMKh5M,69645
|
6
6
|
ostruct/cli/click_options.py,sha256=WbRJdB9sO63ChN3fnCP7XWs73DHKl0C1ervfwL11am0,11371
|
7
|
-
ostruct/cli/errors.py,sha256=
|
7
|
+
ostruct/cli/errors.py,sha256=UytzS6RKOFMpB3GCJl73M93k74cutKOTFo5RDM4PTE0,15292
|
8
8
|
ostruct/cli/exit_codes.py,sha256=uNjvQeUGwU1mlUJYIDrExAn7YlwOXZo603yLAwpqIwk,338
|
9
9
|
ostruct/cli/file_info.py,sha256=ilpT8IuckfhadLF1QQAPLXJp7p8kVpffDEEJ2erHPZU,14485
|
10
10
|
ostruct/cli/file_list.py,sha256=jLuCd1ardoAXX8FNwPgIqEM-ixzr1xP5ZSqXo2lmrj0,11270
|
11
11
|
ostruct/cli/file_utils.py,sha256=J3-6fbEGQ7KD_bU81pAxueHLv9XV0X7f8FSMt_0AJGQ,22537
|
12
|
-
ostruct/cli/model_creation.py,sha256=
|
12
|
+
ostruct/cli/model_creation.py,sha256=UdXT3657rC5t-aZAZkQDuIdaQWSY9P6vgHKNAoFUWVw,16768
|
13
13
|
ostruct/cli/path_utils.py,sha256=j44q1OoLkqMErgK-qEuhuIZ1VyzqRIvNgxR1et9PoXA,4813
|
14
14
|
ostruct/cli/progress.py,sha256=rj9nVEco5UeZORMbzd7mFJpFGJjbH9KbBFh5oTE5Anw,3415
|
15
|
+
ostruct/cli/registry_updates.py,sha256=H0-Ftz4TvzryS2Qyoei7k2GKiY_s0Qr17i6pqrRmgF0,4921
|
15
16
|
ostruct/cli/schema_validation.py,sha256=ohEuxJ0KF93qphj0JSZDnrxDn0C2ZU37g-U2JY03onM,8154
|
16
17
|
ostruct/cli/security/__init__.py,sha256=CQpkCgTFYlA1p6atpQeNgIKtE4LZGUKt4EbytbGKpCs,846
|
17
18
|
ostruct/cli/security/allowed_checker.py,sha256=N5UXlpjdj5zAbKk-lRDlHiHV3KtQHtJNhtZI_qGB4zw,1638
|
18
19
|
ostruct/cli/security/base.py,sha256=q9YUdHEj2eg5w8GEw5403E9OQKIjZbEiaWsvYFnCGLw,1359
|
19
20
|
ostruct/cli/security/case_manager.py,sha256=I_ZJSyntLuGx5qVzze559CI-OxsaNPSibkAN8zZ7PvE,2345
|
20
|
-
ostruct/cli/security/errors.py,sha256=
|
21
|
-
ostruct/cli/security/normalization.py,sha256=
|
21
|
+
ostruct/cli/security/errors.py,sha256=8jYJFRQyEXIH3Wd2ATWORVoqbDg7qwu0TsuROpsqNfU,5254
|
22
|
+
ostruct/cli/security/normalization.py,sha256=ULvFopRLiUMC86yGxge5Jzjbvc64C_j2QlD5smKPjEI,5286
|
22
23
|
ostruct/cli/security/safe_joiner.py,sha256=PHowCeBAkfHfPqRwuO5Com0OemGuq3cHkdu2p9IYNT0,7107
|
23
|
-
ostruct/cli/security/security_manager.py,sha256=
|
24
|
+
ostruct/cli/security/security_manager.py,sha256=HFCqJ5kAhaZlFnPTEs6MKNM8JeE2q79db9jW-cHIvxw,15242
|
24
25
|
ostruct/cli/security/symlink_resolver.py,sha256=wtZdJ_T_0FOy6B1P5ty1odEXQk9vr8BzlWeAFD4huJE,16744
|
25
26
|
ostruct/cli/security/types.py,sha256=15yuG_T4CXyAFFFdSWLjVS7ACmDGIPXhQpZ8awcDwCQ,2991
|
26
27
|
ostruct/cli/security/windows_paths.py,sha256=qxC2H2kLwtmQ7YePYde3UrmOJcGnsLEebDLh242sUaI,13453
|
27
28
|
ostruct/cli/serialization.py,sha256=ec0UswDE2onwtZVUoZaMCsGv6zW_tSKdBng2qVo6Ucs,704
|
28
29
|
ostruct/cli/template_env.py,sha256=S2ZvxuMQMicodSVqUhrw0kOzbNmlpQjSHtWlOwjXCms,1538
|
29
|
-
ostruct/cli/template_extensions.py,sha256=
|
30
|
+
ostruct/cli/template_extensions.py,sha256=_lomtDGMGxMfpw05v_-daJ0JbhRm_r_-uEJlPAjbpkI,2699
|
30
31
|
ostruct/cli/template_filters.py,sha256=SjuQxlM5S283TS2El_AbrzETGnYoQeTpmA9sv5et3QI,19222
|
31
32
|
ostruct/cli/template_io.py,sha256=yUWO-8rZnSdX97DTMSEX8fG9CP1ISsOhm2NZN3Fab9A,8821
|
32
33
|
ostruct/cli/template_rendering.py,sha256=vp_4gvrYLd_kbQi3TYrYNniXLTeLmTaitGVBQManXvo,13342
|
33
34
|
ostruct/cli/template_schema.py,sha256=ckH4rUZnEgfm_BHS9LnMGr8LtDxRmZ0C6UBVrSp8KTc,19604
|
34
|
-
ostruct/cli/template_utils.py,sha256=
|
35
|
+
ostruct/cli/template_utils.py,sha256=MZdXXjL-x-IXX-5Y8GWopGNBkDE2ItLdCuCl0QWFR_U,14968
|
35
36
|
ostruct/cli/template_validation.py,sha256=AXa2zmsws1j-0CTFlp7fMiZR43iNLnj4h467up2JdgU,12693
|
36
37
|
ostruct/cli/token_utils.py,sha256=r4KPEO3Sec18Q6mU0aClK6XGShvusgUggXEQgEPPlaA,1369
|
37
|
-
ostruct/cli/utils.py,sha256=
|
38
|
-
ostruct/cli/validators.py,sha256=
|
38
|
+
ostruct/cli/utils.py,sha256=uY7c0NaINHWfnl77FcPE3TmYUXv3RqEeUTjrCMDij9A,922
|
39
|
+
ostruct/cli/validators.py,sha256=k-vmBjkPmC-VwSTM5Yq1zQjGSIOzzTHS4kc0B7Aqpck,3186
|
39
40
|
ostruct/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
|
-
ostruct_cli-0.
|
41
|
-
ostruct_cli-0.
|
42
|
-
ostruct_cli-0.
|
43
|
-
ostruct_cli-0.
|
44
|
-
ostruct_cli-0.
|
41
|
+
ostruct_cli-0.7.0.dist-info/LICENSE,sha256=QUOY6QCYVxAiH8vdrUTDqe3i9hQ5bcNczppDSVpLTjk,1068
|
42
|
+
ostruct_cli-0.7.0.dist-info/METADATA,sha256=1Z54LbqNhr6aRMLvoiTKeaeETc5fNQe31J7Msz4EmyA,8618
|
43
|
+
ostruct_cli-0.7.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
44
|
+
ostruct_cli-0.7.0.dist-info/entry_points.txt,sha256=NFq9IuqHVTem0j9zKjV8C1si_zGcP1RL6Wbvt9fUDXw,48
|
45
|
+
ostruct_cli-0.7.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|