fluxloop-cli 0.3.3__tar.gz → 0.3.5__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 (70) hide show
  1. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/PKG-INFO +1 -1
  2. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/__init__.py +1 -1
  3. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/api_utils.py +32 -9
  4. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/__init__.py +4 -0
  5. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/auth.py +6 -13
  6. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/config.py +3 -8
  7. fluxloop_cli-0.3.5/fluxloop_cli/commands/data.py +657 -0
  8. fluxloop_cli-0.3.5/fluxloop_cli/commands/evaluate.py +188 -0
  9. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/inputs.py +17 -0
  10. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/personas.py +14 -4
  11. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/projects.py +8 -2
  12. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/sync.py +46 -13
  13. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/test.py +52 -0
  14. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/context_manager.py +3 -3
  15. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/conversation_supervisor.py +63 -0
  16. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/main.py +4 -0
  17. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/templates.py +1 -2
  18. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/turns.py +23 -0
  19. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/PKG-INFO +1 -1
  20. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/SOURCES.txt +2 -0
  21. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/pyproject.toml +1 -1
  22. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/README.md +0 -0
  23. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/arg_binder.py +0 -0
  24. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/auth_manager.py +0 -0
  25. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/apikeys.py +0 -0
  26. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/bundles.py +0 -0
  27. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/context.py +0 -0
  28. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/criteria.py +0 -0
  29. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/generate.py +0 -0
  30. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/init.py +0 -0
  31. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/local_context.py +0 -0
  32. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/run.py +0 -0
  33. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/scenarios.py +0 -0
  34. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/commands/status.py +0 -0
  35. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/common_options.py +0 -0
  36. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/config_loader.py +0 -0
  37. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/config_schema.py +0 -0
  38. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/constants.py +0 -0
  39. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/environment.py +0 -0
  40. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/http_client.py +0 -0
  41. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/input_generator.py +0 -0
  42. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/llm_generator.py +0 -0
  43. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/project_paths.py +0 -0
  44. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/runner.py +0 -0
  45. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/target_loader.py +0 -0
  46. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/testing/__init__.py +0 -0
  47. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/testing/pytest_plugin.py +0 -0
  48. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/testing/types.py +0 -0
  49. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/token_usage.py +0 -0
  50. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli/validators.py +0 -0
  51. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/dependency_links.txt +0 -0
  52. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/entry_points.txt +0 -0
  53. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/requires.txt +0 -0
  54. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/fluxloop_cli.egg-info/top_level.txt +0 -0
  55. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/setup.cfg +0 -0
  56. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_analysis_recommendations.py +0 -0
  57. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_arg_binder.py +0 -0
  58. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_config_command.py +0 -0
  59. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_conversation_supervisor.py +0 -0
  60. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_evaluate_command.py +0 -0
  61. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_evaluation_llm.py +0 -0
  62. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_init_pytest_template.py +0 -0
  63. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_input_generator.py +0 -0
  64. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_prompt_library.py +0 -0
  65. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_pytest_plugin.py +0 -0
  66. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_run_command.py +0 -0
  67. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_runner_multi_turn.py +0 -0
  68. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_success_criteria.py +0 -0
  69. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/tests/test_target_loader.py +0 -0
  70. {fluxloop_cli-0.3.3 → fluxloop_cli-0.3.5}/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.3.3
3
+ Version: 0.3.5
4
4
  Summary: FluxLoop CLI for running agent simulations
5
5
  Author-email: FluxLoop Team <team@fluxloop.dev>
6
6
  License: Apache-2.0
@@ -2,7 +2,7 @@
2
2
  FluxLoop CLI - Command-line interface for running agent simulations.
3
3
  """
4
4
 
5
- __version__ = "0.3.3"
5
+ __version__ = "0.3.5"
6
6
 
7
7
  from .main import app
8
8
 
@@ -20,18 +20,41 @@ from rich.console import Console
20
20
  console = Console()
21
21
 
22
22
 
23
- def resolve_api_url(override: Optional[str]) -> str:
23
+ PRODUCTION_API_URL = "https://api.fluxloop.ai"
24
+ STAGING_API_URL = "https://staging.api.fluxloop.ai"
25
+
26
+
27
+ def _read_project_json_api_url() -> Optional[str]:
28
+ """Read api_url from .fluxloop/project.json if it exists."""
29
+ try:
30
+ from .context_manager import load_project_connection
31
+
32
+ conn = load_project_connection()
33
+ if conn and conn.api_url:
34
+ return conn.api_url
35
+ except Exception:
36
+ pass
37
+ return None
38
+
39
+
40
+ def resolve_api_url(
41
+ override: Optional[str] = None,
42
+ *,
43
+ staging: bool = False,
44
+ ) -> str:
24
45
  """
25
- Resolve API URL from override or environment variables.
46
+ Resolve API URL with a single, unified priority chain.
26
47
 
27
48
  Priority:
28
- 1. Override parameter
29
- 2. FLUXLOOP_API_URL
30
- 3. FLUXLOOP_SYNC_URL
31
- 4. Default: https://api.fluxloop.ai
49
+ 1. ``override`` parameter (--api-url)
50
+ 2. FLUXLOOP_API_URL environment variable
51
+ 3. .fluxloop/project.json ``api_url``
52
+ 4. ``--staging`` flag → staging URL
53
+ 5. Hardcoded production URL (final fallback)
32
54
 
33
55
  Args:
34
- override: Optional URL override.
56
+ override: Optional URL override (--api-url).
57
+ staging: When True, use staging URL as fallback instead of production.
35
58
 
36
59
  Returns:
37
60
  Resolved API URL (trailing slash removed).
