fluxloop-cli 0.2.33__tar.gz → 0.2.35__tar.gz

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 (79) hide show
  1. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/PKG-INFO +1 -2
  2. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/__init__.py +1 -1
  3. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/evaluate.py +0 -6
  4. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/report/pipeline.py +1 -13
  5. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/PKG-INFO +1 -2
  6. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/SOURCES.txt +0 -1
  7. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/requires.txt +0 -1
  8. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/pyproject.toml +1 -2
  9. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_evaluate_command.py +1 -6
  10. fluxloop_cli-0.2.33/fluxloop_cli/evaluation/report/pdf_exporter.py +0 -71
  11. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/README.md +0 -0
  12. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/arg_binder.py +0 -0
  13. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/__init__.py +0 -0
  14. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/config.py +0 -0
  15. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/doctor.py +0 -0
  16. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/generate.py +0 -0
  17. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/init.py +0 -0
  18. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/parse.py +0 -0
  19. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/record.py +0 -0
  20. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/run.py +0 -0
  21. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/commands/status.py +0 -0
  22. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/config_loader.py +0 -0
  23. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/config_schema.py +0 -0
  24. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/constants.py +0 -0
  25. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/conversation_supervisor.py +0 -0
  26. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/environment.py +0 -0
  27. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/__init__.py +0 -0
  28. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/artifacts.py +0 -0
  29. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/config.py +0 -0
  30. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/__init__.py +0 -0
  31. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/analysis.py +0 -0
  32. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/core.py +0 -0
  33. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/reporting/__init__.py +0 -0
  34. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/reporting/html.py +0 -0
  35. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/reporting/markdown.py +0 -0
  36. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/engine/success.py +0 -0
  37. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/llm.py +0 -0
  38. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/__init__.py +0 -0
  39. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/base.py +0 -0
  40. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/information_completeness.py +0 -0
  41. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/intent_recognition.py +0 -0
  42. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/response_clarity.py +0 -0
  43. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/prompts/response_consistency.py +0 -0
  44. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/report/__init__.py +0 -0
  45. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/report/aggregator.py +0 -0
  46. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/report/generator.py +0 -0
  47. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/report/renderer.py +0 -0
  48. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/rules.py +0 -0
  49. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/evaluation/templates/report.html.j2 +0 -0
  50. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/input_generator.py +0 -0
  51. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/llm_generator.py +0 -0
  52. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/main.py +0 -0
  53. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/project_paths.py +0 -0
  54. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/runner.py +0 -0
  55. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/target_loader.py +0 -0
  56. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/templates.py +0 -0
  57. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/testing/__init__.py +0 -0
  58. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/testing/pytest_plugin.py +0 -0
  59. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/testing/types.py +0 -0
  60. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/token_usage.py +0 -0
  61. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli/validators.py +0 -0
  62. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/dependency_links.txt +0 -0
  63. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/entry_points.txt +0 -0
  64. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/fluxloop_cli.egg-info/top_level.txt +0 -0
  65. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/setup.cfg +0 -0
  66. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_analysis_recommendations.py +0 -0
  67. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_arg_binder.py +0 -0
  68. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_config_command.py +0 -0
  69. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_conversation_supervisor.py +0 -0
  70. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_evaluation_llm.py +0 -0
  71. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_init_pytest_template.py +0 -0
  72. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_input_generator.py +0 -0
  73. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_prompt_library.py +0 -0
  74. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_pytest_plugin.py +0 -0
  75. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_run_command.py +0 -0
  76. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_runner_multi_turn.py +0 -0
  77. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_success_criteria.py +0 -0
  78. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_target_loader.py +0 -0
  79. {fluxloop_cli-0.2.33 → fluxloop_cli-0.2.35}/tests/test_testing_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fluxloop-cli
3
- Version: 0.2.33
3
+ Version: 0.2.35
4
4
  Summary: FluxLoop CLI for running agent simulations
5
5
  Author-email: FluxLoop Team <team@fluxloop.dev>
6
6
  License: Apache-2.0
@@ -28,7 +28,6 @@ Requires-Dist: python-dotenv>=1.0.0
28
28
  Requires-Dist: fluxloop>=0.1.0
29
29
  Requires-Dist: ruamel.yaml>=0.17.0
30
30
  Requires-Dist: Jinja2>=3.0
31
- Requires-Dist: weasyprint>=61.0
32
31
  Provides-Extra: dev
33
32
  Requires-Dist: pytest>=7.0; extra == "dev"
34
33
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -2,7 +2,7 @@
2
2
  FluxLoop CLI - Command-line interface for running agent simulations.
