forgexa-cli 1.37.3__tar.gz → 1.37.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 (27) hide show
  1. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/PKG-INFO +1 -1
  2. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/daemon.py +36 -3
  4. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/PKG-INFO +1 -1
  5. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/pyproject.toml +1 -1
  6. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/README.md +0 -0
  7. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/_build_config.py +0 -0
  8. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/_local_bind.py +0 -0
  9. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/agent_core.py +0 -0
  10. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/autoupgrade.py +0 -0
  11. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/main.py +0 -0
  12. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli/py.typed +0 -0
  13. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  14. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  15. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/entry_points.txt +0 -0
  16. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/requires.txt +0 -0
  17. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/forgexa_cli.egg-info/top_level.txt +0 -0
  18. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/setup.cfg +0 -0
  19. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_auth_and_runtime_commands.py +0 -0
  20. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_autoupgrade.py +0 -0
  21. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_check_command.py +0 -0
  22. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_expiry_warnings_and_revoke.py +0 -0
  23. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_local_bind_commands.py +0 -0
  24. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_runtime_credentials.py +0 -0
  25. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_session_credentials.py +0 -0
  26. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_silent_install.py +0 -0
  27. {forgexa_cli-1.37.3 → forgexa_cli-1.37.5}/tests/test_upgrade_observability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.37.3
3
+ Version: 1.37.5
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.37.3"
2
+ __version__ = "1.37.5"
@@ -910,7 +910,7 @@ except (ImportError, ModuleNotFoundError):
910
910
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
911
911
  # Kept in sync with pyproject.toml version via bump-version.sh.
912
912
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
913
- DAEMON_VERSION = "1.37.3"
913
+ DAEMON_VERSION = "1.37.5"
914
914
 
915
915
 
916
916
  def _detect_client_type() -> str:
@@ -1245,6 +1245,8 @@ class TaskResult:
1245
1245
  observations: list[dict] = field(default_factory=list)
1246
1246
  metrics: dict = field(default_factory=dict)
1247
1247
  git: dict = field(default_factory=dict)
1248
+ # Set from the complete agent stream before stdout is retained as a bounded tail.
1249
+ has_verified_completion: bool = False
1248
1250
 
1249
1251
 
1250
1252
  def _filter_local_bind_task_result(result: "TaskResult") -> None:
@@ -4742,6 +4744,21 @@ class ProcessManager:
4742
4744
  or signals["has_meaningful_content"]
4743
4745
  )
4744
4746
 
4747
+ @staticmethod
4748
+ def has_verified_agent_completion(result: "TaskResult") -> bool:
4749
+ """Return True when structured output proves the agent completed a real turn."""
4750
+ if result.has_verified_completion:
4751
+ return True
4752
+ combined = "\n".join(part for part in (result.stdout, result.stderr) if part)
4753
+ signals = ProcessManager._extract_output_signals(combined)
4754
+ return bool(
4755
+ signals["has_assistant_events"]
4756
+ and signals["has_meaningful_content"]
4757
+ and (signals["has_result"] or signals["has_turn_completed"])
4758
+ and not signals["has_turn_failed"]
4759
+ and not signals["error_messages"]
4760
+ )
4761
+
4745
4762
  @staticmethod
4746
4763
  def _copilot_completed_without_result(stdout: str) -> bool:
4747
4764
  """Implementation lives in agent_core._copilot_completed_without_result."""
@@ -5914,6 +5931,13 @@ class ProcessManager:
5914
5931
  and not signals["has_turn_failed"]
5915
5932
  and not signals["error_messages"]
5916
5933
  )
5934
+ has_verified_completion = bool(
5935
+ signals["has_assistant_events"]
5936
+ and signals["has_meaningful_content"]
5937
+ and (signals["has_result"] or signals["has_turn_completed"])
5938
+ and not signals["has_turn_failed"]
5939
+ and not signals["error_messages"]
5940
+ )
5917
5941
  structured_errors = [
5918
5942
  str(msg).strip()
5919
5943
  for msg in (signals.get("error_messages") or [])
@@ -5935,6 +5959,7 @@ class ProcessManager:
5935
5959
  stdout=stdout[-settings.AGENT_MAX_OUTPUT_SIZE:],
5936
5960
  stderr=stderr[-10000:],
5937
5961
  metrics=metrics,
5962
+ has_verified_completion=has_verified_completion,
5938
5963
  )
5939
5964
  elif not copilot_specific_error and copilot_exit is None and completed_without_result:
5940
5965
  if returncode != 0:
@@ -5951,6 +5976,7 @@ class ProcessManager:
5951
5976
  stdout=stdout[-settings.AGENT_MAX_OUTPUT_SIZE:],
5952
5977
  stderr=stderr[-10000:],
5953
5978
  metrics=metrics,
5979
+ has_verified_completion=has_verified_completion,
5954
5980
  )
5955
5981
  else:
5956
5982
  # --- Immediate-failure retry ladder ---
@@ -6473,6 +6499,7 @@ class ProgressReporter:
6473
6499
  "exit_code": result.exit_code,
6474
6500
  "stdout_tail": result.stdout[-20000:] if result.stdout else "",
6475
6501
  "stderr_tail": result.stderr[-5000:] if result.stderr else "",
6502
+ "verified_completion": result.has_verified_completion,
6476
6503
  "error": result.error,
6477
6504
  "failure_code": result.failure_code,
6478
6505
  "preflight": result.preflight,
@@ -9077,10 +9104,16 @@ class RuntimeDaemon:
9077
9104
  int(result.metrics.get("token_input", 0) or 0)
9078
9105
  + int(result.metrics.get("token_output", 0) or 0)
9079
9106
  ) > 0
9080
- if not has_uncommitted and not has_committed and not has_tokens:
9107
+ has_verified_completion = self.process_manager.has_verified_agent_completion(result)
9108
+ if (
9109
+ not has_uncommitted
9110
+ and not has_committed
9111
+ and not has_tokens
9112
+ and not has_verified_completion
9113
+ ):
9081
9114
  logger.warning(
9082
9115
  "Task %s (%s) agent reported success but produced no file changes "
9083
- "and no token usage — marking as failed",
9116
+ "or verified completion evidence — marking as failed",
9084
9117
  task.task_id, task.node_type,
9085
9118
  )
9086
9119
  result.status = "failed"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.37.3
3
+ Version: 1.37.5
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.37.3"
3
+ version = "1.37.5"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
File without changes
File without changes