deepagents-printshop 0.1.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.
Files changed (37) hide show
  1. agents/content_editor/__init__.py +1 -0
  2. agents/content_editor/agent.py +279 -0
  3. agents/content_editor/content_reviewer.py +327 -0
  4. agents/content_editor/versioned_agent.py +455 -0
  5. agents/latex_specialist/__init__.py +1 -0
  6. agents/latex_specialist/agent.py +531 -0
  7. agents/latex_specialist/latex_analyzer.py +510 -0
  8. agents/latex_specialist/latex_optimizer.py +1192 -0
  9. agents/qa_orchestrator/__init__.py +1 -0
  10. agents/qa_orchestrator/agent.py +603 -0
  11. agents/qa_orchestrator/langgraph_workflow.py +733 -0
  12. agents/qa_orchestrator/pipeline_types.py +72 -0
  13. agents/qa_orchestrator/quality_gates.py +495 -0
  14. agents/qa_orchestrator/workflow_coordinator.py +139 -0
  15. agents/research_agent/__init__.py +1 -0
  16. agents/research_agent/agent.py +258 -0
  17. agents/research_agent/llm_report_generator.py +1023 -0
  18. agents/research_agent/report_generator.py +536 -0
  19. agents/visual_qa/__init__.py +1 -0
  20. agents/visual_qa/agent.py +410 -0
  21. deepagents_printshop-0.1.0.dist-info/METADATA +744 -0
  22. deepagents_printshop-0.1.0.dist-info/RECORD +37 -0
  23. deepagents_printshop-0.1.0.dist-info/WHEEL +4 -0
  24. deepagents_printshop-0.1.0.dist-info/entry_points.txt +2 -0
  25. deepagents_printshop-0.1.0.dist-info/licenses/LICENSE +86 -0
  26. tools/__init__.py +1 -0
  27. tools/change_tracker.py +419 -0
  28. tools/content_type_loader.py +171 -0
  29. tools/graph_generator.py +281 -0
  30. tools/latex_generator.py +374 -0
  31. tools/llm_latex_generator.py +678 -0
  32. tools/magazine_layout.py +462 -0
  33. tools/pattern_injector.py +250 -0
  34. tools/pattern_learner.py +477 -0
  35. tools/pdf_compiler.py +386 -0
  36. tools/version_manager.py +346 -0
  37. tools/visual_qa.py +799 -0
