algomath-extract 1.0.0

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 (90) hide show
  1. package/README.md +260 -0
  2. package/bin/algo-extract.js +143 -0
  3. package/bin/algo-generate.js +102 -0
  4. package/bin/algo-help.js +136 -0
  5. package/bin/algo-list.js +56 -0
  6. package/bin/algo-run.js +141 -0
  7. package/bin/algo-status.js +88 -0
  8. package/bin/algo-verify.js +189 -0
  9. package/bin/install.js +349 -0
  10. package/package.json +57 -0
  11. package/requirements.txt +20 -0
  12. package/src/__pycache__/intent.cpython-313.pyc +0 -0
  13. package/src/cli/__pycache__/commands.cpython-313.pyc +0 -0
  14. package/src/cli/cli_entry.py +106 -0
  15. package/src/cli/commands.py +339 -0
  16. package/src/execution/__init__.py +74 -0
  17. package/src/execution/__pycache__/__init__.cpython-313.pyc +0 -0
  18. package/src/execution/__pycache__/display.cpython-313.pyc +0 -0
  19. package/src/execution/__pycache__/errors.cpython-313.pyc +0 -0
  20. package/src/execution/__pycache__/executor.cpython-313.pyc +0 -0
  21. package/src/execution/__pycache__/sandbox.cpython-313.pyc +0 -0
  22. package/src/execution/display.py +261 -0
  23. package/src/execution/errors.py +158 -0
  24. package/src/execution/executor.py +253 -0
  25. package/src/execution/sandbox.py +333 -0
  26. package/src/extraction/__init__.py +102 -0
  27. package/src/extraction/__pycache__/__init__.cpython-313.pyc +0 -0
  28. package/src/extraction/__pycache__/boundaries.cpython-313.pyc +0 -0
  29. package/src/extraction/__pycache__/errors.cpython-313.pyc +0 -0
  30. package/src/extraction/__pycache__/llm_extraction.cpython-313.pyc +0 -0
  31. package/src/extraction/__pycache__/notation.cpython-313.pyc +0 -0
  32. package/src/extraction/__pycache__/parser.cpython-313.pyc +0 -0
  33. package/src/extraction/__pycache__/pdf_processor.cpython-313.pyc +0 -0
  34. package/src/extraction/__pycache__/prompts.cpython-313.pyc +0 -0
  35. package/src/extraction/__pycache__/review.cpython-313.pyc +0 -0
  36. package/src/extraction/__pycache__/schema.cpython-313.pyc +0 -0
  37. package/src/extraction/__pycache__/validation.cpython-313.pyc +0 -0
  38. package/src/extraction/boundaries.py +281 -0
  39. package/src/extraction/errors.py +156 -0
  40. package/src/extraction/llm_extraction.py +225 -0
  41. package/src/extraction/notation.py +240 -0
  42. package/src/extraction/parser.py +402 -0
  43. package/src/extraction/pdf_processor.py +281 -0
  44. package/src/extraction/prompts.py +90 -0
  45. package/src/extraction/review.py +298 -0
  46. package/src/extraction/schema.py +173 -0
  47. package/src/extraction/validation.py +202 -0
  48. package/src/generation/__init__.py +79 -0
  49. package/src/generation/__pycache__/__init__.cpython-313.pyc +0 -0
  50. package/src/generation/__pycache__/code_generator.cpython-313.pyc +0 -0
  51. package/src/generation/__pycache__/errors.cpython-313.pyc +0 -0
  52. package/src/generation/__pycache__/hybrid.cpython-313.pyc +0 -0
  53. package/src/generation/__pycache__/llm_generator.cpython-313.pyc +0 -0
  54. package/src/generation/__pycache__/persistence.cpython-313.pyc +0 -0
  55. package/src/generation/__pycache__/prompts.cpython-313.pyc +0 -0
  56. package/src/generation/__pycache__/review.cpython-313.pyc +0 -0
  57. package/src/generation/__pycache__/templates.cpython-313.pyc +0 -0
  58. package/src/generation/__pycache__/types.cpython-313.pyc +0 -0
  59. package/src/generation/__pycache__/validation.cpython-313.pyc +0 -0
  60. package/src/generation/code_generator.py +375 -0
  61. package/src/generation/errors.py +84 -0
  62. package/src/generation/hybrid.py +210 -0
  63. package/src/generation/llm_generator.py +223 -0
  64. package/src/generation/persistence.py +221 -0
  65. package/src/generation/prompts.py +202 -0
  66. package/src/generation/review.py +254 -0
  67. package/src/generation/templates.py +208 -0
  68. package/src/generation/types.py +196 -0
  69. package/src/generation/validation.py +278 -0
  70. package/src/intent.py +323 -0
  71. package/src/verification/__init__.py +63 -0
  72. package/src/verification/__pycache__/__init__.cpython-313.pyc +0 -0
  73. package/src/verification/__pycache__/checker.cpython-313.pyc +0 -0
  74. package/src/verification/__pycache__/comparison.cpython-313.pyc +0 -0
  75. package/src/verification/__pycache__/explainer.cpython-313.pyc +0 -0
  76. package/src/verification/__pycache__/static_analysis.cpython-313.pyc +0 -0
  77. package/src/verification/checker.py +220 -0
  78. package/src/verification/comparison.py +492 -0
  79. package/src/verification/explainer.py +414 -0
  80. package/src/verification/static_analysis.py +540 -0
  81. package/src/workflows/__init__.py +21 -0
  82. package/src/workflows/__pycache__/__init__.cpython-313.pyc +0 -0
  83. package/src/workflows/__pycache__/extract.cpython-313.pyc +0 -0
  84. package/src/workflows/__pycache__/generate.cpython-313.pyc +0 -0
  85. package/src/workflows/__pycache__/run.cpython-313.pyc +0 -0
  86. package/src/workflows/__pycache__/verify.cpython-313.pyc +0 -0
  87. package/src/workflows/extract.py +181 -0
  88. package/src/workflows/generate.py +155 -0
  89. package/src/workflows/run.py +187 -0
  90. package/src/workflows/verify.py +334 -0
