vbagent 0.1.1__py3-none-any.whl → 0.2.1__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 CHANGED
@@ -1,3 +1,221 @@
1
- """VBAgent - Physics question processing pipeline using OpenAI."""
1
+ """VBAgent - Physics question processing pipeline using OpenAI.
2
2
 
3
- __version__ = "0.1.0"
3
+ This package provides agents for processing physics questions:
4
+ - Classification: Analyze question images for metadata
5
+ - Scanning: Extract LaTeX from question images
6
+ - Variants: Generate problem variants (numerical, context, conceptual)
7
+ - Ideas: Extract physics concepts
8
+ - TikZ: Generate and check diagrams
9
+ - Review: QA checking
10
+ - Alternates: Generate alternate solutions
11
+
12
+ Usage as a library:
13
+ from vbagent import classify, scan, generate_variant
14
+ from vbagent.models import ClassificationResult, ScanResult
15
+ from vbagent.config import get_config, set_config
16
+
17
+ # Classify an image
18
+ result = classify("question.png")
19
+
20
+ # Scan with classification
21
+ latex_result = scan("question.png", result)
22
+
23
+ # Generate a variant
24
+ variant = generate_variant(latex_result.latex, "numerical")
25
+
26
+ # Generate TikZ diagram
27
+ tikz = generate_tikz("A free body diagram showing forces on a block")
28
+
29
+ # Configure models
30
+ config = get_config()
31
+ config.scanner.model = "gpt-5.2"
32
+ set_config(config)
33
+
34
+ Submodule access:
35
+ from vbagent.agents import classify, scan, generate_tikz
36
+ from vbagent.models import ClassificationResult, ScanResult, ReviewResult
37
+ from vbagent.prompts import get_scanner_prompt, get_variant_prompt
38
+ from vbagent.references import ReferenceStore, TikZStore
39
+ from vbagent.config import VBAgentConfig
40
+ """
41
+
42
+ from typing import TYPE_CHECKING
43
+
44
+ __version__ = "0.2.0"
45
+
46
+ # Lazy imports for library consumers
47
+ if TYPE_CHECKING:
48
+ from vbagent.agents import (
49
+ # Classification
50
+ classify,
51
+ # Scanning
52
+ scan,
53
+ scan_with_type,
54
+ # Ideas
55
+ extract_ideas,
56
+ generate_idea_latex,
57
+ # Alternates
58
+ generate_alternate,
59
+ # Variants
60
+ generate_variant,
61
+ generate_numerical_variant,
62
+ generate_context_variant,
63
+ generate_conceptual_variant,
64
+ generate_calculus_variant,
65
+ get_variant_prompt,
66
+ VALID_VARIANT_TYPES,
67
+ # TikZ generation
68
+ generate_tikz,
69
+ validate_tikz_output,
70
+ # QA Checkers
71
+ check_solution,
72
+ check_grammar,
73
+ check_clarity,
74
+ check_tikz,
75
+ check_tikz_with_patch,
76
+ # Review
77
+ review_problem,
78
+ review_problem_sync,
79
+ # Problem selection
80
+ discover_problems,
81
+ select_random,
82
+ load_problem_context,
83
+ ProblemContext,
84
+ # Base utilities
85
+ create_agent,
86
+ run_agent,
87
+ run_agent_sync,
88
+ encode_image,
89
+ create_image_message,
90
+ )
91
+ from vbagent.models import (
92
+ ClassificationResult,
93
+ ScanResult,
94
+ IdeaResult,
95
+ PipelineResult,
96
+ ReviewResult,
97
+ ReviewStats,
98
+ Suggestion,
99
+ ReviewIssueType,
100
+ )
101
+ from vbagent.config import (
102
+ VBAgentConfig,
103
+ AgentModelConfig,
104
+ get_config,
105
+ set_config,
106
+ save_config,
107
+ reset_config,
108
+ get_model,
109
+ get_model_settings,
110
+ AGENT_TYPES,
111
+ MODELS,
112
+ )
113
+
114
+ __all__ = [
115
+ # Version
116
+ "__version__",
117
+ # Classification
118
+ "classify",
119
+ # Scanning
120
+ "scan",
121
+ "scan_with_type",
122
+ # Ideas
123
+ "extract_ideas",
124
+ "generate_idea_latex",
125
+ # Alternates
126
+ "generate_alternate",
127
+ # Variants
128
+ "generate_variant",
129
+ "generate_numerical_variant",
130
+ "generate_context_variant",
131
+ "generate_conceptual_variant",
132
+ "generate_calculus_variant",
133
+ "get_variant_prompt",
134
+ "VALID_VARIANT_TYPES",
135
+ # TikZ generation
136
+ "generate_tikz",
137
+ "validate_tikz_output",
138
+ # QA Checkers
139
+ "check_solution",
140
+ "check_grammar",
141
+ "check_clarity",
142
+ "check_tikz",
143
+ "check_tikz_with_patch",
144
+ # Review
145
+ "review_problem",
146
+ "review_problem_sync",
147
+ # Problem selection
148
+ "discover_problems",
149
+ "select_random",
150
+ "load_problem_context",
151
+ "ProblemContext",
152
+ # Agent utilities
153
+ "create_agent",
154
+ "run_agent",
155
+ "run_agent_sync",
156
+ "encode_image",
157
+ "create_image_message",
158
+ # Models
159
+ "ClassificationResult",
160
+ "ScanResult",
161
+ "IdeaResult",
162
+ "PipelineResult",
163
+ "ReviewResult",
164
+ "ReviewStats",
165
+ "Suggestion",
166
+ "ReviewIssueType",
167
+ # Configuration
168
+ "VBAgentConfig",
169
+ "AgentModelConfig",
170
+ "get_config",
171
+ "set_config",
172
+ "save_config",
173
+ "reset_config",
174
+ "get_model",
175
+ "get_model_settings",
176
+ "AGENT_TYPES",
177
+ "MODELS",
178
+ ]
179
+
180
+
181
+ def __getattr__(name: str):
182
+ """Lazy import to avoid loading heavy dependencies until needed."""
183
+ # Agent functions
184
+ if name in (
185
+ "classify",
186
+ "scan", "scan_with_type",
187
+ "extract_ideas", "generate_idea_latex",
188
+ "generate_alternate",
189
+ "generate_variant", "generate_numerical_variant", "generate_context_variant",
190
+ "generate_conceptual_variant", "generate_calculus_variant",
191
+ "get_variant_prompt", "VALID_VARIANT_TYPES",
192
+ "generate_tikz", "validate_tikz_output",
193
+ "check_solution", "check_grammar", "check_clarity", "check_tikz", "check_tikz_with_patch",
194
+ "review_problem", "review_problem_sync",
195
+ "discover_problems", "select_random", "load_problem_context", "ProblemContext",
196
+ "create_agent", "run_agent", "run_agent_sync",
197
+ "encode_image", "create_image_message",
198
+ ):
199
+ from vbagent import agents
200
+ return getattr(agents, name)
201
+
202
+ # Models
203
+ if name in (
204
+ "ClassificationResult", "ScanResult", "IdeaResult",
205
+ "PipelineResult", "ReviewResult", "ReviewStats",
206
+ "Suggestion", "ReviewIssueType",
207
+ ):
208
+ from vbagent import models
209
+ return getattr(models, name)
210
+
211
+ # Configuration
212
+ if name in (
213
+ "VBAgentConfig", "AgentModelConfig",
214
+ "get_config", "set_config", "save_config", "reset_config",
215
+ "get_model", "get_model_settings",
216
+ "AGENT_TYPES", "MODELS",
217
+ ):
218
+ from vbagent import config
219
+ return getattr(config, name)
220
+
221
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -2,6 +2,14 @@
2
2
 
