fluxloop-cli 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.

Potentially problematic release.


This version of fluxloop-cli might be problematic. Click here for more details.

@@ -0,0 +1,95 @@
1
+ """Utilities for dynamically loading experiment targets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import Callable, Optional
9
+
10
+ from fluxloop.schemas import RunnerConfig
11
+
12
+
13
+ class TargetLoader:
14
+ """Load callables defined by an experiment runner configuration."""
15
+
16
+ def __init__(self, config: RunnerConfig, source_dir: Optional[Path] = None) -> None:
17
+ self.config = config
18
+ self.source_dir = source_dir
19
+
20
+ def load(self) -> Callable:
21
+ """Return a callable based on the configured target."""
22
+
23
+ work_dir = self._resolve_working_directory()
24
+ remove_path = False
25
+
26
+ if work_dir and work_dir not in sys.path:
27
+ sys.path.insert(0, work_dir)
28
+ remove_path = True
29
+
30
+ try:
31
+ if self.config.target:
32
+ return self._load_from_target(self.config.target)
33
+
34
+ module = importlib.import_module(self.config.module_path)
35
+ return getattr(module, self.config.function_name)
36
+ finally:
37
+ if remove_path:
38
+ sys.path.remove(work_dir)
39
+
40
+ def _resolve_working_directory(self) -> str | None:
41
+ if not self.config.working_directory:
42
+ return None
43
+
44
+ raw_path = Path(self.config.working_directory)
45
+ if not raw_path.is_absolute() and self.source_dir:
46
+ raw_path = (self.source_dir / raw_path).resolve()
47
+ else:
48
+ raw_path = raw_path.expanduser().resolve()
49
+
50
+ path = raw_path
51
+ return str(path)
52
+
53
+ def _load_from_target(self, target: str) -> Callable:
54
+ if ":" not in target:
55
+ raise ValueError(
56
+ "Invalid runner.target format. Expected 'module:function' or 'module:Class.method'."
57
+ )
58
+
59
+ module_name, attribute_part = target.split(":", 1)
60
+
61
+ try:
62
+ module = importlib.import_module(module_name)
63
+ except ImportError as exc:
64
+ raise ValueError(f"Failed to import module '{module_name}' for target '{target}': {exc}")
65
+
66
+ if "." in attribute_part:
67
+ class_name, method_name = attribute_part.split(".", 1)
68
+ try:
69
+ cls = getattr(module, class_name)
70
+ except AttributeError as exc:
71
+ raise ValueError(
72
+ f"Class '{class_name}' not found in module '{module_name}' for target '{target}'."
73
+ ) from exc
74
+
75
+ try:
76
+ instance = cls()
77
+ except TypeError as exc:
78
+ raise ValueError(
79
+ "MVP limitation: only classes with zero-argument constructors are supported."
80
+ ) from exc
81
+
82
+ try:
83
+ return getattr(instance, method_name)
84
+ except AttributeError as exc:
85
+ raise ValueError(
86
+ f"Method '{method_name}' not found on class '{class_name}' for target '{target}'."
87
+ ) from exc
88
+
89
+ try:
90
+ return getattr(module, attribute_part)
91
+ except AttributeError as exc:
92
+ raise ValueError(
93
+ f"Function or attribute '{attribute_part}' not found in module '{module_name}' for target '{target}'."
94
+ ) from exc
95
+
@@ -0,0 +1,277 @@
1
+ """
2
+ Templates for generating configuration and code files.
3
+ """
4
+
5
+
6
+ def create_experiment_config(project_name: str) -> str:
7
+ """Create a default experiment configuration."""
8
+ return f"""# FluxLoop Experiment Configuration
9
+ name: {project_name}_experiment
10
+ description: AI agent simulation experiment
11
+ version: 1.0.0
12
+
13
+ # Simulation settings
14
+ iterations: 10
15
+ parallel_runs: 1
16
+ seed: 42
17
+ run_delay_seconds: 0
18
+
19
+ # User personas for simulation
20
+ personas:
21
+ - name: novice_user
22
+ description: A user new to the system
23
+ characteristics:
24
+ - Asks basic questions
25
+ - May use incorrect terminology
26
+ - Needs detailed explanations
27
+ language: en
28
+ expertise_level: novice
29
+ goals:
30
+ - Understand how the system works
31
+ - Complete simple tasks
32
+
33
+ - name: expert_user
34
+ description: An experienced power user
35
+ characteristics:
36
+ - Uses technical terminology
37
+ - Asks complex questions
38
+ - Expects efficient responses
39
+ language: en
40
+ expertise_level: expert
41
+ goals:
42
+ - Optimize workflows
43
+ - Access advanced features
44
+
45
+ # Base inputs for reference (generate inputs from these)
46
+ base_inputs:
47
+ - input: "How do I get started?"
48
+ expected_intent: help
49
+ - input: "What can you do?"
50
+ expected_intent: capabilities
51
+ - input: "Show me an example"
52
+ expected_intent: demo
53
+
54
+ # Agent runner configuration
55
+ runner:
56
+ target: "examples.simple_agent:run" # module:function or module:Class.method
57
+ working_directory: . # IMPORTANT: Set this to your project's root directory
58
+ timeout_seconds: 30
59
+ max_retries: 3
60
+
61
+ # Recorded argument replay (optional)
62
+ replay_args:
63
+ enabled: false
64
+ recording_file: recordings/args_recording.jsonl
65
+ callable_providers:
66
+ send_message_callback: "builtin:collector.send"
67
+ send_error_callback: "builtin:collector.error"
68
+ override_param_path: data.content
69
+
70
+ # Input generation configuration
71
+ input_generation:
72
+ mode: llm
73
+ llm:
74
+ enabled: true
75
+ provider: openai
76
+ model: gpt-5
77
+ strategies:
78
+ - type: rephrase
79
+ - type: verbose
80
+ - type: error_prone
81
+ variation_count: 2
82
+
83
+ # Evaluation methods
84
+ evaluators:
85
+ - name: success_checker
86
+ type: rule_based
87
+ enabled: true
88
+ rules:
89
+ - check: output_not_empty
90
+ weight: 1.0
91
+
92
+ - name: response_quality
93
+ type: llm_judge
94
+ enabled: false
95
+ model: gpt-5
96
+ prompt_template: |
97
+ Rate the quality of this response on a scale of 1-10:
98
+ Input: {{input}}
99
+ Output: {{output}}
100
+
101
+ Consider: relevance, completeness, clarity
102
+ Score:
103
+
104
+ # Output configuration
105
+ output_directory: experiments
106
+ save_traces: true
107
+ save_aggregated_metrics: true
108
+
109
+ # Inputs must be generated before running experiments
110
+ inputs_file: inputs/generated.yaml
111
+
112
+ # Collector settings (optional)
113
+ # collector_url: http://localhost:8000
114
+ # collector_api_key: your-api-key
115
+
116
+ # Tags and metadata
117
+ tags:
118
+ - simulation
119
+ - testing
120
+ metadata:
121
+ team: development
122
+ environment: local
123
+ """
124
+
125
+
126
+ def create_sample_agent() -> str:
127
+ """Create a sample agent implementation."""
128
+ return '''"""
129
+ Sample agent implementation for FluxLoop testing.
130
+ """
131
+
132
+ import random
133
+ import time
134
+ from typing import Any, Dict
135
+
136
+ import fluxloop
137
+
138
+
139
+ @fluxloop.agent(name="SimpleAgent")
140
+ def run(input_text: str) -> str:
141
+ """
142
+ Main agent entry point.
143
+
144
+ Args:
145
+ input_text: Input from the user
146
+
147
+ Returns:
148
+ Agent response
149
+ """
150
+ # Process the input
151
+ processed = process_input(input_text)
152
+
153
+ # Generate response
154
+ response = generate_response(processed)
155
+
156
+ # Simulate some work
157
+ time.sleep(random.uniform(0.1, 0.5))
158
+
159
+ return response
160
+
161
+
162
+ @fluxloop.prompt(model="simple-model")
163
+ def generate_response(processed_input: Dict[str, Any]) -> str:
164
+ """
165
+ Generate a response based on processed input.
166
+ """
167
+ intent = processed_input.get("intent", "unknown")
168
+
169
+ responses = {
170
+ "greeting": "Hello! How can I help you today?",
171
+ "help": "I can assist you with various tasks. What would you like to know?",
172
+ "capabilities": "I can answer questions, provide information, and help with tasks.",
173
+ "demo": "Here's an example: You can ask me about any topic and I'll try to help.",
174
+ "unknown": "I'm not sure I understand. Could you please rephrase?",
175
+ }
176
+
177
+ return responses.get(intent, responses["unknown"])
178
+
179
+
180
+ @fluxloop.tool(description="Process and analyze input text")
181
+ def process_input(text: str) -> Dict[str, Any]:
182
+ """
183
+ Process the input text to extract intent and entities.
184
+ """
185
+ # Simple intent detection
186
+ text_lower = text.lower()
187
+
188
+ intent = "unknown"
189
+ if any(word in text_lower for word in ["hello", "hi", "hey"]):
190
+ intent = "greeting"
191
+ elif any(word in text_lower for word in ["help", "start", "begin"]):
192
+ intent = "help"
193
+ elif any(word in text_lower for word in ["can you", "what can", "capabilities"]):
194
+ intent = "capabilities"
195
+ elif "example" in text_lower or "demo" in text_lower:
196
+ intent = "demo"
197
+
198
+ return {
199
+ "original": text,
200
+ "intent": intent,
201
+ "word_count": len(text.split()),
202
+ "has_question": "?" in text,
203
+ }
204
+
205
+
206
+ if __name__ == "__main__":
207
+ # Test the agent locally
208
+ with fluxloop.instrument("test_run"):
209
+ result = run("Hello, what can you help me with?")
210
+ print(f"Result: {result}")
211
+ '''
212
+
213
+
214
+ def create_gitignore() -> str:
215
+ """Create a .gitignore file."""
216
+ return """# Python
217
+ __pycache__/
218
+ *.py[cod]
219
+ *$py.class
220
+ *.so
221
+ .Python
222
+ venv/
223
+ env/
224
+ ENV/
225
+ .venv/
226
+
227
+ # FluxLoop
228
+ traces/
229
+ *.trace
230
+ *.log
231
+
232
+ # Environment
233
+ .env
234
+ .env.local
235
+ *.env
236
+
237
+ # IDE
238
+ .vscode/
239
+ .idea/
240
+ *.swp
241
+ *.swo
242
+
243
+ # OS
244
+ .DS_Store
245
+ Thumbs.db
246
+
247
+ # Testing
248
+ .pytest_cache/
249
+ .coverage
250
+ htmlcov/
251
+ *.coverage
252
+ """
253
+
254
+
255
+ def create_env_file() -> str:
256
+ """Create a .env template file."""
257
+ return """# FluxLoop Configuration
258
+ FLUXLOOP_COLLECTOR_URL=http://localhost:8000
259
+ FLUXLOOP_API_KEY=your-api-key-here
260
+ FLUXLOOP_ENABLED=true
261
+ FLUXLOOP_DEBUG=false
262
+ FLUXLOOP_SAMPLE_RATE=1.0
263
+ # Argument Recording (global toggle)
264
+ FLUXLOOP_RECORD_ARGS=false
265
+ FLUXLOOP_RECORDING_FILE=recordings/args_recording.jsonl
266
+
267
+ # Service Configuration
268
+ FLUXLOOP_SERVICE_NAME=my-agent
269
+ FLUXLOOP_ENVIRONMENT=development
270
+
271
+ # LLM API Keys (if needed)
272
+ # OPENAI_API_KEY=sk-...
273
+ # ANTHROPIC_API_KEY=sk-ant-...
274
+
275
+ # Other Configuration
276
+ # Add your custom environment variables here
277
+ """
@@ -0,0 +1,31 @@
1
+ """Helper validators for CLI inputs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable, List
6
+
7
+ import typer
8
+
9
+ from fluxloop.schemas import VariationStrategy
10
+
11
+
12
+ def parse_variation_strategies(values: Iterable[str]) -> List[VariationStrategy]:
13
+ """Parse CLI-provided variation strategy names."""
14
+
15
+ strategies: List[VariationStrategy] = []
16
+ for value in values:
17
+ normalized = value.strip().lower().replace("-", "_")
18
+ if not normalized:
19
+ continue
20
+
21
+ try:
22
+ strategies.append(VariationStrategy(normalized))
23
+ except ValueError as exc: # pragma: no cover - exercised via Typer
24
+ allowed = ", ".join(strategy.value for strategy in VariationStrategy)
25
+ raise typer.BadParameter(
26
+ f"Unknown strategy '{value}'. Allowed values: {allowed}"
27
+ ) from exc
28
+
29
+ return strategies
30
+
31
+
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: fluxloop-cli
3
+ Version: 0.1.0
4
+ Summary: FluxLoop CLI for running agent simulations
5
+ Author-email: FluxLoop Team <team@fluxloop.dev>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/fluxloop/fluxloop
8
+ Project-URL: Documentation, https://docs.fluxloop.dev
9
+ Project-URL: Repository, https://github.com/fluxloop/fluxloop
10
+ Project-URL: Issues, https://github.com/fluxloop/fluxloop/issues
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: typer[all]>=0.9.0
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: pyyaml>=6.0
25
+ Requires-Dist: httpx>=0.24.0
26
+ Requires-Dist: rich>=13.0
27
+ Requires-Dist: python-dotenv>=1.0.0
28
+ Requires-Dist: fluxloop>=0.1.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+ Requires-Dist: mypy>=1.0; extra == "dev"
35
+ Requires-Dist: black>=23.0; extra == "dev"
36
+ Provides-Extra: openai
37
+ Requires-Dist: openai>=1.0.0; extra == "openai"
38
+ Provides-Extra: anthropic
39
+ Requires-Dist: anthropic>=0.7.0; extra == "anthropic"
40
+
41
+ # FluxLoop CLI
42
+
43
+ Command-line interface for running agent simulations and managing FluxLoop workflows.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install fluxloop-cli
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ```bash
54
+ # Initialize a new FluxLoop project
55
+ fluxloop init
56
+
57
+ # Run agent simulations
58
+ fluxloop run
59
+
60
+ # Generate test inputs
61
+ fluxloop generate
62
+
63
+ # Check status
64
+ fluxloop status
65
+ ```
66
+
67
+ ## Features
68
+
69
+ - 🚀 **Easy Setup**: Initialize projects with a single command
70
+ - 🔄 **Simulation Runner**: Execute agent tests with various input scenarios
71
+ - 📝 **Input Generation**: LLM-powered test input generation
72
+ - 📊 **Rich Output**: Beautiful terminal UI with detailed progress tracking
73
+
74
+ ## Requirements
75
+
76
+ - Python 3.8 or higher
77
+ - FluxLoop SDK
78
+
79
+ ## Documentation
80
+
81
+ For detailed documentation, visit [https://docs.fluxloop.dev](https://docs.fluxloop.dev)
82
+
83
+ ## License
84
+
85
+ Apache License 2.0 - see LICENSE file for details
86
+
@@ -0,0 +1,24 @@
1
+ fluxloop_cli/__init__.py,sha256=RJ2NWEwNPNHoj71atQXloxrF-E180A934a-Em1W3aAY,142
2
+ fluxloop_cli/arg_binder.py,sha256=oluHrwe1nNVq7alxBhBEoZrLrYop-cRgXgSu59LJcw4,7827
3
+ fluxloop_cli/config_loader.py,sha256=IM5YF4qsaOquvyHNr27ryEsioE_3f6A2ikayWu8QXtU,4888
4
+ fluxloop_cli/constants.py,sha256=SrIaAjdGljrgER_NvSbzFgfL3SeYco4KPAoLXawtDBw,249
5
+ fluxloop_cli/input_generator.py,sha256=H7gy1zw8kFDei_tLjuWHESafkEU_wGjHHb34bhJjCmk,5031
6
+ fluxloop_cli/llm_generator.py,sha256=SosP5DeZuhBLEM6bj7BDp-7mckvVhtNJMEk2ZgV143M,12894
7
+ fluxloop_cli/main.py,sha256=c0YvWyrS8OIB4ZhuDUiFnGvutXwtQM_6Q-6tiakiFgg,2492
8
+ fluxloop_cli/project_paths.py,sha256=EDDUccltK02-k0dGluX0sc1D1VM10fZTltmiFuwGKSg,2475
9
+ fluxloop_cli/runner.py,sha256=Aqd5Gkqn3XqzteAOU4C7-5k3wjoiBVMNBln1fGGNI1o,22545
10
+ fluxloop_cli/target_loader.py,sha256=F8fTxf-Jfu8rxK7-3Y_uPPxa6GBkCbQpXPaorQNqF6g,3220
11
+ fluxloop_cli/templates.py,sha256=VTpuZ4pcKggmKvMDheRUCE4X9JpvLWSbCxr2Sf83aqk,6299
12
+ fluxloop_cli/validators.py,sha256=8cOCLSqvkQDSHRuty9-s5WJ70uvHGT_BEcXtxdlnX78,884
13
+ fluxloop_cli/commands/__init__.py,sha256=zaXs9_IpI0Zo9CmDVRAw1QiofNzRWPcmHTnuN6V7NRA,146
14
+ fluxloop_cli/commands/config.py,sha256=jfIY5FO3rqks3WrohpZWbsPsvHiOSY_ZifuYqhu56g8,11229
15
+ fluxloop_cli/commands/generate.py,sha256=lOOF-lsTyrLB5_dw20vNY-R6Uf6tIgnXrj5NUX8RdnE,9748
16
+ fluxloop_cli/commands/init.py,sha256=kEtdZM49ujj9PlLpoEILbEQgkPutE5dhVBuxk5WCHtE,7028
17
+ fluxloop_cli/commands/parse.py,sha256=AVPYi59ejFWx4TYyM7JuI69koxDVkIBxy4LBRDMMbFM,9220
18
+ fluxloop_cli/commands/run.py,sha256=ZuH0VFHQYnal487FsGLe3N6rDIsNHvLo6aNWBP7Knoo,9585
19
+ fluxloop_cli/commands/status.py,sha256=yVRgruKJGn4V5KDE7RDEoxna3pa0LLRSI0j5pxdmKMY,6688
20
+ fluxloop_cli-0.1.0.dist-info/METADATA,sha256=Oz5S0eAM5WmwrKbui5DetEr7L-Vr7zd7jNRj9Glcn3A,2461
21
+ fluxloop_cli-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
+ fluxloop_cli-0.1.0.dist-info/entry_points.txt,sha256=NxOEMku4yLMY5kp_Qcd3JcevfXP6A98FsSf9xHcwkyE,51
23
+ fluxloop_cli-0.1.0.dist-info/top_level.txt,sha256=ahLkaxzwhmVU4z-YhkmQVzAbW3-wez9cKnwPiDK7uKM,13
24
+ fluxloop_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fluxloop = fluxloop_cli.main:app
@@ -0,0 +1 @@
1
+ fluxloop_cli