vbagent 0.1.1__py3-none-any.whl → 0.2.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.
- vbagent/__init__.py +220 -2
- vbagent/agents/__init__.py +84 -1
- vbagent/agents/converter.py +2 -2
- vbagent/agents/reviewer.py +2 -2
- vbagent/agents/tikz_checker.py +351 -37
- vbagent/agents/variant.py +74 -0
- vbagent/cli/check.py +750 -34
- vbagent/cli/common.py +87 -25
- vbagent/cli/convert.py +1 -1
- vbagent/models/__init__.py +41 -4
- vbagent/prompts/__init__.py +120 -1
- vbagent/prompts/converter.py +317 -74
- vbagent/prompts/tikz_checker.py +91 -3
- vbagent/references/__init__.py +60 -3
- vbagent-0.2.0.dist-info/METADATA +1049 -0
- {vbagent-0.1.1.dist-info → vbagent-0.2.0.dist-info}/RECORD +18 -18
- vbagent-0.1.1.dist-info/METADATA +0 -383
- {vbagent-0.1.1.dist-info → vbagent-0.2.0.dist-info}/WHEEL +0 -0
- {vbagent-0.1.1.dist-info → vbagent-0.2.0.dist-info}/entry_points.txt +0 -0
vbagent/cli/common.py
CHANGED
|
@@ -684,16 +684,19 @@ def find_image_for_problem(
|
|
|
684
684
|
tex_file: Path,
|
|
685
685
|
images_dir: Optional[str | Path] = None,
|
|
686
686
|
extensions: tuple[str, ...] = (".png", ".jpg", ".jpeg", ".webp", ".gif"),
|
|
687
|
+
auto_discover: bool = True,
|
|
687
688
|
) -> Optional[Path]:
|
|
688
689
|
"""Find the corresponding image file for a tex file.
|
|
689
690
|
|
|
690
|
-
Searches for an image with the same base name as the tex file
|
|
691
|
-
|
|
691
|
+
Searches for an image with the same base name as the tex file.
|
|
692
|
+
If images_dir is not provided and auto_discover is True, searches
|
|
693
|
+
common image locations automatically.
|
|
692
694
|
|
|
693
695
|
Args:
|
|
694
696
|
tex_file: Path to the .tex file
|
|
695
697
|
images_dir: Directory to search for images (optional)
|
|
696
698
|
extensions: Image file extensions to search for
|
|
699
|
+
auto_discover: Whether to auto-search common locations if images_dir not provided
|
|
697
700
|
|
|
698
701
|
Returns:
|
|
699
702
|
Path to the image file if found, None otherwise
|
|
@@ -702,39 +705,98 @@ def find_image_for_problem(
|
|
|
702
705
|
tex_file = Path("src/src_tex/problem_1.tex")
|
|
703
706
|
images_dir = "src/src_images"
|
|
704
707
|
# Will look for: src/src_images/problem_1.png, problem_1.jpg, etc.
|
|
708
|
+
|
|
709
|
+
# Auto-discovery (when images_dir is None):
|
|
710
|
+
tex_file = Path("agentic/scans/Problem_12.tex")
|
|
711
|
+
# Will search: images/, ../images/, agentic/images/, etc.
|
|
705
712
|
"""
|
|
706
|
-
|
|
713
|
+
base_name = tex_file.stem
|
|
714
|
+
|
|
715
|
+
def _search_in_dir(search_dir: Path) -> Optional[Path]:
|
|
716
|
+
"""Search for image in a specific directory."""
|
|
717
|
+
if not search_dir.exists():
|
|
718
|
+
return None
|
|
719
|
+
|
|
720
|
+
for ext in extensions:
|
|
721
|
+
image_path = search_dir / f"{base_name}{ext}"
|
|
722
|
+
if image_path.exists():
|
|
723
|
+
return image_path
|
|
724
|
+
|
|
725
|
+
# Also try case-insensitive match
|
|
726
|
+
image_path_upper = search_dir / f"{base_name}{ext.upper()}"
|
|
727
|
+
if image_path_upper.exists():
|
|
728
|
+
return image_path_upper
|
|
729
|
+
|
|
730
|
+
# Try glob pattern for case-insensitive search
|
|
731
|
+
for ext in extensions:
|
|
732
|
+
pattern = f"{base_name}.*"
|
|
733
|
+
matches = list(search_dir.glob(pattern))
|
|
734
|
+
for match in matches:
|
|
735
|
+
if match.suffix.lower() in extensions:
|
|
736
|
+
return match
|
|
737
|
+
|
|
707
738
|
return None
|
|
708
739
|
|
|
709
|
-
|
|
710
|
-
if not
|
|
740
|
+
# If images_dir is explicitly provided, search only there
|
|
741
|
+
if images_dir is not None:
|
|
742
|
+
images_path = Path(images_dir)
|
|
743
|
+
return _search_in_dir(images_path)
|
|
744
|
+
|
|
745
|
+
# Auto-discovery mode
|
|
746
|
+
if not auto_discover:
|
|
711
747
|
return None
|
|
712
748
|
|
|
713
|
-
|
|
714
|
-
|
|
749
|
+
tex_dir = tex_file.parent
|
|
750
|
+
|
|
751
|
+
# Common image directory locations to search (in priority order)
|
|
752
|
+
search_locations = [
|
|
753
|
+
# Same directory as tex file
|
|
754
|
+
tex_dir,
|
|
755
|
+
# images/ sibling directory
|
|
756
|
+
tex_dir.parent / "images",
|
|
757
|
+
# images/ subdirectory
|
|
758
|
+
tex_dir / "images",
|
|
759
|
+
# Parent's parent images/ (for nested structures like agentic/scans/)
|
|
760
|
+
tex_dir.parent.parent / "images",
|
|
761
|
+
# src_images pattern (common in some projects)
|
|
762
|
+
tex_dir.parent / "src_images",
|
|
763
|
+
]
|
|
715
764
|
|
|
716
|
-
#
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
for ext in extensions:
|
|
729
|
-
pattern = f"{base_name}.*"
|
|
730
|
-
matches = list(images_path.glob(pattern))
|
|
731
|
-
for match in matches:
|
|
732
|
-
if match.suffix.lower() in extensions:
|
|
733
|
-
return match
|
|
765
|
+
# Also check for pattern-based sibling directories
|
|
766
|
+
# e.g., src_tex -> src_images, scans -> images
|
|
767
|
+
dir_name = tex_dir.name
|
|
768
|
+
if dir_name.endswith("_tex"):
|
|
769
|
+
search_locations.append(tex_dir.parent / dir_name.replace("_tex", "_images"))
|
|
770
|
+
if dir_name == "scans":
|
|
771
|
+
search_locations.append(tex_dir.parent / "images")
|
|
772
|
+
|
|
773
|
+
for search_dir in search_locations:
|
|
774
|
+
result = _search_in_dir(search_dir)
|
|
775
|
+
if result:
|
|
776
|
+
return result
|
|
734
777
|
|
|
735
778
|
return None
|
|
736
779
|
|
|
737
780
|
|
|
781
|
+
def has_diagram_placeholder(content: str) -> bool:
|
|
782
|
+
"""Check if content contains a diagram placeholder that needs an image.
|
|
783
|
+
|
|
784
|
+
Detects patterns like:
|
|
785
|
+
- \\input{diagram}
|
|
786
|
+
- % \\input{diagram} (commented placeholder)
|
|
787
|
+
- \\begin{center}\\input{diagram}\\end{center}
|
|
788
|
+
|
|
789
|
+
Args:
|
|
790
|
+
content: LaTeX content to check
|
|
791
|
+
|
|
792
|
+
Returns:
|
|
793
|
+
True if a diagram placeholder is found (including commented ones)
|
|
794
|
+
"""
|
|
795
|
+
import re
|
|
796
|
+
# Match both active and commented placeholders
|
|
797
|
+
return bool(re.search(r'%?\s*\\input\{diagram\}', content))
|
|
798
|
+
|
|
799
|
+
|
|
738
800
|
def discover_images_dir(tex_dir: Path) -> Optional[Path]:
|
|
739
801
|
"""Auto-discover images directory based on tex directory structure.
|
|
740
802
|
|
vbagent/cli/convert.py
CHANGED
|
@@ -86,7 +86,7 @@ def _format_latex(content: str) -> str:
|
|
|
86
86
|
return '\n'.join(formatted_lines)
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
VALID_FORMAT_CHOICES = ["mcq_sc", "mcq_mc", "subjective", "integer"]
|
|
89
|
+
VALID_FORMAT_CHOICES = ["mcq_sc", "mcq_mc", "subjective", "integer", "match", "passage"]
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
def parse_tex_content(tex_path: str) -> str:
|
vbagent/models/__init__.py
CHANGED
|
@@ -1,38 +1,67 @@
|
|
|
1
1
|
"""Data models for vbagent.
|
|
2
2
|
|
|
3
3
|
Uses lazy imports to avoid loading pydantic until models are actually needed.
|
|
4
|
+
|
|
5
|
+
Available models:
|
|
6
|
+
- ClassificationResult: Result from image classification
|
|
7
|
+
- ScanResult: Result from LaTeX extraction
|
|
8
|
+
- IdeaResult: Extracted physics concepts
|
|
9
|
+
- PipelineResult: Full pipeline output
|
|
10
|
+
- ReviewResult, Suggestion, ReviewStats: QA review models
|
|
11
|
+
- VersionStore, StoredSuggestion: Version tracking
|
|
12
|
+
- BatchResult, BatchStats: Batch processing models
|
|
4
13
|
"""
|
|
5
14
|
|
|
6
15
|
from typing import TYPE_CHECKING
|
|
7
16
|
|
|
8
17
|
if TYPE_CHECKING:
|
|
9
|
-
from .classification import ClassificationResult
|
|
18
|
+
from .classification import ClassificationResult, QuestionType, Difficulty, DiagramType
|
|
10
19
|
from .scan import ScanResult
|
|
11
20
|
from .idea import IdeaResult
|
|
12
21
|
from .pipeline import PipelineResult
|
|
13
22
|
from .review import ReviewIssueType, Suggestion, ReviewResult, ReviewStats
|
|
14
23
|
from .version_store import SuggestionStatus, StoredSuggestion, VersionStore
|
|
24
|
+
from .batch import BatchDatabase, ImageRecord, ProcessingStatus
|
|
25
|
+
from .diff import generate_unified_diff, apply_unified_diff, apply_diff, parse_diff
|
|
15
26
|
|
|
16
27
|
__all__ = [
|
|
28
|
+
# Classification
|
|
17
29
|
"ClassificationResult",
|
|
30
|
+
"QuestionType",
|
|
31
|
+
"Difficulty",
|
|
32
|
+
"DiagramType",
|
|
33
|
+
# Scan
|
|
18
34
|
"ScanResult",
|
|
35
|
+
# Idea
|
|
19
36
|
"IdeaResult",
|
|
37
|
+
# Pipeline
|
|
20
38
|
"PipelineResult",
|
|
39
|
+
# Review
|
|
21
40
|
"ReviewIssueType",
|
|
22
41
|
"Suggestion",
|
|
23
42
|
"ReviewResult",
|
|
24
43
|
"ReviewStats",
|
|
44
|
+
# Version store
|
|
25
45
|
"SuggestionStatus",
|
|
26
46
|
"StoredSuggestion",
|
|
27
47
|
"VersionStore",
|
|
48
|
+
# Batch
|
|
49
|
+
"BatchDatabase",
|
|
50
|
+
"ImageRecord",
|
|
51
|
+
"ProcessingStatus",
|
|
52
|
+
# Diff utilities
|
|
53
|
+
"generate_unified_diff",
|
|
54
|
+
"apply_unified_diff",
|
|
55
|
+
"apply_diff",
|
|
56
|
+
"parse_diff",
|
|
28
57
|
]
|
|
29
58
|
|
|
30
59
|
|
|
31
60
|
def __getattr__(name: str):
|
|
32
61
|
"""Lazy import of model classes to speed up CLI startup."""
|
|
33
|
-
if name
|
|
34
|
-
from .
|
|
35
|
-
return
|
|
62
|
+
if name in ("ClassificationResult", "QuestionType", "Difficulty", "DiagramType"):
|
|
63
|
+
from . import classification
|
|
64
|
+
return getattr(classification, name)
|
|
36
65
|
|
|
37
66
|
if name == "ScanResult":
|
|
38
67
|
from .scan import ScanResult
|
|
@@ -54,4 +83,12 @@ def __getattr__(name: str):
|
|
|
54
83
|
from . import version_store
|
|
55
84
|
return getattr(version_store, name)
|
|
56
85
|
|
|
86
|
+
if name in ("BatchDatabase", "ImageRecord", "ProcessingStatus"):
|
|
87
|
+
from . import batch
|
|
88
|
+
return getattr(batch, name)
|
|
89
|
+
|
|
90
|
+
if name in ("generate_unified_diff", "apply_unified_diff", "apply_diff", "parse_diff"):
|
|
91
|
+
from . import diff
|
|
92
|
+
return getattr(diff, name)
|
|
93
|
+
|
|
57
94
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
vbagent/prompts/__init__.py
CHANGED
|
@@ -1 +1,120 @@
|
|
|
1
|
-
"""Prompt modules for vbagent agents.
|
|
1
|
+
"""Prompt modules for vbagent agents.
|
|
2
|
+
|
|
3
|
+
Provides prompt templates for all agent types. These can be used
|
|
4
|
+
to customize agent behavior or create custom agents.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from vbagent.prompts import get_scanner_prompt, get_variant_prompt
|
|
8
|
+
|
|
9
|
+
# Get scanner prompt for MCQ questions
|
|
10
|
+
prompt = get_scanner_prompt("mcq_sc")
|
|
11
|
+
|
|
12
|
+
# Get variant prompts
|
|
13
|
+
system, user = get_variant_prompt("numerical")
|
|
14
|
+
|
|
15
|
+
# Access individual prompts
|
|
16
|
+
from vbagent.prompts import CLASSIFIER_PROMPT, IDEA_PROMPT
|
|
17
|
+
|
|
18
|
+
Available prompt modules:
|
|
19
|
+
- scanner: LaTeX extraction prompts by question type
|
|
20
|
+
- variants: Problem variant generation prompts
|
|
21
|
+
- classifier: Image classification prompt
|
|
22
|
+
- idea: Concept extraction prompt
|
|
23
|
+
- alternate: Alternate solution prompt
|
|
24
|
+
- reviewer: QA review prompt
|
|
25
|
+
- tikz: TikZ diagram generation prompt
|
|
26
|
+
- solution_checker, grammar_checker, clarity_checker, tikz_checker: QA checker prompts
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from typing import TYPE_CHECKING
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from .scanner import get_scanner_prompt, SCANNER_PROMPTS
|
|
33
|
+
from .classifier import SYSTEM_PROMPT as CLASSIFIER_PROMPT
|
|
34
|
+
from .idea import SYSTEM_PROMPT as IDEA_PROMPT
|
|
35
|
+
from .alternate import SYSTEM_PROMPT as ALTERNATE_PROMPT
|
|
36
|
+
from .reviewer import SYSTEM_PROMPT as REVIEWER_PROMPT
|
|
37
|
+
from .tikz import SYSTEM_PROMPT as TIKZ_PROMPT
|
|
38
|
+
from .solution_checker import SYSTEM_PROMPT as SOLUTION_CHECKER_PROMPT
|
|
39
|
+
from .grammar_checker import SYSTEM_PROMPT as GRAMMAR_CHECKER_PROMPT
|
|
40
|
+
from .clarity_checker import SYSTEM_PROMPT as CLARITY_CHECKER_PROMPT
|
|
41
|
+
from .tikz_checker import SYSTEM_PROMPT as TIKZ_CHECKER_PROMPT
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
# Scanner
|
|
45
|
+
"get_scanner_prompt",
|
|
46
|
+
"SCANNER_PROMPTS",
|
|
47
|
+
# Variant
|
|
48
|
+
"get_variant_prompt",
|
|
49
|
+
# Individual prompts
|
|
50
|
+
"CLASSIFIER_PROMPT",
|
|
51
|
+
"IDEA_PROMPT",
|
|
52
|
+
"ALTERNATE_PROMPT",
|
|
53
|
+
"REVIEWER_PROMPT",
|
|
54
|
+
"TIKZ_PROMPT",
|
|
55
|
+
"SOLUTION_CHECKER_PROMPT",
|
|
56
|
+
"GRAMMAR_CHECKER_PROMPT",
|
|
57
|
+
"CLARITY_CHECKER_PROMPT",
|
|
58
|
+
"TIKZ_CHECKER_PROMPT",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_variant_prompt(variant_type: str) -> tuple[str, str]:
|
|
63
|
+
"""Get the system and user prompts for a variant type.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
variant_type: Type of variant (numerical, context, conceptual, calculus)
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Tuple of (system_prompt, user_template)
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ValueError: If variant_type is not valid
|
|
73
|
+
"""
|
|
74
|
+
from vbagent.agents.variant import get_variant_prompt as _get_variant_prompt
|
|
75
|
+
return _get_variant_prompt(variant_type)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def __getattr__(name: str):
|
|
79
|
+
"""Lazy import of prompt modules."""
|
|
80
|
+
if name in ("get_scanner_prompt", "SCANNER_PROMPTS"):
|
|
81
|
+
from . import scanner
|
|
82
|
+
return getattr(scanner, name)
|
|
83
|
+
|
|
84
|
+
if name == "CLASSIFIER_PROMPT":
|
|
85
|
+
from .classifier import SYSTEM_PROMPT
|
|
86
|
+
return SYSTEM_PROMPT
|
|
87
|
+
|
|
88
|
+
if name == "IDEA_PROMPT":
|
|
89
|
+
from .idea import SYSTEM_PROMPT
|
|
90
|
+
return SYSTEM_PROMPT
|
|
91
|
+
|
|
92
|
+
if name == "ALTERNATE_PROMPT":
|
|
93
|
+
from .alternate import SYSTEM_PROMPT
|
|
94
|
+
return SYSTEM_PROMPT
|
|
95
|
+
|
|
96
|
+
if name == "REVIEWER_PROMPT":
|
|
97
|
+
from .reviewer import SYSTEM_PROMPT
|
|
98
|
+
return SYSTEM_PROMPT
|
|
99
|
+
|
|
100
|
+
if name == "TIKZ_PROMPT":
|
|
101
|
+
from .tikz import SYSTEM_PROMPT
|
|
102
|
+
return SYSTEM_PROMPT
|
|
103
|
+
|
|
104
|
+
if name == "SOLUTION_CHECKER_PROMPT":
|
|
105
|
+
from .solution_checker import SYSTEM_PROMPT
|
|
106
|
+
return SYSTEM_PROMPT
|
|
107
|
+
|
|
108
|
+
if name == "GRAMMAR_CHECKER_PROMPT":
|
|
109
|
+
from .grammar_checker import SYSTEM_PROMPT
|
|
110
|
+
return SYSTEM_PROMPT
|
|
111
|
+
|
|
112
|
+
if name == "CLARITY_CHECKER_PROMPT":
|
|
113
|
+
from .clarity_checker import SYSTEM_PROMPT
|
|
114
|
+
return SYSTEM_PROMPT
|
|
115
|
+
|
|
116
|
+
if name == "TIKZ_CHECKER_PROMPT":
|
|
117
|
+
from .tikz_checker import SYSTEM_PROMPT
|
|
118
|
+
return SYSTEM_PROMPT
|
|
119
|
+
|
|
120
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|