pdd-cli 0.0.23__py3-none-any.whl → 0.0.25__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.
Potentially problematic release.
This version of pdd-cli might be problematic. Click here for more details.
- pdd/__init__.py +7 -1
- pdd/bug_main.py +21 -3
- pdd/bug_to_unit_test.py +16 -5
- pdd/change.py +2 -1
- pdd/change_main.py +407 -189
- pdd/cli.py +853 -301
- pdd/code_generator.py +2 -1
- pdd/conflicts_in_prompts.py +2 -1
- pdd/construct_paths.py +377 -222
- pdd/context_generator.py +2 -1
- pdd/continue_generation.py +3 -2
- pdd/crash_main.py +55 -20
- pdd/data/llm_model.csv +8 -8
- pdd/detect_change.py +2 -1
- pdd/fix_code_loop.py +465 -160
- pdd/fix_code_module_errors.py +7 -4
- pdd/fix_error_loop.py +9 -9
- pdd/fix_errors_from_unit_tests.py +207 -365
- pdd/fix_main.py +31 -4
- pdd/fix_verification_errors.py +285 -0
- pdd/fix_verification_errors_loop.py +975 -0
- pdd/fix_verification_main.py +412 -0
- pdd/generate_output_paths.py +427 -183
- pdd/generate_test.py +3 -2
- pdd/increase_tests.py +2 -2
- pdd/llm_invoke.py +18 -8
- pdd/pdd_completion.zsh +38 -1
- pdd/preprocess.py +3 -3
- pdd/process_csv_change.py +466 -154
- pdd/prompts/extract_prompt_split_LLM.prompt +7 -4
- pdd/prompts/extract_prompt_update_LLM.prompt +11 -5
- pdd/prompts/extract_unit_code_fix_LLM.prompt +2 -2
- pdd/prompts/find_verification_errors_LLM.prompt +25 -0
- pdd/prompts/fix_code_module_errors_LLM.prompt +29 -0
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +5 -5
- pdd/prompts/fix_verification_errors_LLM.prompt +20 -0
- pdd/prompts/generate_test_LLM.prompt +9 -3
- pdd/prompts/split_LLM.prompt +3 -3
- pdd/prompts/update_prompt_LLM.prompt +3 -3
- pdd/split.py +13 -12
- pdd/split_main.py +22 -13
- pdd/trace_main.py +7 -0
- pdd/xml_tagger.py +2 -1
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/METADATA +4 -4
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/RECORD +49 -44
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/WHEEL +1 -1
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/licenses/LICENSE +0 -0
- {pdd_cli-0.0.23.dist-info → pdd_cli-0.0.25.dist-info}/top_level.txt +0 -0
pdd/fix_main.py
CHANGED
|
@@ -2,10 +2,12 @@ import sys
|
|
|
2
2
|
from typing import Tuple, Optional
|
|
3
3
|
import click
|
|
4
4
|
from rich import print as rprint
|
|
5
|
+
from rich.markup import MarkupError, escape
|
|
5
6
|
|
|
6
7
|
import requests
|
|
7
8
|
import asyncio
|
|
8
9
|
import os
|
|
10
|
+
from pathlib import Path
|
|
9
11
|
|
|
10
12
|
from .preprocess import preprocess
|
|
11
13
|
|
|
@@ -15,6 +17,9 @@ from .fix_error_loop import fix_error_loop
|
|
|
15
17
|
from .get_jwt_token import get_jwt_token
|
|
16
18
|
from .get_language import get_language
|
|
17
19
|
|
|
20
|
+
# Import DEFAULT_STRENGTH from the package
|
|
21
|
+
from . import DEFAULT_STRENGTH
|
|
22
|
+
|
|
18
23
|
def fix_main(
|
|
19
24
|
ctx: click.Context,
|
|
20
25
|
prompt_file: str,
|
|
@@ -65,6 +70,12 @@ def fix_main(
|
|
|
65
70
|
analysis_results = None
|
|
66
71
|
|
|
67
72
|
try:
|
|
73
|
+
# Verify error file exists if not in loop mode
|
|
74
|
+
if not loop:
|
|
75
|
+
error_path = Path(error_file)
|
|
76
|
+
if not error_path.exists():
|
|
77
|
+
raise FileNotFoundError(f"Error file '{error_file}' does not exist.")
|
|
78
|
+
|
|
68
79
|
# Construct file paths
|
|
69
80
|
input_file_paths = {
|
|
70
81
|
"prompt_file": prompt_file,
|
|
@@ -85,11 +96,12 @@ def fix_main(
|
|
|
85
96
|
force=ctx.obj.get('force', False),
|
|
86
97
|
quiet=ctx.obj.get('quiet', False),
|
|
87
98
|
command="fix",
|
|
88
|
-
command_options=command_options
|
|
99
|
+
command_options=command_options,
|
|
100
|
+
create_error_file=loop # Only create error file if in loop mode
|
|
89
101
|
)
|
|
90
102
|
|
|
91
103
|
# Get parameters from context
|
|
92
|
-
strength = ctx.obj.get('strength',
|
|
104
|
+
strength = ctx.obj.get('strength', DEFAULT_STRENGTH)
|
|
93
105
|
temperature = ctx.obj.get('temperature', 0)
|
|
94
106
|
verbose = ctx.obj.get('verbose', False)
|
|
95
107
|
if loop:
|
|
@@ -139,7 +151,16 @@ def fix_main(
|
|
|
139
151
|
if verbose and analysis_results:
|
|
140
152
|
# Log the first 200 characters of analysis if in verbose mode
|
|
141
153
|
analysis_preview = analysis_results[:200] + "..." if len(analysis_results) > 200 else analysis_results
|
|
142
|
-
|
|
154
|
+
try:
|
|
155
|
+
# Attempt to print the preview using rich markup parsing
|
|
156
|
+
rprint(f"[bold]Analysis preview:[/bold] {analysis_preview}")
|
|
157
|
+
except MarkupError as me:
|
|
158
|
+
# If markup fails, print a warning and the escaped preview
|
|
159
|
+
rprint(f"[bold yellow]Warning:[/bold yellow] Analysis preview contained invalid markup: {me}")
|
|
160
|
+
rprint(f"[bold]Raw Analysis preview (escaped):[/bold] {escape(analysis_preview)}")
|
|
161
|
+
except Exception as e:
|
|
162
|
+
# Handle other potential errors during preview printing
|
|
163
|
+
rprint(f"[bold red]Error printing analysis preview: {e}[/bold red]")
|
|
143
164
|
if success:
|
|
144
165
|
rprint("[bold green]Fixed files saved:[/bold green]")
|
|
145
166
|
rprint(f" Test file: {output_file_paths['output_test']}")
|
|
@@ -263,5 +284,11 @@ def fix_main(
|
|
|
263
284
|
|
|
264
285
|
except Exception as e:
|
|
265
286
|
if not ctx.obj.get('quiet', False):
|
|
266
|
-
|
|
287
|
+
# Safely handle and print MarkupError
|
|
288
|
+
if isinstance(e, MarkupError):
|
|
289
|
+
rprint(f"[bold red]Markup Error in fix_main:[/bold red]")
|
|
290
|
+
rprint(escape(str(e)))
|
|
291
|
+
else:
|
|
292
|
+
# Print other errors normally (might still fail if they contain markup)
|
|
293
|
+
rprint(f"[bold red]Error:[/bold red] {str(e)}")
|
|
267
294
|
sys.exit(1)
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Dict, Any
|
|
3
|
+
from rich import print as rprint
|
|
4
|
+
from rich.markdown import Markdown
|
|
5
|
+
from .load_prompt_template import load_prompt_template
|
|
6
|
+
from .llm_invoke import llm_invoke
|
|
7
|
+
|
|
8
|
+
def fix_verification_errors(
|
|
9
|
+
program: str,
|
|
10
|
+
prompt: str,
|
|
11
|
+
code: str,
|
|
12
|
+
output: str,
|
|
13
|
+
strength: float,
|
|
14
|
+
temperature: float = 0.0,
|
|
15
|
+
verbose: bool = False,
|
|
16
|
+
) -> Dict[str, Any]:
|
|
17
|
+
"""
|
|
18
|
+
Identifies and fixes issues in a code module based on verification output.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
program: The program code that ran the code module.
|
|
22
|
+
prompt: The prompt used to generate the code module.
|
|
23
|
+
code: The code module to be fixed.
|
|
24
|
+
output: The output logs from the program run during verification.
|
|
25
|
+
strength: The strength (0-1) for the LLM model selection.
|
|
26
|
+
temperature: The temperature for the LLM model. Defaults to 0.
|
|
27
|
+
verbose: If True, prints detailed execution information. Defaults to False.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
A dictionary containing:
|
|
31
|
+
- 'explanation': A string with verification details and fix explanation
|
|
32
|
+
in XML format, or None if no issues were found.
|
|
33
|
+
- 'fixed_program': The potentially fixed program code string.
|
|
34
|
+
- 'fixed_code': The potentially fixed code module string.
|
|
35
|
+
- 'total_cost': The total cost incurred from LLM calls.
|
|
36
|
+
- 'model_name': The name of the LLM model used.
|
|
37
|
+
- 'verification_issues_count': The number of issues found during verification.
|
|
38
|
+
"""
|
|
39
|
+
total_cost = 0.0
|
|
40
|
+
model_name = None
|
|
41
|
+
verification_issues_count = 0
|
|
42
|
+
verification_details = None
|
|
43
|
+
fix_explanation = None
|
|
44
|
+
fixed_program = program
|
|
45
|
+
fixed_code = code
|
|
46
|
+
final_explanation = None
|
|
47
|
+
|
|
48
|
+
# Check only essential inputs, allow empty output
|
|
49
|
+
if not all([program, prompt, code]):
|
|
50
|
+
# Keep the error print for program, prompt, code missing
|
|
51
|
+
rprint("[bold red]Error:[/bold red] Missing one or more required inputs (program, prompt, code).")
|
|
52
|
+
return {
|
|
53
|
+
"explanation": None,
|
|
54
|
+
"fixed_program": program, # Return original if possible
|
|
55
|
+
"fixed_code": code, # Return original if possible
|
|
56
|
+
"total_cost": 0.0,
|
|
57
|
+
"model_name": None,
|
|
58
|
+
"verification_issues_count": 0,
|
|
59
|
+
}
|
|
60
|
+
if not (0.0 <= strength <= 1.0):
|
|
61
|
+
rprint(f"[bold red]Error:[/bold red] Strength must be between 0.0 and 1.0, got {strength}.")
|
|
62
|
+
return {
|
|
63
|
+
"explanation": None,
|
|
64
|
+
"fixed_program": program,
|
|
65
|
+
"fixed_code": code,
|
|
66
|
+
"total_cost": 0.0,
|
|
67
|
+
"model_name": None,
|
|
68
|
+
"verification_issues_count": 0,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if verbose:
|
|
72
|
+
rprint("[blue]Loading prompt templates...[/blue]")
|
|
73
|
+
try:
|
|
74
|
+
find_errors_prompt_template = load_prompt_template("find_verification_errors_LLM")
|
|
75
|
+
fix_errors_prompt_template = load_prompt_template("fix_verification_errors_LLM")
|
|
76
|
+
if not find_errors_prompt_template or not fix_errors_prompt_template:
|
|
77
|
+
raise ValueError("One or both prompt templates could not be loaded.")
|
|
78
|
+
except Exception as e:
|
|
79
|
+
rprint(f"[bold red]Error loading prompt templates:[/bold red] {e}")
|
|
80
|
+
return {
|
|
81
|
+
"explanation": None,
|
|
82
|
+
"fixed_program": program,
|
|
83
|
+
"fixed_code": code,
|
|
84
|
+
"total_cost": total_cost,
|
|
85
|
+
"model_name": model_name,
|
|
86
|
+
"verification_issues_count": verification_issues_count,
|
|
87
|
+
}
|
|
88
|
+
if verbose:
|
|
89
|
+
rprint("[green]Prompt templates loaded successfully.[/green]")
|
|
90
|
+
|
|
91
|
+
if verbose:
|
|
92
|
+
rprint(f"\n[blue]Step 2: Running verification check (Strength: {strength}, Temp: {temperature})...[/blue]")
|
|
93
|
+
|
|
94
|
+
verification_input_json = {
|
|
95
|
+
"program": program,
|
|
96
|
+
"prompt": prompt,
|
|
97
|
+
"code": code,
|
|
98
|
+
"output": output,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
verification_response = llm_invoke(
|
|
103
|
+
prompt=find_errors_prompt_template,
|
|
104
|
+
input_json=verification_input_json,
|
|
105
|
+
strength=strength,
|
|
106
|
+
temperature=temperature,
|
|
107
|
+
verbose=False, # Keep internal llm_invoke verbose off unless needed
|
|
108
|
+
)
|
|
109
|
+
total_cost += verification_response.get('cost', 0.0)
|
|
110
|
+
model_name = verification_response.get('model_name', model_name)
|
|
111
|
+
verification_result = verification_response.get('result', '')
|
|
112
|
+
|
|
113
|
+
if verbose:
|
|
114
|
+
rprint(f"[cyan]Verification LLM call complete.[/cyan]")
|
|
115
|
+
rprint(f" [dim]Model Used:[/dim] {verification_response.get('model_name', 'N/A')}")
|
|
116
|
+
rprint(f" [dim]Cost:[/dim] ${verification_response.get('cost', 0.0):.6f}")
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
rprint(f"[bold red]Error during verification LLM call:[/bold red] {e}")
|
|
120
|
+
return {
|
|
121
|
+
"explanation": None,
|
|
122
|
+
"fixed_program": program,
|
|
123
|
+
"fixed_code": code,
|
|
124
|
+
"total_cost": total_cost,
|
|
125
|
+
"model_name": model_name,
|
|
126
|
+
"verification_issues_count": verification_issues_count,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if verbose:
|
|
130
|
+
rprint("\n[blue]Verification Result:[/blue]")
|
|
131
|
+
# Markdown object handles its own rendering, no extra needed here
|
|
132
|
+
rprint(Markdown(verification_result))
|
|
133
|
+
|
|
134
|
+
issues_found = False
|
|
135
|
+
try:
|
|
136
|
+
# Attempt to match and extract digits directly
|
|
137
|
+
count_match = re.search(r"<issues_count>(\d+)</issues_count>", verification_result)
|
|
138
|
+
if count_match:
|
|
139
|
+
verification_issues_count = int(count_match.group(1)) # Safe due to \d+
|
|
140
|
+
else:
|
|
141
|
+
# Specific match failed, check if tag exists with invalid content or is missing
|
|
142
|
+
generic_count_match = re.search(r"<issues_count>(.*?)</issues_count>", verification_result, re.DOTALL)
|
|
143
|
+
if generic_count_match:
|
|
144
|
+
# Tag found, but content is not \d+ -> Parsing Error
|
|
145
|
+
rprint("[bold red]Error:[/bold red] Could not parse integer value from <issues_count> tag.")
|
|
146
|
+
# Return the specific error structure for parsing errors after verification call
|
|
147
|
+
return {
|
|
148
|
+
"explanation": None,
|
|
149
|
+
"fixed_program": program,
|
|
150
|
+
"fixed_code": code,
|
|
151
|
+
"total_cost": total_cost, # Cost incurred so far
|
|
152
|
+
"model_name": model_name, # Model used so far
|
|
153
|
+
"verification_issues_count": 0, # Reset count on parsing error
|
|
154
|
+
}
|
|
155
|
+
else:
|
|
156
|
+
# Tag truly not found -> Warning
|
|
157
|
+
rprint("[yellow]Warning:[/yellow] Could not find <issues_count> tag in verification result. Assuming 0 issues.")
|
|
158
|
+
verification_issues_count = 0
|
|
159
|
+
|
|
160
|
+
# Proceed to check for details tag if count > 0
|
|
161
|
+
if verification_issues_count > 0:
|
|
162
|
+
details_match = re.search(r"<details>(.*?)</details>", verification_result, re.DOTALL)
|
|
163
|
+
if details_match:
|
|
164
|
+
verification_details = details_match.group(1).strip()
|
|
165
|
+
if verification_details:
|
|
166
|
+
issues_found = True
|
|
167
|
+
if verbose:
|
|
168
|
+
rprint(f"\n[yellow]Found {verification_issues_count} potential issues. Proceeding to fix step.[/yellow]")
|
|
169
|
+
else:
|
|
170
|
+
# Count > 0, but details empty -> Warning
|
|
171
|
+
rprint("[yellow]Warning:[/yellow] <issues_count> is > 0, but <details> tag is empty. Treating as no issues found.")
|
|
172
|
+
verification_issues_count = 0 # Reset count
|
|
173
|
+
else:
|
|
174
|
+
# Count > 0, but no details tag -> Warning
|
|
175
|
+
rprint("[yellow]Warning:[/yellow] <issues_count> is > 0, but could not find <details> tag. Treating as no issues found.")
|
|
176
|
+
verification_issues_count = 0 # Reset count
|
|
177
|
+
else:
|
|
178
|
+
# verification_issues_count is 0 (either parsed as 0 or defaulted after warning)
|
|
179
|
+
if verbose:
|
|
180
|
+
rprint("\n[green]No issues found during verification.[/green]")
|
|
181
|
+
|
|
182
|
+
# Removed ValueError catch as it's handled by the logic above
|
|
183
|
+
except Exception as e:
|
|
184
|
+
# Generic catch for other potential parsing issues
|
|
185
|
+
rprint(f"[bold red]Error parsing verification result:[/bold red] {e}")
|
|
186
|
+
return {
|
|
187
|
+
"explanation": None,
|
|
188
|
+
"fixed_program": program,
|
|
189
|
+
"fixed_code": code,
|
|
190
|
+
"total_cost": total_cost,
|
|
191
|
+
"model_name": model_name,
|
|
192
|
+
"verification_issues_count": 0, # Reset count on parsing error
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if issues_found and verification_details:
|
|
196
|
+
if verbose:
|
|
197
|
+
rprint(f"\n[blue]Step 5: Running fix generation (Strength: {strength}, Temp: {temperature})...[/blue]")
|
|
198
|
+
|
|
199
|
+
fix_input_json = {
|
|
200
|
+
"program": program,
|
|
201
|
+
"prompt": prompt,
|
|
202
|
+
"code": code,
|
|
203
|
+
"output": output,
|
|
204
|
+
"issues": verification_details,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
fix_response = llm_invoke(
|
|
209
|
+
prompt=fix_errors_prompt_template,
|
|
210
|
+
input_json=fix_input_json,
|
|
211
|
+
strength=strength,
|
|
212
|
+
temperature=temperature,
|
|
213
|
+
verbose=False, # Keep internal llm_invoke verbose off unless needed
|
|
214
|
+
)
|
|
215
|
+
total_cost += fix_response.get('cost', 0.0)
|
|
216
|
+
model_name = fix_response.get('model_name', model_name) # Update model name to the last one used
|
|
217
|
+
fix_result = fix_response.get('result', '')
|
|
218
|
+
|
|
219
|
+
if verbose:
|
|
220
|
+
rprint(f"[cyan]Fix LLM call complete.[/cyan]")
|
|
221
|
+
rprint(f" [dim]Model Used:[/dim] {fix_response.get('model_name', 'N/A')}")
|
|
222
|
+
rprint(f" [dim]Cost:[/dim] ${fix_response.get('cost', 0.0):.6f}")
|
|
223
|
+
rprint("\n[blue]Fix Result:[/blue]")
|
|
224
|
+
# Markdown object handles its own rendering, no extra needed here
|
|
225
|
+
rprint(Markdown(fix_result))
|
|
226
|
+
|
|
227
|
+
fixed_program_match = re.search(r"<fixed_program>(.*?)</fixed_program>", fix_result, re.DOTALL)
|
|
228
|
+
fixed_code_match = re.search(r"<fixed_code>(.*?)</fixed_code>", fix_result, re.DOTALL)
|
|
229
|
+
explanation_match = re.search(r"<explanation>(.*?)</explanation>", fix_result, re.DOTALL)
|
|
230
|
+
|
|
231
|
+
if fixed_program_match:
|
|
232
|
+
fixed_program = fixed_program_match.group(1).strip()
|
|
233
|
+
if verbose: rprint("[green]Extracted fixed program.[/green]")
|
|
234
|
+
else:
|
|
235
|
+
if verbose: rprint("[yellow]Warning:[/yellow] Could not find <fixed_program> tag in fix result. Using original program.")
|
|
236
|
+
|
|
237
|
+
if fixed_code_match:
|
|
238
|
+
fixed_code = fixed_code_match.group(1).strip()
|
|
239
|
+
if verbose: rprint("[green]Extracted fixed code module.[/green]")
|
|
240
|
+
else:
|
|
241
|
+
if verbose: rprint("[yellow]Warning:[/yellow] Could not find <fixed_code> tag in fix result. Using original code module.")
|
|
242
|
+
|
|
243
|
+
if explanation_match:
|
|
244
|
+
fix_explanation = explanation_match.group(1).strip()
|
|
245
|
+
if verbose: rprint("[green]Extracted fix explanation.[/green]")
|
|
246
|
+
else:
|
|
247
|
+
if verbose: rprint("[yellow]Warning:[/yellow] Could not find <explanation> tag in fix result.")
|
|
248
|
+
fix_explanation = "[Fix explanation not provided by LLM]"
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
rprint(f"[bold red]Error during fix LLM call or extraction:[/bold red] {e}")
|
|
252
|
+
# Combine verification details with the error message if fix failed
|
|
253
|
+
final_explanation = f"<error>Error during fix generation: {str(e)}</error>\n"
|
|
254
|
+
if verification_details:
|
|
255
|
+
fix_explanation = f"[Error during fix generation: {e}]"
|
|
256
|
+
# Note: verification_issues_count should retain its value from the verification step
|
|
257
|
+
|
|
258
|
+
if verbose:
|
|
259
|
+
rprint(f"\n[bold blue]Total Cost for fix_verification_errors run:[/bold blue] ${total_cost:.6f}")
|
|
260
|
+
|
|
261
|
+
# Construct final explanation only if issues were initially found and processed
|
|
262
|
+
if verification_details:
|
|
263
|
+
if fix_explanation:
|
|
264
|
+
final_explanation = (
|
|
265
|
+
f"<verification_details>{verification_details}</verification_details>\n"
|
|
266
|
+
f"<fix_explanation>{fix_explanation}</fix_explanation>"
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
# This case might occur if fix step wasn't run due to parsing issues after verification,
|
|
270
|
+
# or if fix_explanation extraction failed silently (though we added a default).
|
|
271
|
+
# Let's ensure we always provide some context if details were found.
|
|
272
|
+
final_explanation = (
|
|
273
|
+
f"<verification_details>{verification_details}</verification_details>\n"
|
|
274
|
+
f"<fix_explanation>[Fix explanation not available or fix step skipped]</fix_explanation>"
|
|
275
|
+
)
|
|
276
|
+
# If no issues were found initially (verification_details is None), final_explanation remains None
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
"explanation": final_explanation,
|
|
280
|
+
"fixed_program": fixed_program,
|
|
281
|
+
"fixed_code": fixed_code,
|
|
282
|
+
"total_cost": total_cost,
|
|
283
|
+
"model_name": model_name,
|
|
284
|
+
"verification_issues_count": verification_issues_count,
|
|
285
|
+
}
|