3
3
  Uses lazy imports to avoid loading heavy dependencies (openai, agents, mcp, pydantic)
4
4
  until they are actually needed. This significantly improves CLI startup time.
5
+
6
+ Available agents and functions:
7
+ - classify: Classify physics question images
8
+ - scan, scan_with_type: Extract LaTeX from images
9
+ - extract_ideas, generate_idea_latex: Extract physics concepts
10
+ - generate_alternate: Generate alternate solutions
11
+ - generate_variant: Generate problem variants
12
+ - check_solution, check_grammar, check_clarity, check_tikz: QA checkers
5
13
  """
6
14
 
7
15
  from typing import TYPE_CHECKING
@@ -16,8 +24,18 @@ if TYPE_CHECKING:
16
24
  run_agent_sync,
17
25
  )
18
26
  from .classifier import classifier_agent, classify
27
+ from .scanner import scan, scan_with_type, create_scanner_agent
19
28
  from .idea import idea_agent_json, idea_agent_latex, extract_ideas, generate_idea_latex
20
29
  from .alternate import alternate_agent, generate_alternate, extract_answer
30
+ from .variant import (
31
+ generate_variant,
32
+ generate_numerical_variant,
33
+ generate_context_variant,
34
+ generate_conceptual_variant,
35
+ generate_calculus_variant,
36
+ get_variant_prompt,
37
+ VALID_VARIANT_TYPES,
38
+ )
21
39
  from .selector import (
22
40
  ProblemContext,
23
41
  discover_problems,
@@ -42,26 +60,58 @@ if TYPE_CHECKING:
42
60
  from .tikz_checker import (
43
61
  tikz_checker_agent,
44
62
  check_tikz,
63
+ check_tikz_with_patch,
45
64
  has_tikz_passed,
46
65
  has_tikz_environment,
66
+ PatchResult,
67
+ )
68
+ from .tikz import (
69
+ generate_tikz,
70
+ create_tikz_agent,
71
+ validate_tikz_output,
72
+ search_tikz_reference,
73
+ )
74
+ from .reviewer import (
75
+ review_problem,
76
+ review_problem_sync,
77
+ ReviewAgentError,
78
+ ReviewError,
79
+ ReviewErrorType,
47
80
  )
48
81
 
49
82
 
50
83
  __all__ = [
84
+ # Base utilities
51
85
  "encode_image",
52
86
  "create_image_message",
53
87
  "create_agent",
54
88
  "run_agent",
55
89
  "run_agent_sync",
90
+ # Classifier
56
91
  "classifier_agent",
57
92
  "classify",
93
+ # Scanner
94
+ "scan",
95
+ "scan_with_type",
96
+ "create_scanner_agent",
97
+ # Idea extraction
58
98
  "idea_agent_json",
59
99
  "idea_agent_latex",
60
100
  "extract_ideas",
61
101
  "generate_idea_latex",
102
+ # Alternate solutions
62
103
  "alternate_agent",
63
104
  "generate_alternate",
64
105
  "extract_answer",
106
+ # Variants
107
+ "generate_variant",
108
+ "generate_numerical_variant",
109
+ "generate_context_variant",
110
+ "generate_conceptual_variant",
111
+ "generate_calculus_variant",
112
+ "get_variant_prompt",
113
+ "VALID_VARIANT_TYPES",
114
+ # Problem selection
65
115
  "ProblemContext",
66
116
  "discover_problems",
67
117
  "select_random",
@@ -81,8 +131,21 @@ __all__ = [
81
131
  # TikZ checker
82
132
  "tikz_checker_agent",
83
133
  "check_tikz",
134
+ "check_tikz_with_patch",
84
135
  "has_tikz_passed",
85
136
  "has_tikz_environment",
137
+ "PatchResult",
138
+ # TikZ generator
139
+ "generate_tikz",
140
+ "create_tikz_agent",
141
+ "validate_tikz_output",
142
+ "search_tikz_reference",
143
+ # Reviewer
144
+ "review_problem",
145
+ "review_problem_sync",
146
+ "ReviewAgentError",
147
+ "ReviewError",
148
+ "ReviewErrorType",
86
149
  ]
87
150
 
88
151
 
@@ -96,6 +159,10 @@ def __getattr__(name: str):
96
159
  from . import classifier
97
160
  return getattr(classifier, name)
98
161
 
162
+ if name in ("scan", "scan_with_type", "create_scanner_agent"):
163
+ from . import scanner
164
+ return getattr(scanner, name)
165
+
99
166
  if name in ("idea_agent_json", "idea_agent_latex", "extract_ideas", "generate_idea_latex"):
100
167
  from . import idea
101
168
  return getattr(idea, name)
@@ -104,6 +171,14 @@ def __getattr__(name: str):
104
171
  from . import alternate
105
172
  return getattr(alternate, name)
106
173
 
174
+ if name in (
175
+ "generate_variant", "generate_numerical_variant", "generate_context_variant",
176
+ "generate_conceptual_variant", "generate_calculus_variant",
177
+ "get_variant_prompt", "VALID_VARIANT_TYPES",
178
+ ):
179
+ from . import variant
180
+ return getattr(variant, name)
181
+
107
182
  if name in ("ProblemContext", "discover_problems", "select_random", "load_problem_context"):
108
183
  from . import selector
109
184
  return getattr(selector, name)
@@ -120,8 +195,16 @@ def __getattr__(name: str):
120
195
  from . import clarity_checker
121
196
  return getattr(clarity_checker, name)
122
197
 
123
- if name in ("tikz_checker_agent", "check_tikz", "has_tikz_passed", "has_tikz_environment"):
198
+ if name in ("tikz_checker_agent", "check_tikz", "check_tikz_with_patch", "has_tikz_passed", "has_tikz_environment", "PatchResult"):
124
199
  from . import tikz_checker
125
200
  return getattr(tikz_checker, name)
126
201
 
202
+ if name in ("generate_tikz", "create_tikz_agent", "validate_tikz_output", "search_tikz_reference"):
203
+ from . import tikz
204
+ return getattr(tikz, name)
205
+
206
+ if name in ("review_problem", "review_problem_sync", "ReviewAgentError", "ReviewError", "ReviewErrorType"):
207
+ from . import reviewer
208
+ return getattr(reviewer, name)
209
+
127
210
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
vbagent/agents/base.py CHANGED
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any, Optional
8
8
  if TYPE_CHECKING:
9
9
  from agents import Agent, ModelSettings
10
10
 
11
- from vbagent.config import get_model, get_model_settings
11
+ from vbagent.config import get_model, get_model_settings, apply_provider_config
12
12
 
13
13
 
14
14
  def _get_agent_class():
@@ -115,6 +115,9 @@ def create_agent(
115
115
  """
