fluxloop-cli 0.2.35__tar.gz → 0.3.0__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.
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/PKG-INFO +1 -1
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/__init__.py +1 -1
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/reporting/html.py +1 -1
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/report/renderer.py +68 -21
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/PKG-INFO +1 -1
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/pyproject.toml +1 -1
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/README.md +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/arg_binder.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/config.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/doctor.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/evaluate.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/generate.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/init.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/parse.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/record.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/run.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/commands/status.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/config_loader.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/config_schema.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/constants.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/conversation_supervisor.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/environment.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/artifacts.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/config.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/analysis.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/core.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/reporting/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/reporting/markdown.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/success.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/llm.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/base.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/information_completeness.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/intent_recognition.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/response_clarity.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/response_consistency.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/report/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/report/aggregator.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/report/generator.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/report/pipeline.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/rules.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/templates/report.html.j2 +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/input_generator.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/llm_generator.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/main.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/project_paths.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/runner.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/target_loader.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/templates.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/testing/__init__.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/testing/pytest_plugin.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/testing/types.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/token_usage.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/validators.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/SOURCES.txt +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/dependency_links.txt +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/entry_points.txt +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/requires.txt +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli.egg-info/top_level.txt +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/setup.cfg +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_analysis_recommendations.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_arg_binder.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_config_command.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_conversation_supervisor.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_evaluate_command.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_evaluation_llm.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_init_pytest_template.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_input_generator.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_prompt_library.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_pytest_plugin.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_run_command.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_runner_multi_turn.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_success_criteria.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_target_loader.py +0 -0
- {fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/tests/test_testing_types.py +0 -0
|
@@ -93,7 +93,7 @@ DEFAULT_TEMPLATE = r"""<!DOCTYPE html>
|
|
|
93
93
|
</div>
|
|
94
94
|
</div>
|
|
95
95
|
<a
|
|
96
|
-
href="https://fluxloop.
|
|
96
|
+
href="https://fluxloop.ai/"
|
|
97
97
|
class="inline-flex items-center gap-2 self-start rounded-full border border-sky-400 px-4 py-2 text-sm font-semibold text-sky-200 transition hover:bg-sky-500/10 focus:outline-none focus:ring-2 focus:ring-sky-400 focus:ring-offset-2 focus:ring-offset-slate-950"
|
|
98
98
|
target="_blank"
|
|
99
99
|
rel="noopener noreferrer"
|
|
@@ -13,6 +13,24 @@ from jinja2 import Environment, FileSystemLoader
|
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
DEFAULT_METRIC_THRESHOLDS = {
|
|
17
|
+
"task_completion": {"good": 80, "fair": 60},
|
|
18
|
+
"hallucination": {"good": 5, "fair": 15},
|
|
19
|
+
"relevance": {"good": 90, "fair": 80},
|
|
20
|
+
"tool_usage": {"good": 90, "fair": 80},
|
|
21
|
+
"user_satisfaction": {"good": 70, "fair": 50},
|
|
22
|
+
"clarity": {"good": 90, "fair": 80},
|
|
23
|
+
"persona_consistency": {"good": 85, "fair": 70},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
DISPLAY_TO_CONFIG_METRIC_KEYS = {"tool_usage": "tool_usage_appropriateness"}
|
|
27
|
+
CONFIG_TO_DISPLAY_METRIC_KEYS = {
|
|
28
|
+
config_key: display_key for display_key, config_key in DISPLAY_TO_CONFIG_METRIC_KEYS.items()
|
|
29
|
+
}
|
|
30
|
+
GENERIC_THRESHOLD_FALLBACK = {"good": 80, "fair": 60}
|
|
31
|
+
INVERTED_METRICS = {"hallucination"}
|
|
32
|
+
|
|
33
|
+
|
|
16
34
|
class ReportRenderer:
|
|
17
35
|
"""Prepares data and renders the HTML report."""
|
|
18
36
|
|
|
@@ -155,27 +173,56 @@ class ReportRenderer:
|
|
|
155
173
|
}
|
|
156
174
|
|
|
157
175
|
def _transform_eval_criteria(self, eval_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
158
|
-
|
|
159
|
-
efficiency = eval_config.get("efficiency", {})
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
metrics_cfg = eval_config.get("metrics", {}) or {}
|
|
177
|
+
efficiency = eval_config.get("efficiency", {}) or {}
|
|
178
|
+
thresholds: Dict[str, Dict[str, str]] = {}
|
|
179
|
+
|
|
180
|
+
def _coerce_number(value: Any, fallback: float) -> float:
|
|
181
|
+
if isinstance(value, (int, float)):
|
|
182
|
+
return float(value)
|
|
183
|
+
try:
|
|
184
|
+
return float(value)
|
|
185
|
+
except (TypeError, ValueError):
|
|
186
|
+
return float(fallback)
|
|
187
|
+
|
|
188
|
+
def _format_number(value: float) -> str:
|
|
189
|
+
if value.is_integer():
|
|
190
|
+
return str(int(value))
|
|
191
|
+
return str(value)
|
|
192
|
+
|
|
193
|
+
def _register_threshold(display_key: str, good_val: float, fair_val: float) -> None:
|
|
194
|
+
good_text, fair_text = _format_number(good_val), _format_number(fair_val)
|
|
195
|
+
if display_key in INVERTED_METRICS:
|
|
196
|
+
thresholds[display_key] = {
|
|
197
|
+
"good": f"<={good_text}%",
|
|
198
|
+
"fair": f"{good_text}-{fair_text}%",
|
|
199
|
+
"poor": f">{fair_text}%",
|
|
200
|
+
}
|
|
201
|
+
else:
|
|
202
|
+
thresholds[display_key] = {
|
|
203
|
+
"good": f">={good_text}%",
|
|
204
|
+
"fair": f"{fair_text}-{good_text}%",
|
|
205
|
+
"poor": f"<{fair_text}%",
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
def _resolve_thresholds(display_key: str, metric_cfg: Dict[str, Any]) -> None:
|
|
209
|
+
defaults = DEFAULT_METRIC_THRESHOLDS.get(display_key, GENERIC_THRESHOLD_FALLBACK)
|
|
210
|
+
thresholds_cfg = metric_cfg.get("thresholds", {})
|
|
211
|
+
good_val = _coerce_number(thresholds_cfg.get("good"), defaults["good"])
|
|
212
|
+
fair_val = _coerce_number(thresholds_cfg.get("fair"), defaults["fair"])
|
|
213
|
+
_register_threshold(display_key, good_val, fair_val)
|
|
214
|
+
|
|
215
|
+
for cfg_key, cfg_value in metrics_cfg.items():
|
|
216
|
+
display_key = CONFIG_TO_DISPLAY_METRIC_KEYS.get(cfg_key, cfg_key)
|
|
217
|
+
_resolve_thresholds(display_key, cfg_value)
|
|
218
|
+
|
|
219
|
+
for display_key, defaults in DEFAULT_METRIC_THRESHOLDS.items():
|
|
220
|
+
if display_key not in thresholds:
|
|
221
|
+
_register_threshold(
|
|
222
|
+
display_key,
|
|
223
|
+
float(defaults["good"]),
|
|
224
|
+
float(defaults["fair"]),
|
|
225
|
+
)
|
|
179
226
|
|
|
180
227
|
eff_flags = {}
|
|
181
228
|
if "output_tokens" in efficiency:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/reporting/__init__.py
RENAMED
|
File without changes
|
{fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/engine/reporting/markdown.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/intent_recognition.py
RENAMED
|
File without changes
|
{fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/response_clarity.py
RENAMED
|
File without changes
|
{fluxloop_cli-0.2.35 → fluxloop_cli-0.3.0}/fluxloop_cli/evaluation/prompts/response_consistency.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|