@@ -0,0 +1,181 @@
1
+ """Extraction workflow for AlgoMath."""
2
+
3
+ from typing import Dict, List, Optional, Any
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ # Add project root to Python path
8
+ project_root = Path(__file__).parent.parent.parent
9
+ if str(project_root) not in sys.path:
10
+ sys.path.insert(0, str(project_root))
11
+
12
+ # Import extraction components
13
+ from src.extraction.llm_extraction import HybridExtractor
14
+ from src.extraction.review import ReviewInterface
15
+ from src.extraction.schema import algorithm_to_json
16
+
17
+
18
+ def show_progress(phase: str, current: int, total: int) -> str:
19
+ """
20
+ Generate a progress bar string.
21
+
22
+ Args:
23
+ phase: Name of the current phase
24
+ current: Current step number
25
+ total: Total number of steps
26
+
27
+ Returns:
28
+ Formatted progress bar string
29
+
30
+ Example:
31
+ >>> show_progress("Extract", 8, 10)
32
+ "Extract: ████████░░ 80%"
33
+ """
34
+ if total <= 0:
35
+ return f"{phase}: ░░░░░░░░░░ 0%"
36
+
37
+ filled = int(10 * current / total)
38
+ filled = max(0, min(filled, 10)) # Clamp to 0-10 range
39
+ bar = '█' * filled + '░' * (10 - filled)
40
+ pct = int(100 * current / total)
41
+ return f"{phase}: {bar} {pct}%"
42
+
43
+
44
+ def run_extraction(
45
+ context: Any,
46
+ text: Optional[str] = None,
47
+ name: Optional[str] = None,
48
+ skip_review: bool = False
49
+ ) -> Dict[str, Any]:
50
+ """
51
+ Run the extraction workflow with hybrid extraction.
52
+
53
+ Per EXT-01, EXT-02, EXT-03, EXT-04, EXT-05, EXT-06.
54
+ """
55
+ # Import here to avoid circular imports
56
+ from algomath.context import ContextManager
57
+ from algomath.state import WorkflowState
58
+
59
+ # Progress: Parsing
60
+ progress = show_progress("Extract", 1, 5)
61
+
62
+ # Check if we have algorithm text
63
+ if text is None:
64
+ return {
65
+ 'status': 'needs_input',
66
+ 'progress': progress,
67
+ 'message': 'Please provide algorithm text to extract',
68
+ 'next_steps': [
69
+ 'Provide algorithm text',
70
+ 'Cancel extraction'
71
+ ]
72
+ }
73
+
74
+ # Save text to context
75
+ context.save_text(text)
76
+
77
+ # Progress: Extracting
78
+ progress = show_progress("Extract", 2, 5)
79
+
80
+ # Run hybrid extraction
81
+ extractor = HybridExtractor()
82
+ result = extractor.extract(text, prefer_llm=True)
83
+
84
+ if not result.success:
85
+ return {
86
+ 'status': 'extraction_failed',
87
+ 'progress': progress,
88
+ 'errors': result.errors,
89
+ 'message': 'Failed to extract algorithm from text',
90
+ 'next_steps': [
91
+ 'Try again with clearer text',
92
+ 'Cancel extraction'
93
+ ]
94
+ }
95
+
96
+ # Progress: Structuring
97
+ progress = show_progress("Extract", 3, 5)
98
+
99
+ # Convert steps to JSON-serializable format
100
+ algorithm = result.algorithm
101
+ steps_data = []
102
+ for step in algorithm.steps:
103
+ steps_data.append({
104
+ 'id': step.id,
105
+ 'type': step.type.value,
106
+ 'description': step.description,
107
+ 'inputs': step.inputs,
108
+ 'outputs': step.outputs,
109
+ 'line_refs': step.line_refs,
110
+ 'condition': step.condition,
111
+ 'body': step.body,
112
+ 'else_body': step.else_body,
113
+ 'iter_var': step.iter_var,
114
+ 'iter_range': step.iter_range,
115
+ 'expression': step.expression,
116
+ 'call_target': step.call_target,
117
+ 'arguments': step.arguments,
118
+ 'annotation': step.annotation
119
+ })
120
+
121
+ # Prepare review interface
122
+ review = ReviewInterface(algorithm)
123
+
124
+ # Progress: Validating
125
+ progress = show_progress("Extract", 4, 5)
126
+
127
+ if skip_review:
128
+ # Auto-approve
129
+ context.save_steps(steps_data)
130
+ else:
131
+ # Return for review
132
+ context.save_steps(steps_data) # Save tentative steps
133
+
134
+ return {
135
+ 'status': 'needs_review',
136
+ 'progress': progress,
137
+ 'algorithm': {
138
+ 'name': algorithm.name,
139
+ 'inputs': algorithm.inputs,
140
+ 'outputs': algorithm.outputs,
141
+ 'steps': steps_data
142
+ },
143
+ 'review_interface': review,
144
+ 'method': result.method,
145
+ 'message': 'Algorithm extracted. Please review before proceeding.',
146
+ 'next_steps': [
147
+ 'Review and approve extracted steps',
148
+ 'Edit steps if needed',
149
+ 'Regenerate with clearer text'
150
+ ]
151
+ }
152
+
153
+ # Progress: Complete
154
+ progress = show_progress("Extract", 5, 5)
155
+
156
+ return {
157
+ 'status': 'extraction_complete',
158
+ 'progress': progress,
159
+ 'steps_extracted': len(steps_data),
160
+ 'algorithm_name': algorithm.name or (name if name else 'unnamed'),
161
+ 'method': result.method,
162
+ 'next_steps': [
163
+ 'Generate code with /algo-generate',
164
+ 'Review extracted steps: /algo-status',
165
+ 'Extract a different algorithm: /algo-extract'
166
+ ]
167
+ }
168
+
169
+
170
+ def get_progress_bar(step: int, total: int) -> str:
171
+ """
172
+ Generate progress bar string: Extract: ████████░░ 80%
173
+
174
+ Args:
175
+ step: Current step
176
+ total: Total steps
177
+
178
+ Returns:
179
+ Progress bar string
180
+ """
181
+ return show_progress("Extract", step, total)
@@ -0,0 +1,155 @@
1
+ """
2
+ Generation workflow for AlgoMath.
3
+
4
+ This module implements the code generation phase, transforming
5
+ extracted algorithm steps into executable Python code.
6
+ """
7
+
8
+ from typing import Dict, List, Optional, Any
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ # Add project root to Python path
13
+ project_root = Path(__file__).parent.parent.parent
14
+ if str(project_root) not in sys.path:
15
+ sys.path.insert(0, str(project_root))
16
+
17
+
18
+ def show_progress(phase: str, current: int, total: int) -> str:
19
+ """
20
+ Generate a progress bar string.
21
+
22
+ Args:
23
+ phase: Name of the current phase
24
+ current: Current step number
25
+ total: Total number of steps
26
+
27
+ Returns:
28
+ Formatted progress bar string
29
+ """
30
+ if total <= 0:
31
+ return f"{phase}: ░░░░░░░░░░ 0%"
32
+
33
+ filled = int(10 * current / total)
34
+ filled = max(0, min(filled, 10)) # Clamp to 0-10 range
35
+ bar = '█' * filled + '░' * (10 - filled)
36
+ pct = int(100 * current / total)
37
+ return f"{phase}: {bar} {pct}%"
38
+
39
+
40
+ def run_generation(context: "ContextManager") -> Dict[str, Any]:
41
+ """
42
+ Generate Python code from extracted steps using TemplateCodeGenerator.
43
+
44
+ Args:
45
+ context: ContextManager instance
46
+
47
+ Returns:
48
+ Dict with status and code generation result
49
+
50
+ Example:
51
+ >>> ctx = ContextManager()
52
+ >>> ctx.start_session()
53
+ >>> ctx.save_steps([{"step": 1, "action": "init"}])
54
+ >>> result = run_generation(ctx)
55
+ >>> print(result['status'])
56
+ 'code_generated'
57
+ """
58
+ # Import here to avoid circular imports
59
+ from algomath.context import ContextManager
60
+ from src.extraction.schema import Algorithm
61
+ from src.generation import HybridCodeGenerator
62
+
63
+ # Progress indicator
64
+ progress = show_progress("Generate", 1, 10)
65
+
66
+ # Load algorithm
67
+ try:
68
+ algorithm_data = context.store.load_session()
69
+ if not algorithm_data.get('algorithm'):
70
+ return {
71
+ 'status': 'needs_extraction',
72
+ 'progress': progress,
73
+ 'message': 'No algorithm found. Extract algorithm first with /algo-extract',
74
+ 'next_steps': [
75
+ 'Extract algorithm with /algo-extract',
76
+ 'Check status with /algo-status'
77
+ ]
78
+ }
79
+ except Exception:
80
+ return {
81
+ 'status': 'error',
82
+ 'progress': progress,
83
+ 'message': 'Could not load algorithm data',
84
+ 'next_steps': [
85
+ 'Start over with /algo-extract',
86
+ 'Show help with /algo-help'
87
+ ]
88
+ }
89
+
90
+ # Convert to Algorithm object
91
+ try:
92
+ algorithm = Algorithm.from_dict(algorithm_data['algorithm'])
93
+ except Exception as e:
94
+ return {
95
+ 'status': 'error',
96
+ 'progress': progress,
97
+ 'message': f'Failed to parse algorithm: {e}',
98
+ 'next_steps': ['Extract algorithm again with /algo-extract']
99
+ }
100
+
101
+ # Update progress
102
+ progress = show_progress("Generate", 5, 10)
103
+
104
+ # Generate code using hybrid generator (Template → LLM → Stub)
105
+ try:
106
+ generator = HybridCodeGenerator()
107
+ result = generator.generate_for_workflow(algorithm)
108
+ generated = result['generated']
109
+
110
+ # Validate syntax
111
+ if not generated.validation_result.is_valid:
112
+ return {
113
+ 'status': 'generation_error',
114
+ 'progress': show_progress("Generate", 7, 10),
115
+ 'error': generated.validation_result.errors,
116
+ 'message': 'Generated code has syntax errors',
117
+ 'next_steps': ['Review extraction with /algo-extract', 'Try again with /algo-generate']
118
+ }
119
+
120
+ # Save to context
121
+ context.save_code(generated.source)
122
+
123
+ # Determine message based on strategy
124
+ strategy = result['strategy']
125
+ messages = {
126
+ 'template': 'Generated code using templates',
127
+ 'llm': 'Generated code using LLM for complex expressions',
128
+ 'stub': 'Generated stub code (full generation failed)'
129
+ }
130
+
131
+ # Final progress
132
+ progress = show_progress("Generate", 10, 10)
133
+
134
+ return {
135
+ 'status': 'code_generated',
136
+ 'progress': progress,
137
+ 'lines_of_code': len(generated.source.split('\n')),
138
+ 'algorithm_name': generated.algorithm_name,
139
+ 'strategy': strategy,
140
+ 'message': messages.get(strategy, 'Code generated'),
141
+ 'next_steps': [
142
+ 'Review code with /algo-review',
143
+ 'Execute with /algo-run',
144
+ 'Regenerate with /algo-generate',
145
+ 'Check status with /algo-status'
146
+ ]
147
+ }
148
+ except Exception as e:
149
+ return {
150
+ 'status': 'generation_error',
151
+ 'progress': show_progress("Generate", 5, 10),
152
+ 'error': str(e),
153
+ 'message': f'Code generation failed: {e}',
154
+ 'next_steps': ['Try again with /algo-generate', 'Review extraction with /algo-extract']
155
+ }
@@ -0,0 +1,187 @@
1
+ """
2
+ Execution workflow for AlgoMath.
3
+
4
+ This module implements the code execution phase, running
5
+ generated code in a controlled environment.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Dict, List, Optional, Any
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ # Add project root to Python path
14
+ project_root = Path(__file__).parent.parent.parent
15
+ if str(project_root) not in sys.path:
16
+ sys.path.insert(0, str(project_root))
17
+
18
+ from src.execution import execute_code, ExecutionConfig, ExecutionStatus
19
+
20
+
21
+ def show_progress(phase: str, current: int, total: int) -> str:
22
+ """
23
+ Generate a progress bar string.
24
+
25
+ Args:
26
+ phase: Name of the current phase
27
+ current: Current step number
28
+ total: Total number of steps
29
+
30
+ Returns:
31
+ Formatted progress bar string
32
+ """
33
+ if total <= 0:
34
+ return f"{phase}: ░░░░░░░░░░ 0%"
35
+
36
+ filled = int(10 * current / total)
37
+ filled = max(0, min(filled, 10)) # Clamp to 0-10 range
38
+ bar = '█' * filled + '░' * (10 - filled)
39
+ pct = int(100 * current / total)
40
+ return f"{phase}: {bar} {pct}%"
41
+
42
+
43
+ def run_execution(
44
+ context,
45
+ inputs: Optional[Dict[str, Any]] = None,
46
+ skip_execution: bool = False
47
+ ) -> Dict[str, Any]:
48
+ """
49
+ Execute generated code.
50
+
51
+ Per D-21: Auto-triggered after code approval.
52
+ Per D-22: Transitions CODE_GENERATED → EXECUTING → EXECUTION_COMPLETE.
53
+ Per D-23: Shows progress during execution.
54
+ Per D-25: Can skip execution (user controls flow).
55
+
56
+ Args:
57
+ context: ContextManager instance
58
+ inputs: Optional input data for the algorithm
59
+ skip_execution: If True, skip execution and return mock results
60
+
61
+ Returns:
62
+ Dict with execution status and results
63
+
64
+ Example:
65
+ >>> ctx = ContextManager()
66
+ >>> ctx.start_session()
67
+ >>> ctx.save_code("def test(): pass")
68
+ >>> result = run_execution(ctx)
69
+ >>> print(result['status'])
70
+ 'success'
71
+ """
72
+ # Progress: Starting per D-23
73
+ progress = show_progress("Execute", 2, 10)
74
+ print(f"\n{progress}")
75
+ print("Setting up execution environment...")
76
+
77
+ # Check if code exists
78
+ try:
79
+ algorithm_data = context.store.load_session()
80
+ code = algorithm_data.get('code', '')
81
+
82
+ if not code:
83
+ return {
84
+ 'status': 'needs_generation',
85
+ 'progress': progress,
86
+ 'message': 'No code found. Generate code first with /algo-generate',
87
+ 'next_steps': [
88
+ 'Generate code with /algo-generate',
89
+ 'Extract algorithm with /algo-extract',
90
+ 'Check status with /algo-status'
91
+ ]
92
+ }
93
+ except Exception as e:
94
+ return {
95
+ 'status': 'error',
96
+ 'progress': progress,
97
+ 'message': f'Could not load algorithm data: {e}',
98
+ 'next_steps': [
99
+ 'Start over with /algo-extract',
100
+ 'Show help with /algo-help'
101
+ ]
102
+ }
103
+
104
+ # Per D-25: Skip execution if requested
105
+ if skip_execution:
106
+ mock_results = {
107
+ 'status': 'skipped',
108
+ 'stdout': 'Execution skipped per user request.',
109
+ 'stderr': '',
110
+ 'execution_time': 0.0,
111
+ 'return_value': None,
112
+ 'error_type': None,
113
+ 'error_message': None,
114
+ 'timestamp': datetime.now().isoformat()
115
+ }
116
+ context.save_results(mock_results)
117
+ progress = show_progress("Execute", 10, 10)
118
+ return {
119
+ 'status': 'skipped',
120
+ 'progress': progress,
121
+ 'message': 'Execution skipped. Proceed to verification.',
122
+ 'next_steps': [
123
+ 'Verify manually with /algo-verify',
124
+ 'Run with /algo-run',
125
+ 'Regenerate with /algo-generate'
126
+ ]
127
+ }
128
+
129
+ # Progress: Executing
130
+ progress = show_progress("Execute", 5, 10)
131
+ print(f"\n{progress}")
132
+ print("Running algorithm (timeout: 30s)...")
133
+
134
+ # Configure execution per D-05, D-02
135
+ config = ExecutionConfig(
136
+ timeout=30,
137
+ max_memory_mb=512
138
+ )
139
+
140
+ # Execute code
141
+ result = execute_code(code, inputs=inputs, config=config)
142
+
143
+ # Progress: Saving
144
+ progress = show_progress("Execute", 8, 10)
145
+ print(f"\n{progress}")
146
+ print("Capturing results...")
147
+
148
+ # Format results for context per D-16
149
+ results_data = {
150
+ 'status': result.status.value,
151
+ 'stdout': result.stdout,
152
+ 'stderr': result.stderr,
153
+ 'execution_time': result.runtime_seconds,
154
+ 'return_value': result.return_value,
155
+ 'error_type': result.error_type,
156
+ 'error_message': result.error_message,
157
+ 'timestamp': datetime.now().isoformat()
158
+ }
159
+
160
+ # Save to context (triggers EXECUTION_COMPLETE transition per D-22)
161
+ context.save_results(results_data)
162
+
163
+ # Final progress per D-23
164
+ progress = show_progress("Execute", 10, 10)
165
+
166
+ # Build response per D-18
167
+ if result.status == ExecutionStatus.SUCCESS:
168
+ message = f"✓ Execution complete in {result.runtime_seconds:.3f}s"
169
+ elif result.status == ExecutionStatus.TIMEOUT:
170
+ message = "⚠ Execution timed out (30s limit). Check for infinite loops."
171
+ else:
172
+ message = f"✗ Execution failed: {result.error_message or result.error_type or 'Unknown error'}"
173
+
174
+ return {
175
+ 'status': result.status.value,
176
+ 'progress': progress,
177
+ 'execution_time': result.runtime_seconds,
178
+ 'stdout': result.stdout[:2000] if result.stdout else '', # per D-15
179
+ 'stderr': result.stderr[:1000] if result.stderr else '',
180
+ 'error': result.error_message if result.status != ExecutionStatus.SUCCESS else None,
181
+ 'message': message,
182
+ 'next_steps': [
183
+ 'Verify results with /algo-verify',
184
+ 'Run again with /algo-run',
185
+ 'Regenerate code with /algo-generate'
186
+ ]
187
+ }