116
116
  Agent = _get_agent_class()
117
117
 
118
+ # Apply provider config (base_url, api_key) before creating agent
119
+ apply_provider_config()
120
+
118
121
  # Get model and settings from config if not explicitly provided
119
122
  if model is None:
120
123
  model = get_model(agent_type or "default")
@@ -1,32 +1,56 @@
1
- """Classifier agent for physics question image classification.
1
+ """Classifier agent for question image classification.
2
2
 
3
- Uses openai-agents SDK to analyze physics question images and extract
3
+ Uses openai-agents SDK to analyze question images and extract
4
4
  structured metadata including question type, difficulty, topic, etc.
5
5
  """
6
6
 
7
+ from typing import TYPE_CHECKING, Optional
8
+
9
+ if TYPE_CHECKING:
10
+ from agents import Agent
11
+
7
12
  from vbagent.agents.base import (
8
13
  create_agent,
9
14
  create_image_message,
10
15
  run_agent_sync,
11
16
  )
17
+ from vbagent.config import get_config
12
18
  from vbagent.models.classification import ClassificationResult
13
- from vbagent.prompts.classifier import SYSTEM_PROMPT, USER_TEMPLATE
19
+ from vbagent.prompts.classifier import get_classifier_prompt, get_user_template
14
20
 
15
21
 
16
- # Create the classifier agent with structured output
17
- classifier_agent = create_agent(
18
- name="Classifier",
19
- instructions=SYSTEM_PROMPT,
20
- output_type=ClassificationResult,
21
- agent_type="classifier",
22
- )
22
+ def create_classifier_agent(subject: Optional[str] = None) -> "Agent":
23
+ """Create a classifier agent for a subject.
24
+
25
+ Args:
26
+ subject: Subject override (uses config if not provided)
27
+
28
+ Returns:
29
+ Configured Agent instance for classification
30
+ """
31
+ if subject is None:
32
+ subject = get_config().subject
33
+
34
+ prompt = get_classifier_prompt(subject)
35
+
36
+ return create_agent(
37
+ name=f"Classifier-{subject}",
38
+ instructions=prompt,
39
+ output_type=ClassificationResult,
40
+ agent_type="classifier",
41
+ )
23
42
 
24
43
 
25
- def classify(image_path: str) -> ClassificationResult:
26
- """Analyze a physics question image and return structured metadata.
44
+ # Legacy: Create default classifier agent for backward compatibility
45
+ classifier_agent = create_classifier_agent("physics")
46
+
47
+
48
+ def classify(image_path: str, subject: Optional[str] = None) -> ClassificationResult:
49
+ """Analyze a question image and return structured metadata.
27
50
 
28
51
  Args:
29
52
  image_path: Path to the image file to classify
53
+ subject: Subject override (uses config if not provided)
30
54
 
31
55
  Returns:
32
56
  ClassificationResult with extracted metadata
@@ -34,6 +58,11 @@ def classify(image_path: str) -> ClassificationResult:
34
58
  Raises:
35
59
  FileNotFoundError: If the image file doesn't exist
36
60
  """