@@ -0,0 +1,346 @@
1
+ """
2
+ Version Manager - Milestone 2
3
+
4
+ Handles content versioning, tracking, and management for iterative improvements.
5
+ """
6
+
7
+ import json
8
+ import shutil
9
+ from pathlib import Path
10
+ from datetime import datetime
11
+ from typing import Dict, List, Optional, Tuple
12
+ import hashlib
13
+
14
+
15
+ class VersionManager:
16
+ """
17
+ Manages content versions and provides version tracking capabilities.
18
+
19
+ Features:
20
+ - Create and track content versions
21
+ - Generate version manifests
22
+ - Handle rollback operations
23
+ - Maintain version lineage
24
+ """
25
+
26
+ def __init__(self, base_dir: str = "artifacts"):
27
+ """
28
+ Initialize the version manager.
29
+
30
+ Args:
31
+ base_dir: Base directory for all artifacts
32
+ """
33
+ self.base_dir = Path(base_dir)
34
+ self.content_dir = self.base_dir / "reviewed_content"
35
+ self.history_dir = self.base_dir / "version_history"
36
+ self.manifest_path = self.history_dir / "version_manifest.json"
37
+
38
+ # Ensure directories exist
39
+ self.content_dir.mkdir(parents=True, exist_ok=True)
40
+ self.history_dir.mkdir(parents=True, exist_ok=True)
41
+ (self.history_dir / "changes").mkdir(exist_ok=True)
42
+ (self.history_dir / "diffs").mkdir(exist_ok=True)
43
+
44
+ # Initialize manifest if it doesn't exist
45
+ self._init_manifest()
46
+
47
+ def _init_manifest(self):
48
+ """Initialize the version manifest file."""
49
+ if not self.manifest_path.exists():
50
+ manifest = {
51
+ "versions": {},
52
+ "latest_version": None,
53
+ "created_at": datetime.now().isoformat(),
54
+ "last_updated": datetime.now().isoformat()
55
+ }
56
+ self._save_manifest(manifest)
57
+
58
+ def _load_manifest(self) -> Dict:
59
+ """Load the version manifest."""
60
+ with open(self.manifest_path, 'r', encoding='utf-8') as f:
61
+ return json.load(f)
62
+
63
+ def _save_manifest(self, manifest: Dict):
64
+ """Save the version manifest."""
65
+ manifest["last_updated"] = datetime.now().isoformat()
66
+ with open(self.manifest_path, 'w', encoding='utf-8') as f:
67
+ json.dump(manifest, f, indent=2, ensure_ascii=False)
68
+
69
+ def _calculate_content_hash(self, content_dict: Dict[str, str]) -> str:
70
+ """Calculate a hash of the content for integrity checking."""
71
+ content_str = json.dumps(content_dict, sort_keys=True)
72
+ return hashlib.sha256(content_str.encode()).hexdigest()[:16]
73
+
74
+ def create_version(self,
75
+ content_dict: Dict[str, str],
76
+ version_name: str,
77
+ agent_name: str = "unknown",
78
+ parent_version: Optional[str] = None,
79
+ metadata: Optional[Dict] = None) -> Dict:
80
+ """
81
+ Create a new content version.
82
+
83
+ Args:
84
+ content_dict: Dictionary of filename -> content
85
+ version_name: Name for this version (e.g., "v1_content_edited")
86
+ agent_name: Name of the agent that created this version
87
+ parent_version: Name of the parent version (if any)
88
+ metadata: Additional metadata for this version
89
+
90
+ Returns:
91
+ Version info dictionary
92
+ """
93
+ manifest = self._load_manifest()
94
+
95
+ # Check if version already exists
96
+ if version_name in manifest["versions"]:
97
+ raise ValueError(f"Version {version_name} already exists")
98
+
99
+ # Create version directory
100
+ version_dir = self.content_dir / version_name
101
+ version_dir.mkdir(exist_ok=True)
102
+
103
+ # Save content files
104
+ for filename, content in content_dict.items():
105
+ file_path = version_dir / filename
106
+ with open(file_path, 'w', encoding='utf-8') as f:
107
+ f.write(content)
108
+
109
+ # Create version metadata
110
+ version_info = {
111
+ "name": version_name,
112
+ "agent": agent_name,
113
+ "parent_version": parent_version,
114
+ "created_at": datetime.now().isoformat(),
115
+ "content_hash": self._calculate_content_hash(content_dict),
116
+ "files": list(content_dict.keys()),
117
+ "file_count": len(content_dict),
118
+ "directory": str(version_dir.relative_to(self.base_dir)),
119
+ "metadata": metadata or {}
120
+ }
121
+
122
+ # Update manifest
123
+ manifest["versions"][version_name] = version_info
124
+ manifest["latest_version"] = version_name
125
+ self._save_manifest(manifest)
126
+
127
+ # Update current symlink
128
+ self._update_current_symlink(version_name)
129
+
130
+ return version_info
131
+
132
+ def get_version(self, version_name: str) -> Optional[Dict]:
133
+ """
134
+ Get information about a specific version.
135
+
136
+ Args:
137
+ version_name: Name of the version to retrieve
138
+
139
+ Returns:
140
+ Version info dictionary or None if not found
141
+ """
142
+ manifest = self._load_manifest()
143
+ return manifest["versions"].get(version_name)
144
+
145
+ def get_version_content(self, version_name: str) -> Dict[str, str]:
146
+ """
147
+ Load the content of a specific version.
148
+
149
+ Args:
150
+ version_name: Name of the version to load
151
+
152
+ Returns:
153
+ Dictionary of filename -> content
154
+ """
155
+ version_info = self.get_version(version_name)
156
+ if not version_info:
157
+ raise ValueError(f"Version {version_name} not found")
158
+
159
+ version_dir = self.base_dir / version_info["directory"]
160
+ content_dict = {}
161
+
162
+ for filename in version_info["files"]:
163
+ file_path = version_dir / filename
164
+ if file_path.exists():
165
+ with open(file_path, 'r', encoding='utf-8') as f:
166
+ content_dict[filename] = f.read()
167
+
168
+ return content_dict
169
+
170
+ def list_versions(self) -> List[Dict]:
171
+ """
172
+ List all versions in chronological order.
173
+
174
+ Returns:
175
+ List of version info dictionaries
176
+ """
177
+ manifest = self._load_manifest()
178
+ versions = list(manifest["versions"].values())
179
+
180
+ # Sort by creation date
181
+ versions.sort(key=lambda v: v["created_at"])
182
+
183
+ return versions
184
+
185
+ def get_latest_version(self) -> Optional[str]:
186
+ """
187
+ Get the name of the latest version.
188
+
189
+ Returns:
190
+ Latest version name or None if no versions exist
191
+ """
192
+ manifest = self._load_manifest()
193
+ return manifest.get("latest_version")
194
+
195
+ def get_version_lineage(self, version_name: str) -> List[str]:
196
+ """
197
+ Get the lineage (ancestry) of a version.
198
+
199
+ Args:
200
+ version_name: Version to trace lineage for
201
+
202
+ Returns:
203
+ List of version names from root to specified version
204
+ """
205
+ lineage = []
206
+ current = version_name
207
+
208
+ while current:
209
+ version_info = self.get_version(current)
210
+ if not version_info:
211
+ break
212
+
213
+ lineage.insert(0, current)
214
+ current = version_info.get("parent_version")
215
+
216
+ return lineage
217
+
218
+ def rollback_to_version(self, version_name: str) -> Dict:
219
+ """
220
+ Rollback to a specific version (updates current symlink).
221
+
222
+ Args:
223
+ version_name: Version to rollback to
224
+
225
+ Returns:
226
+ Version info of the rollback target
227
+ """
228
+ version_info = self.get_version(version_name)
229
+ if not version_info:
230
+ raise ValueError(f"Version {version_name} not found")
231
+
232
+ # Update current symlink
233
+ self._update_current_symlink(version_name)
234
+
235
+ # Update manifest to mark this as latest
236
+ manifest = self._load_manifest()
237
+ manifest["latest_version"] = version_name
238
+ self._save_manifest(manifest)
239
+
240
+ return version_info
241
+
242
+ def delete_version(self, version_name: str) -> bool:
243
+ """
244
+ Delete a version (use with caution).
245
+
246
+ Args:
247
+ version_name: Version to delete
248
+
249
+ Returns:
250
+ True if deletion was successful
251
+ """
252
+ version_info = self.get_version(version_name)
253
+ if not version_info:
254
+ return False
255
+
256
+ # Remove directory
257
+ version_dir = self.base_dir / version_info["directory"]
258
+ if version_dir.exists():
259
+ shutil.rmtree(version_dir)
260
+
261
+ # Update manifest
262
+ manifest = self._load_manifest()
263
+ del manifest["versions"][version_name]
264
+
265
+ # Update latest if this was the latest
266
+ if manifest.get("latest_version") == version_name:
267
+ versions = list(manifest["versions"].values())
268
+ if versions:
269
+ latest = max(versions, key=lambda v: v["created_at"])
270
+ manifest["latest_version"] = latest["name"]
271
+ else:
272
+ manifest["latest_version"] = None
273
+
274
+ self._save_manifest(manifest)
275
+ return True
276
+
277
+ def _update_current_symlink(self, version_name: str):
278
+ """Update the 'current' pointer to the specified version."""
279
+ current_link = self.content_dir / "current"
280
+ target_dir = version_name
281
+
282
+ # Try symlink first, fall back to text file on Windows if permission denied
283
+ try:
284
+ # Remove existing symlink
285
+ if current_link.exists() or current_link.is_symlink():
286
+ current_link.unlink()
287
+ # Create new symlink
288
+ current_link.symlink_to(target_dir)
289
+ except OSError:
290
+ # Windows without admin rights - use a text file instead
291
+ current_file = self.content_dir / "current.txt"
292
+ with open(current_file, 'w', encoding='utf-8') as f:
293
+ f.write(version_name)
294
+
295
+ def get_version_stats(self) -> Dict:
296
+ """
297
+ Get statistics about all versions.
298
+
299
+ Returns:
300
+ Statistics dictionary
301
+ """
302
+ versions = self.list_versions()
303
+
304
+ if not versions:
305
+ return {
306
+ "total_versions": 0,
307
+ "earliest_version": None,
308
+ "latest_version": None,
309
+ "agents_used": [],
310
+ "total_files": 0
311
+ }
312
+
313
+ agents = set()
314
+ total_files = 0
315
+
316
+ for version in versions:
317
+ agents.add(version.get("agent", "unknown"))
318
+ total_files += version.get("file_count", 0)
319
+
320
+ return {
321
+ "total_versions": len(versions),
322
+ "earliest_version": versions[0]["name"],
323
+ "latest_version": versions[-1]["name"],
324
+ "agents_used": list(agents),
325
+ "total_files": total_files,
326
+ "average_files_per_version": total_files / len(versions) if versions else 0
327
+ }
328
+
329
+ def export_version_history(self, output_path: str):
330
+ """Export complete version history to a JSON file."""
331
+ manifest = self._load_manifest()
332
+ stats = self.get_version_stats()
333
+
334
+ export_data = {
335
+ "export_timestamp": datetime.now().isoformat(),
336
+ "statistics": stats,
337
+ "manifest": manifest,
338
+ "version_lineages": {}
339
+ }
340
+
341
+ # Add lineage for each version
342
+ for version_name in manifest["versions"]:
343
+ export_data["version_lineages"][version_name] = self.get_version_lineage(version_name)
344
+
345
+ with open(output_path, 'w', encoding='utf-8') as f:
346
+ json.dump(export_data, f, indent=2, ensure_ascii=False)