@@ -39,8 +62,8 @@ def resolve_api_url(override: Optional[str]) -> str:
39
62
  url = (
40
63
  override
41
64
  or os.getenv("FLUXLOOP_API_URL")
42
- or os.getenv("FLUXLOOP_SYNC_URL")
43
- or "https://api.fluxloop.ai"
65
+ or _read_project_json_api_url()
66
+ or (STAGING_API_URL if staging else PRODUCTION_API_URL)
44
67
  )
45
68
  return url.rstrip("/")
46
69
 
@@ -7,6 +7,8 @@ from . import (
7
7
  config,
8
8
  context,
9
9
  criteria,
10
+ data,
11
+ evaluate,
10
12
  generate,
11
13
  init,
12
14
  inputs,
@@ -27,6 +29,8 @@ __all__ = [
27
29
  "config",
28
30
  "context",
29
31
  "criteria",
32
+ "data",
33
+ "evaluate",
30
34
  "generate",
31
35
  "init",
32
36
  "inputs",
@@ -16,6 +16,7 @@ from rich.panel import Panel
16
16
  from rich.spinner import Spinner
17
17
  from rich.live import Live
18
18
 
19
+ from ..api_utils import resolve_api_url
19
20
  from ..auth_manager import (
20
21
  start_device_code_flow,
21
22
  poll_device_code,
@@ -35,17 +36,6 @@ app = typer.Typer(help="Manage FluxLoop authentication")
35
36
  console = Console()
36
37
 
37
38
 
38
- def _resolve_api_url(override: Optional[str]) -> str:
39
- """Resolve API URL from override or environment variables."""
40
- url = (
41
- override
42
- or os.getenv("FLUXLOOP_API_URL")
43
- or os.getenv("FLUXLOOP_SYNC_URL")
44
- or "https://api.fluxloop.ai"
45
- )
46
- return url.rstrip("/")
47
-
48
-
49
39
  def _is_agent_environment() -> bool:
50
40
  """Detect if running in an agent/headless environment."""
51
41
  # Check common agent environment indicators
@@ -63,6 +53,9 @@ def login(
63
53
  api_url: Optional[str] = typer.Option(
64
54
  None, "--api-url", help="FluxLoop API base URL"
65
55
  ),
56
+ staging: bool = typer.Option(
57
+ False, "--staging", help="Use staging API (staging.api.fluxloop.ai)"
58
+ ),
66
59
  force: bool = typer.Option(
67
60
  False, "--force", "-f", help="Force re-login even if already logged in"
68
61
  ),
@@ -87,7 +80,7 @@ def login(
87
80
  unless --force is specified. This makes the command idempotent and
88
81
  safe to call from automated scripts or AI agents.
89
82
  """
90
- api_url = _resolve_api_url(api_url)
83
+ api_url = resolve_api_url(api_url, staging=staging)
91
84
 
92
85
  # Check if already logged in (idempotent behavior)
93
86
  if not force:
@@ -290,7 +283,7 @@ def status():
290
283
  If token is expired or about to expire, automatically attempts to refresh.
291
284
  Only suggests re-login if refresh fails.
292
285
  """
293
- api_url = _resolve_api_url(None)
286
+ api_url = resolve_api_url()
294
287
  token = load_auth_token()
295
288
 
296
289
  if not token:
@@ -191,8 +191,7 @@ def env(
191
191
  loaded_paths = []
192
192
 
193
193
  env_vars = [
194
- ("FLUXLOOP_SYNC_URL", "Sync API base URL", "https://api.fluxloop.ai"),
195
- ("FLUXLOOP_API_KEY", "API key for authentication", None),
194
+ ("FLUXLOOP_API_URL", "API base URL override (optional, project.json is primary)", None),
196
195
  ("FLUXLOOP_SYNC_API_KEY", "Sync API key for uploads", None),
197
196
  ("FLUXLOOP_ENABLED", "Enable/disable tracing", "true"),
198
197
  ("FLUXLOOP_DEBUG", "Enable debug mode", "false"),
@@ -327,13 +326,12 @@ def set_llm(
327
326
  @app.command()
328
327
  def set_sync_key(
329
328
  api_key: str = typer.Argument(..., help="Sync API key"),
330
- api_url: Optional[str] = typer.Option(None, "--url", help="Sync API base URL"),
331
329
  overwrite_env: bool = typer.Option(False, "--overwrite-env", help="Overwrite existing key in .env"),
332
330
  env_file: Path = typer.Option(Path(".env"), "--env-file", help="Path to environment file"),
333
331
  project: Optional[str] = typer.Option(None, "--project", help="Project name under the FluxLoop root"),
334
332
  root: Path = typer.Option(Path(DEFAULT_ROOT_DIR_NAME), "--root", help="FluxLoop root directory"),
335
333
  ):
336
- """Save Sync API credentials to .env."""
334
+ """Save Sync API key to .env."""
337
335
 
338
336
  env_path = resolve_env_path(env_file, project, root)
339
337
  env_contents: Dict[str, str] = {}
@@ -351,12 +349,9 @@ def set_sync_key(
351
349
  else:
352
350
  env_contents["FLUXLOOP_SYNC_API_KEY"] = api_key
353
351
 
354
- if api_url:
355
- env_contents["FLUXLOOP_SYNC_URL"] = api_url
356
-
357
352
  env_lines = [f"{key}={value}" for key, value in env_contents.items()]
358
353
  env_path.write_text("\n".join(env_lines) + "\n")
359
- console.print(f"[green]✓[/green] Saved sync credentials to {env_path}")
354
+ console.print(f"[green]✓[/green] Saved sync API key to {env_path}")
360
355
 
361
356
 
362
357
  @app.command()