37
- message = create_image_message(image_path, USER_TEMPLATE)
38
- result = run_agent_sync(classifier_agent, message)
61
+ if subject is None:
62
+ subject = get_config().subject
63
+
64
+ agent = create_classifier_agent(subject)
65
+ user_template = get_user_template(subject)
66
+ message = create_image_message(image_path, user_template)
67
+ result = run_agent_sync(agent, message)
39
68
  return result
@@ -0,0 +1,57 @@
1
+ """Agent for fixing LaTeX compilation errors.
2
+
3
+ Takes a LaTeX snippet and pdflatex error output, returns corrected LaTeX.
4
+ """
5
+
6
+ from vbagent.agents.base import create_agent, run_agent_sync
7
+
8
+
9
+ SYSTEM_PROMPT = r"""You are a LaTeX error fixer. You receive LaTeX code that failed to compile and the pdflatex error output.
10
+
11
+ Your job:
12
+ 1. Read the error messages carefully
13
+ 2. Fix ONLY the errors — do not change the content or structure
14
+ 3. Common fixes: missing braces, undefined commands, wrong environment names, missing $ delimiters
15
+ 4. Output ONLY the corrected LaTeX code — no explanations, no markdown, no code blocks
16
+
17
+ CRITICAL: Output the EXACT same content with ONLY the compilation errors fixed. Do not add \documentclass, preamble, or any wrapping."""
18
+
19
+ USER_TEMPLATE = """Fix the compilation errors in this LaTeX code.
20
+
21
+ **Errors from pdflatex:**
22
+ ```
23
+ {errors}
24
+ ```
25
+
26
+ **LaTeX code to fix:**
27
+ ```latex
28
+ {latex}
29
+ ```
30
+
31
+ Output ONLY the corrected LaTeX code:"""
32
+
33
+
34
+ def fix_latex(error_summary: str, latex: str) -> str:
35
+ """Send LaTeX + errors to agent and get fixed version.
36
+
37
+ Args:
38
+ error_summary: Parsed pdflatex error output
39
+ latex: The LaTeX code that failed to compile
40
+
41
+ Returns:
42
+ Corrected LaTeX code
43
+ """
44
+ agent = create_agent(
45
+ name="LaTeX-Fixer",
46
+ instructions=SYSTEM_PROMPT,
47
+ agent_type="converter", # Use converter model (lighter/cheaper)
48
+ )
49
+
50
+ prompt = USER_TEMPLATE.format(errors=error_summary, latex=latex)
51
+ result = run_agent_sync(agent, prompt)
52
+
53
+ # Clean markdown artifacts
54
+ import re
55
+ result = re.sub(r'^```(?:latex|tex)?\s*\n?', '', result, flags=re.IGNORECASE)
56
+ result = re.sub(r'\n?```\s*$', '', result)
57
+ return result.strip()
@@ -48,9 +48,9 @@ from vbagent.prompts.converter import (
48
48
 
49
49
 
50
50
  # Valid format types
51
- FormatType = Literal["mcq_sc", "mcq_mc", "subjective", "integer"]
51
+ FormatType = Literal["mcq_sc", "mcq_mc", "subjective", "integer", "match", "passage"]
52
52
 
53
- VALID_FORMATS = {"mcq_sc", "mcq_mc", "subjective", "integer"}
53
+ VALID_FORMATS = {"mcq_sc", "mcq_mc", "subjective", "integer", "match", "passage"}
54
54
 
55
55
 
56
56
  # Create the format converter agent
@@ -208,13 +208,13 @@ def _convert_issue_type(issue_type_str: str) -> ReviewIssueType:
208
208
 
209
209
 
210
210
  def _create_suggestion_with_diff(
211
- raw: RawSuggestion,
211
+ raw, # RawSuggestion instance
212
212
  context: ProblemContext,
213
213
  ) -> Suggestion:
214
214
  """Convert a raw suggestion to a Suggestion with generated diff.
215
215
 
216
216
  Args:
217
- raw: Raw suggestion from the AI
217
+ raw: Raw suggestion from the AI (RawSuggestion instance)
218
218
  context: Problem context for file path resolution
219
219
 
220
220
  Returns: