fluxloop-cli 0.2.1__tar.gz → 0.2.3__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.
Potentially problematic release.
This version of fluxloop-cli might be problematic. Click here for more details.
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/PKG-INFO +1 -1
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/__init__.py +1 -1
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/config_loader.py +63 -1
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/input_generator.py +8 -28
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/templates.py +3 -3
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/validators.py +10 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/PKG-INFO +1 -1
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/pyproject.toml +1 -1
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/README.md +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/arg_binder.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/__init__.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/config.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/generate.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/init.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/parse.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/record.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/run.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/commands/status.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/config_schema.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/constants.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/llm_generator.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/main.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/project_paths.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/runner.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli/target_loader.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/SOURCES.txt +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/dependency_links.txt +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/entry_points.txt +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/requires.txt +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/fluxloop_cli.egg-info/top_level.txt +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/setup.cfg +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/tests/test_arg_binder.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/tests/test_config_command.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/tests/test_input_generator.py +0 -0
- {fluxloop_cli-0.2.1 → fluxloop_cli-0.2.3}/tests/test_target_loader.py +0 -0
|
@@ -22,7 +22,7 @@ from .constants import CONFIG_DIRECTORY_NAME
|
|
|
22
22
|
# Add shared schemas to path
|
|
23
23
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "shared"))
|
|
24
24
|
|
|
25
|
-
from fluxloop.schemas import ExperimentConfig
|
|
25
|
+
from fluxloop.schemas import ExperimentConfig, VariationStrategy
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def load_experiment_config(
|
|
@@ -75,6 +75,8 @@ def load_experiment_config(
|
|
|
75
75
|
data = merged
|
|
76
76
|
source_dir = project_root
|
|
77
77
|
|
|
78
|
+
_normalize_variation_strategies(data)
|
|
79
|
+
|
|
78
80
|
# Validate and create config object
|
|
79
81
|
try:
|
|
80
82
|
config = ExperimentConfig(**data)
|
|
@@ -222,6 +224,66 @@ def _deep_merge(target: Dict[str, Any], incoming: Dict[str, Any]) -> Dict[str, A
|
|
|
222
224
|
return target
|
|
223
225
|
|
|
224
226
|
|
|
227
|
+
def _normalize_variation_strategies(payload: Dict[str, Any]) -> None:
|
|
228
|
+
"""Ensure variation strategies are represented as enum-compatible strings."""
|
|
229
|
+
|
|
230
|
+
strategies = payload.get("variation_strategies")
|
|
231
|
+
if not isinstance(strategies, list):
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
normalized = []
|
|
235
|
+
for entry in strategies:
|
|
236
|
+
if isinstance(entry, VariationStrategy):
|
|
237
|
+
normalized.append(entry.value)
|
|
238
|
+
continue
|
|
239
|
+
|
|
240
|
+
candidate: Optional[str]
|
|
241
|
+
if isinstance(entry, str):
|
|
242
|
+
candidate = entry
|
|
243
|
+
elif isinstance(entry, dict):
|
|
244
|
+
candidate = (
|
|
245
|
+
entry.get("type")
|
|
246
|
+
or entry.get("name")
|
|
247
|
+
or entry.get("strategy")
|
|
248
|
+
or entry.get("value")
|
|
249
|
+
)
|
|
250
|
+
else:
|
|
251
|
+
candidate = str(entry)
|
|
252
|
+
|
|
253
|
+
if not candidate:
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
canonical = (
|
|
257
|
+
candidate.strip()
|
|
258
|
+
.lower()
|
|
259
|
+
.replace(" ", "_")
|
|
260
|
+
.replace("-", "_")
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
alias_map = {
|
|
264
|
+
"error_prone": (
|
|
265
|
+
VariationStrategy.ERROR_PRONE.value
|
|
266
|
+
if hasattr(VariationStrategy, "ERROR_PRONE")
|
|
267
|
+
else VariationStrategy.TYPO.value
|
|
268
|
+
),
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
canonical = alias_map.get(canonical, canonical)
|
|
272
|
+
|
|
273
|
+
normalized.append(canonical)
|
|
274
|
+
|
|
275
|
+
# Remove duplicates while preserving order
|
|
276
|
+
seen = set()
|
|
277
|
+
deduped = []
|
|
278
|
+
for item in normalized:
|
|
279
|
+
if item in seen:
|
|
280
|
+
continue
|
|
281
|
+
seen.add(item)
|
|
282
|
+
deduped.append(item)
|
|
283
|
+
|
|
284
|
+
payload["variation_strategies"] = deduped
|
|
285
|
+
|
|
286
|
+
|
|
225
287
|
def _detect_config_context(resolved_path: Path) -> tuple[str, Path, Path]:
|
|
226
288
|
"""Determine whether the path points to legacy or multi-section config."""
|
|
227
289
|
|
|
@@ -88,40 +88,27 @@ class GenerationError(Exception):
|
|
|
88
88
|
def generate_inputs(
|
|
89
89
|
config: ExperimentConfig,
|
|
90
90
|
settings: GenerationSettings,
|
|
91
|
-
recording_template: Optional[Dict[str, Any]] = None,
|
|
92
91
|
) -> GenerationResult:
|
|
93
92
|
"""Generate deterministic input entries based on configuration."""
|
|
94
93
|
base_inputs = config.base_inputs
|
|
95
|
-
config_for_generation = config
|
|
96
|
-
if recording_template:
|
|
97
|
-
base_inputs = [
|
|
98
|
-
{
|
|
99
|
-
"input": recording_template["base_content"],
|
|
100
|
-
"metadata": {
|
|
101
|
-
"source": "recording",
|
|
102
|
-
"target": recording_template.get("target"),
|
|
103
|
-
},
|
|
104
|
-
}
|
|
105
|
-
]
|
|
106
|
-
config_for_generation = config.model_copy(update={"base_inputs": base_inputs})
|
|
107
94
|
|
|
108
95
|
if not base_inputs:
|
|
109
96
|
raise GenerationError("base_inputs must be defined to generate inputs")
|
|
110
97
|
|
|
111
|
-
mode = settings.mode or
|
|
98
|
+
mode = settings.mode or config.input_generation.mode
|
|
112
99
|
|
|
113
100
|
if mode == InputGenerationMode.LLM:
|
|
114
101
|
strategies: Sequence[VariationStrategy]
|
|
115
102
|
if settings.strategies and len(settings.strategies) > 0:
|
|
116
103
|
strategies = list(settings.strategies)
|
|
117
|
-
elif
|
|
118
|
-
strategies =
|
|
104
|
+
elif config.variation_strategies:
|
|
105
|
+
strategies = config.variation_strategies
|
|
119
106
|
else:
|
|
120
107
|
strategies = DEFAULT_STRATEGIES
|
|
121
108
|
|
|
122
109
|
try:
|
|
123
110
|
raw_entries = generate_llm_inputs(
|
|
124
|
-
config=
|
|
111
|
+
config=config,
|
|
125
112
|
strategies=strategies,
|
|
126
113
|
settings=settings,
|
|
127
114
|
)
|
|
@@ -134,23 +121,16 @@ def generate_inputs(
|
|
|
134
121
|
]
|
|
135
122
|
|
|
136
123
|
metadata = {
|
|
137
|
-
"config_name":
|
|
124
|
+
"config_name": config.name,
|
|
138
125
|
"total_base_inputs": len(base_inputs),
|
|
139
|
-
"total_personas": len(
|
|
126
|
+
"total_personas": len(config.personas),
|
|
140
127
|
"strategies": [strategy.value for strategy in strategies],
|
|
141
128
|
"limit": settings.limit,
|
|
142
129
|
"generation_mode": InputGenerationMode.LLM.value,
|
|
143
|
-
"llm_provider":
|
|
144
|
-
"llm_model":
|
|
130
|
+
"llm_provider": config.input_generation.llm.provider,
|
|
131
|
+
"llm_model": config.input_generation.llm.model,
|
|
145
132
|
}
|
|
146
133
|
|
|
147
|
-
if recording_template:
|
|
148
|
-
for entry in entries:
|
|
149
|
-
entry.metadata["args_template"] = "use_recorded"
|
|
150
|
-
entry.metadata["template_kwargs"] = recording_template.get("full_kwargs")
|
|
151
|
-
metadata["recording_target"] = recording_template.get("target")
|
|
152
|
-
metadata["recording_base_input"] = recording_template.get("base_content")
|
|
153
|
-
|
|
154
134
|
return GenerationResult(entries=entries, metadata=metadata)
|
|
155
135
|
|
|
156
136
|
raise GenerationError(
|
|
@@ -13,11 +13,21 @@ def parse_variation_strategies(values: Iterable[str]) -> List[VariationStrategy]
|
|
|
13
13
|
"""Parse CLI-provided variation strategy names."""
|
|
14
14
|
|
|
15
15
|
strategies: List[VariationStrategy] = []
|
|
16
|
+
alias_map = {
|
|
17
|
+
"error_prone": (
|
|
18
|
+
VariationStrategy.ERROR_PRONE.value
|
|
19
|
+
if hasattr(VariationStrategy, "ERROR_PRONE")
|
|
20
|
+
else VariationStrategy.TYPO.value
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
for value in values:
|
|
17
25
|
normalized = value.strip().lower().replace("-", "_")
|
|
18
26
|
if not normalized:
|
|
19
27
|
continue
|
|
20
28
|
|
|
29
|
+
normalized = alias_map.get(normalized, normalized)
|
|
30
|
+
|
|
21
31
|
try:
|
|
22
32
|
strategies.append(VariationStrategy(normalized))
|
|
23
33
|
except ValueError as exc: # pragma: no cover - exercised via Typer
|
|
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
|