fruxon 0.8.0__tar.gz → 0.8.2__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 (72) hide show
  1. {fruxon-0.8.0 → fruxon-0.8.2}/PKG-INFO +1 -1
  2. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/_version.py +2 -2
  3. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/examples.py +2 -0
  4. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/run.py +18 -3
  5. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-meet/SKILL.md +1 -1
  6. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_cli.py +31 -0
  7. {fruxon-0.8.0 → fruxon-0.8.2}/.gitignore +0 -0
  8. {fruxon-0.8.0 → fruxon-0.8.2}/HISTORY.md +0 -0
  9. {fruxon-0.8.0 → fruxon-0.8.2}/LICENSE +0 -0
  10. {fruxon-0.8.0 → fruxon-0.8.2}/README.md +0 -0
  11. {fruxon-0.8.0 → fruxon-0.8.2}/pyproject.toml +0 -0
  12. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/__init__.py +0 -0
  13. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/__main__.py +0 -0
  14. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/_ssl.py +0 -0
  15. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/__init__.py +0 -0
  16. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/_schema.py +0 -0
  17. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/_shared.py +0 -0
  18. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/agents.py +0 -0
  19. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/agents_budget.py +0 -0
  20. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/agents_draft.py +0 -0
  21. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/agents_revisions.py +0 -0
  22. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/agents_tests.py +0 -0
  23. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/auth.py +0 -0
  24. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/chat.py +0 -0
  25. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/completion.py +0 -0
  26. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/config.py +0 -0
  27. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/describe.py +0 -0
  28. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/doctor.py +0 -0
  29. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/guides.py +0 -0
  30. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/integrations.py +0 -0
  31. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/keys.py +0 -0
  32. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/llm_providers.py +0 -0
  33. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/skills.py +0 -0
  34. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/tools.py +0 -0
  35. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli/trace.py +0 -0
  36. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/cli_auth.py +0 -0
  37. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/credentials.py +0 -0
  38. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/doctor.py +0 -0
  39. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/exceptions.py +0 -0
  40. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/fruxon.py +0 -0
  41. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/models.py +0 -0
  42. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/output.py +0 -0
  43. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/params.py +0 -0
  44. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/__init__.py +0 -0
  45. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-agent-mode/SKILL.md +0 -0
  46. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-build-agent/SKILL.md +0 -0
  47. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-create-integration/SKILL.md +0 -0
  48. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-debug-revision/SKILL.md +0 -0
  49. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/skills/fruxon-use-integrations/SKILL.md +0 -0
  50. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/ui.py +0 -0
  51. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/update_check.py +0 -0
  52. {fruxon-0.8.0 → fruxon-0.8.2}/src/fruxon/validation.py +0 -0
  53. {fruxon-0.8.0 → fruxon-0.8.2}/tests/__init__.py +0 -0
  54. {fruxon-0.8.0 → fruxon-0.8.2}/tests/conftest.py +0 -0
  55. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_actor.py +0 -0
  56. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_budgets.py +0 -0
  57. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_client.py +0 -0
  58. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_credentials.py +0 -0
  59. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_doctor.py +0 -0
  60. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_draft_evaluate_cli.py +0 -0
  61. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_drafts.py +0 -0
  62. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_fruxon.py +0 -0
  63. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_guides.py +0 -0
  64. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_output.py +0 -0
  65. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_params.py +0 -0
  66. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_schema.py +0 -0
  67. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_skills.py +0 -0
  68. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_ssl.py +0 -0
  69. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_test_chats.py +0 -0
  70. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_ui.py +0 -0
  71. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_update_check.py +0 -0
  72. {fruxon-0.8.0 → fruxon-0.8.2}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fruxon
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: The Fruxon SDK is a lightweight Python client for integrating with the Fruxon platform.
5
5
  Project-URL: bugs, https://github.com/fruxon-ai/fruxon-sdk/issues