3
3
  """
4
4
 
5
- __version__ = "0.2.33"
5
+ __version__ = "0.2.35"
6
6
 
7
7
  from .main import app
8
8
 
@@ -259,12 +259,6 @@ def experiment(
259
259
 
260
260
  artifacts = asyncio.run(pipeline.run(trace_records, trace_summaries))
261
261
  console.print(f"\n✅ Report ready: [bold cyan]{artifacts.html_path}[/bold cyan]")
262
- if artifacts.pdf_path:
263
- console.print(f"🖨️ PDF ready: [bold green]{artifacts.pdf_path}[/bold green]")
264
- else:
265
- console.print(
266
- "⚠️ PDF export skipped (WeasyPrint is unavailable or PDF rendering failed)."
267
- )
268
262
 
269
263
 
270
264
 
@@ -10,7 +10,6 @@ from typing import Any, Dict, List, Optional
10
10
 
11
11
  from .aggregator import StatsAggregator
12
12
  from .generator import OverallEvaluator, ReportLLMClient, TraceEvaluator
13
- from .pdf_exporter import PdfExportError, ReportPdfExporter
14
13
  from .renderer import ReportRenderer
15
14
 
16
15
  logger = logging.getLogger(__name__)
@@ -21,7 +20,6 @@ class ReportArtifacts:
21
20
  """Artifacts produced by the evaluation report pipeline."""
22
21
 
23
22
  html_path: Path
24
- pdf_path: Optional[Path] = None
25
23
 
26
24
 
27
25
  class ReportPipeline:
@@ -45,7 +43,6 @@ class ReportPipeline:
45
43
  self.aggregator = StatsAggregator(config)
46
44
  self.overall_evaluator = OverallEvaluator(self.client, config)
47
45
  self.renderer = ReportRenderer(output_dir)
48
- self.pdf_exporter = ReportPdfExporter(output_dir)
49
46
 
50
47
  async def run(
51
48
  self,
@@ -86,18 +83,9 @@ class ReportPipeline:
86
83
  report_path = self.renderer.render(
87
84
  rule_based_data, llm_ov_data, traces_for_rules, self.config
88
85
  )
89
-
90
- pdf_path: Optional[Path] = None
91
- try:
92
- pdf_path = self.pdf_exporter.export(report_path)
93
- except PdfExportError as exc:
94
- logger.warning("PDF export failed: %s", exc)
95
86
 
96
87
  logger.info("✅ Pipeline Complete! Report: %s", report_path)
97
- if pdf_path:
98
- logger.info("✅ PDF ready: %s", pdf_path)
99
-
100
- return ReportArtifacts(html_path=report_path, pdf_path=pdf_path)
88
+ return ReportArtifacts(html_path=report_path)
101
89
 
102
90
  async def _run_pt_evaluations(self, traces: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
103
91
  """Run TraceEvaluator concurrently."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fluxloop-cli
3
- Version: 0.2.33
3
+ Version: 0.2.35
4
4
  Summary: FluxLoop CLI for running agent simulations
5
5
  Author-email: FluxLoop Team <team@fluxloop.dev>
6
6
  License: Apache-2.0
@@ -28,7 +28,6 @@ Requires-Dist: python-dotenv>=1.0.0
28
28
  Requires-Dist: fluxloop>=0.1.0
29
29
  Requires-Dist: ruamel.yaml>=0.17.0
30
30
  Requires-Dist: Jinja2>=3.0
31
- Requires-Dist: weasyprint>=61.0
32
31
  Provides-Extra: dev
33
32
  Requires-Dist: pytest>=7.0; extra == "dev"
34
33
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -53,7 +53,6 @@ fluxloop_cli/evaluation/prompts/response_consistency.py
53
53
  fluxloop_cli/evaluation/report/__init__.py
54
54
  fluxloop_cli/evaluation/report/aggregator.py
55
55
  fluxloop_cli/evaluation/report/generator.py
56
- fluxloop_cli/evaluation/report/pdf_exporter.py
57
56
  fluxloop_cli/evaluation/report/pipeline.py
58
57
  fluxloop_cli/evaluation/report/renderer.py
59
58
  fluxloop_cli/evaluation/templates/report.html.j2
@@ -7,7 +7,6 @@ python-dotenv>=1.0.0
7
7
  fluxloop>=0.1.0
8
8
  ruamel.yaml>=0.17.0
9
9
  Jinja2>=3.0
10
- weasyprint>=61.0
11
10
 
12
11
  [anthropic]
13
12
  anthropic>=0.7.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fluxloop-cli"
7
- version = "0.2.33"
7
+ version = "0.2.35"
8
8
  description = "FluxLoop CLI for running agent simulations"
9
9
  authors = [
10
10
  {name = "FluxLoop Team", email = "team@fluxloop.dev"}
@@ -34,7 +34,6 @@ dependencies = [
34
34
  "fluxloop>=0.1.0",
35
35
  "ruamel.yaml>=0.17.0",
36
36
  "Jinja2>=3.0",
37
- "weasyprint>=61.0",
38
37
  ]
39
38
 
40
39
  [project.optional-dependencies]
@@ -28,9 +28,7 @@ def pipeline_stub(monkeypatch):
28
28
  self.output_dir.mkdir(parents=True, exist_ok=True)
29
29
  html_path = self.output_dir / "report.html"
30
30
  html_path.write_text("<html>stub</html>", encoding="utf-8")
31
- pdf_path = self.output_dir / "report.pdf"
32
- pdf_path.write_bytes(b"%PDF-1.4\n%Stub\n")
33
- return ReportArtifacts(html_path=html_path, pdf_path=pdf_path)
31
+ return ReportArtifacts(html_path=html_path)
34
32
 
35
33
  monkeypatch.setattr("fluxloop_cli.commands.evaluate.ReportPipeline", StubPipeline)
36
34
  return instances
@@ -312,7 +310,6 @@ def test_evaluate_generates_outputs(tmp_path: Path, pipeline_stub) -> None:
312
310
  output_dir = experiment_dir / "evaluation_report"
313
311
  html_report = output_dir / "report.html"
314
312
  assert html_report.exists()
315
- assert (output_dir / "report.pdf").exists()
316
313
 
317
314
  assert len(pipeline_stub) == 1
318
315
  stub_instance = pipeline_stub[0]
@@ -354,7 +351,6 @@ def test_evaluate_llm_without_api_key_is_recorded(tmp_path: Path, pipeline_stub)
354
351
 
355
352
  output_dir = experiment_dir / "evaluation_report"
356
353
  assert (output_dir / "report.html").exists()
357
- assert (output_dir / "report.pdf").exists()
358
354
 
359
355
  assert len(pipeline_stub) == 1
360
356
  assert pipeline_stub[0].api_key is None
@@ -395,7 +391,6 @@ def test_evaluate_phase2_extended_outputs(tmp_path: Path, pipeline_stub) -> None
395
391
 
396
392
  output_dir = experiment_dir / "evaluation_report"
397
393
  assert (output_dir / "report.html").exists()
398
- assert (output_dir / "report.pdf").exists()
399
394
 
400
395
  assert len(pipeline_stub) == 1
401
396
  stub_instance = pipeline_stub[0]
@@ -1,71 +0,0 @@
1
- """Utilities for exporting the rendered HTML report as a PDF."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- from pathlib import Path
7
- from typing import Optional
8
-
9
- try: # pragma: no cover - import guard exercised via tests/log statements
10
- from weasyprint import CSS, HTML # type: ignore
11
- except ModuleNotFoundError: # pragma: no cover - handled gracefully at runtime
12
- HTML = None # type: ignore
13
- CSS = None # type: ignore
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class PdfExportError(RuntimeError):
19
- """Raised when PDF generation fails."""
20
-
21
-
22
- class ReportPdfExporter:
23
- """Converts the generated HTML report into a PDF file."""
24
-
25
- def __init__(self, output_dir: Path) -> None:
26
- self.output_dir = output_dir
27
-
28
- def export(self, html_report: Path) -> Optional[Path]:
29
- """Render ``report.html`` to ``report.pdf`` if WeasyPrint is available."""
30
-
31
- if HTML is None:
32
- logger.info(
33
- "WeasyPrint is not installed; skipping PDF export for %s", html_report
34
- )
35
- return None
36
-
37
- if not html_report.exists():
38
- raise PdfExportError(f"HTML report not found at {html_report}")
39
-
40
- pdf_path = self.output_dir / "report.pdf"
41
- try:
42
- stylesheets = [CSS(string=self._default_portrait_css())] if CSS else None
43
- HTML(filename=str(html_report), base_url=str(html_report.parent)).write_pdf(
44
- target=str(pdf_path),
45
- stylesheets=stylesheets,
46
- )
47
- logger.info("📄 PDF report generated at %s", pdf_path)
48
- except Exception as exc: # pragma: no cover - depends on external renderer
49
- raise PdfExportError(f"Failed to generate PDF: {exc}") from exc
50
-
51
- return pdf_path
52
-
53
- def _default_portrait_css(self) -> str:
54
- """Ensure the PDF renders in portrait mode for better readability."""
55
-
56
- return """
57
- @page {
58
- size: A4 portrait;
59
- margin: 15mm;
60
- }
61
-
62
- html, body {
63
- width: 100%;
64
- height: auto;
65
- }
66
-
67
- .page-break {
68
- page-break-after: always;
69
- }
70
- """
71
-
File without changes
File without changes