6
6
  Project-URL: changelog, https://github.com/fruxon-ai/fruxon-sdk/blob/main/HISTORY.md
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.8.0'
22
- __version_tuple__ = version_tuple = (0, 8, 0)
21
+ __version__ = version = '0.8.2'
22
+ __version_tuple__ = version_tuple = (0, 8, 2)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -52,6 +52,8 @@ _EXAMPLES: dict[str, list[tuple[str, str]]] = {
52
52
  ("fruxon agents list", "Browse what's deployed"),
53
53
  ("fruxon agents get my-agent", "Show one agent's manifest"),
54
54
  ("fruxon agents schema my-agent", "Param shape — feed to an LLM before `run`"),
55
+ ("fruxon agents draft pull my-agent", "Fetch the working copy locally"),
56
+ ("fruxon agents draft run my-agent -p user_query='hi'", "Run the draft (Origin=TEST, no prod spend)"),
55
57
  ("fruxon agents revisions my-agent", "List revisions for an agent"),
56
58
  ("fruxon agents tests my-agent", "List eval/test runs"),
57
59
  ("fruxon agents budget get my-agent", "Show per-origin cost cap"),
@@ -695,6 +695,13 @@ def _run_stream_ndjson(
695
695
  continue
696
696
 
697
697
  trace = event.data.get("trace") if isinstance(event.data.get("trace"), dict) else {}
698
+ # ``-1`` is the backend's sentinel for "no published
699
+ # revision" / "draft head" / similar non-applicable
700
+ # states. For ``agent_revision`` we drop the field
701
+ # entirely in that case rather than emit a misleading
702
+ # ``-1`` an LLM driver would have to special-case on
703
+ # its own side. Other numeric fields (duration, costs)
704
+ # pass through verbatim since their zero is meaningful.
698
705
  for src_key, dst_key, cast in (
699
706
  ("duration", "duration_ms", int),
700
707
  ("totalCost", "total_cost", float),
@@ -703,8 +710,11 @@ def _run_stream_ndjson(
703
710
  ("agentRevision", "agent_revision", int),
704
711
  ):
705
712
  val = trace.get(src_key) if isinstance(trace, dict) else None
706
- if isinstance(val, (int, float)):
707
- done[dst_key] = cast(val)
713
+ if not isinstance(val, (int, float)):
714
+ continue
715
+ if src_key == "agentRevision" and val <= 0:
716
+ continue
717
+ done[dst_key] = cast(val)
708
718
  _emit_ndjson(done)
709
719
  continue
710
720
 
@@ -1292,7 +1302,12 @@ def _render_done(data: dict[str, object], *, agent: str | None = None) -> None:
1292
1302
  parts.append(format_duration(duration))
1293
1303
  if isinstance(total_cost, (int, float)) and total_cost:
1294
1304
  parts.append(f"${float(total_cost):.4f}")
1295
- if isinstance(agent_revision, (int, float)) and agent_revision:
1305
+ # Only surface a real revision number. The backend sends ``-1`` as
1306
+ # a sentinel for "no published revision yet" / "draft head" /
1307
+ # similar non-applicable states — printing it verbatim ("rev -1")
1308
+ # is worse than dropping the field entirely, because it looks like
1309
+ # a real but bizarre revision id.
1310
+ if isinstance(agent_revision, (int, float)) and agent_revision > 0:
1296
1311
  parts.append(f"rev [bold]{int(agent_revision)}[/bold]")
1297
1312
  if isinstance(record_id, str) and record_id:
1298
1313
  parts.append(f"record [cyan]{record_id}[/cyan]")
@@ -31,7 +31,7 @@ fruxon agents list / get / create / test
31
31
  fruxon agents schema <agent> # typed parameter metadata
32
32
  fruxon agents validate <agent> -p k=v # pre-flight a payload (no execution)
33
33
  fruxon agents revisions create [--deploy] / deploy
34
- fruxon agents draft pull / push / status / evaluate / discard
34
+ fruxon agents draft pull / push / status / run / evaluate / undo / redo / reset / discard
35
35
  fruxon run <id> -p key=value # execute deployed revision
36
36
  fruxon integrations list / create
37
37
  fruxon tools list <integration> / create
@@ -3471,6 +3471,37 @@ class TestRunAgentModeNdjson:
3471
3471
  # two ``done`` flavors.
3472
3472
  assert "status" not in done
3473
3473
 
3474
+ def test_stream_drops_sentinel_agent_revision(self, runner, monkeypatch):
3475
+ """The backend sends ``agentRevision: -1`` as a sentinel for
3476
+ "no published revision yet" / "draft head" / similar non-
3477
+ applicable states. Drop the field entirely in that case
3478
+ rather than emit a misleading ``-1`` an LLM driver would have
3479
+ to special-case on its own side."""
3480
+ credentials.save(credentials.StoredCredentials(api_key="fxn_x", org="acme"))
3481
+ monkeypatch.setenv("FRUXON_AGENT_MODE", "1")
3482
+
3483
+ from fruxon.fruxon import StreamEvent
3484
+
3485
+ self._stub_stream(
3486
+ monkeypatch,
3487
+ [
3488
+ StreamEvent(
3489
+ event="done",
3490
+ data={
3491
+ "executionRecordId": "rec-x",
3492
+ "trace": {"duration": 1234, "totalCost": 0.005, "agentRevision": -1},
3493
+ },
3494
+ ),
3495
+ ],
3496
+ )
3497
+ result = runner.invoke(app, ["run", "my-agent"])
3498
+ assert result.exit_code == 0, result.stderr
3499
+ done = self._parse_lines(result.stdout)[-1]
3500
+ # Other fields still surface; only ``agent_revision`` is suppressed.
3501
+ assert done["duration_ms"] == 1234
3502
+ assert done["total_cost"] == pytest.approx(0.005)
3503
+ assert "agent_revision" not in done
3504
+
3474
3505
 
3475
3506
  # ─────────────────────────────────────────────────────────────────────────────
3476
3507
  # Non-interactive enforcement — paths that would block on human input
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes