qaas-python 0.2.0__py3-none-any.whl → 0.2.2__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.
qaas/cli.py CHANGED
@@ -449,16 +449,14 @@ def doctor(
449
449
 
450
450
 
451
451
  def _agent_usable(spec, caps: dict[str, bool]) -> bool:
452
- """Whether an agent can do useful work with the capabilities available.
452
+ """Delegates to `target.agent_usable`, which the conductor also uses.
453
453
 
454
- SURFACE without a browser-reachable UI has nothing to do; the rest can all
455
- contribute from static analysis alone, at lower confidence.
454
+ Two copies of this rule meant `qaas doctor` could report an agent unusable
455
+ while a run dispatched it anyway.
456
456
  """
457
- if spec.name == "SURFACE":
458
- return caps["live_ui"]
459
- if spec.name == "PROOF":
460
- return caps["live_api"] or caps["static_analysis"]
461
- return True
457
+ from qaas.target import agent_usable
458
+
459
+ return agent_usable(spec.name, caps)
462
460
 
463
461
 
464
462
  @app.command()
qaas/conductor.py CHANGED
@@ -25,6 +25,7 @@ from typing import Any, Callable
25
25
 
26
26
  from qaas.config import AgentSpec, SystemConfig, load_config
27
27
  from qaas.envelope import DefectEnvelope
28
+ from qaas.target import agent_usable
28
29
  from qaas.mcp.context import ToolContext
29
30
  from qaas.runner import RunOutcome, run_agent
30
31
  from qaas.store import RunStore, SystemMapStore
@@ -269,6 +270,27 @@ class Conductor:
269
270
  async def _phase_discover(self, specs, store, budget, report, mode, map_version) -> None:
270
271
  """Discovery agents are independent. Run them concurrently, bounded."""
271
272
  discovery = [s for name, s in specs.items() if s.layer == "discovery"]
273
+
274
+ # Skip agents this target cannot support. `qaas doctor` has always
275
+ # reported these ("agents that cannot: SURFACE"), but nothing acted on
276
+ # it, so a run against a target with no reachable UI would still
277
+ # dispatch SURFACE and spend its entire budget hunting a browser that
278
+ # was never there. Being told an agent cannot work and then watching it
279
+ # run is worse than not being told.
280
+ profile = getattr(self.config, "profile", None)
281
+ if profile is not None:
282
+ caps = profile.capabilities()
283
+ unusable = [s for s in discovery if not agent_usable(s.name, caps)]
284
+ if unusable:
285
+ discovery = [s for s in discovery if s not in unusable]
286
+ store.log(
287
+ "skipped",
288
+ reason="target cannot support these agents",
289
+ agents=[s.name for s in unusable],
290
+ )
291
+ for spec in unusable:
292
+ self._emit("skipped", agent=spec.name, reason="target lacks the capability")
293
+
272
294
  if not discovery:
273
295
  return
274
296
 
qaas/target.py CHANGED
@@ -259,3 +259,21 @@ def load_target(name: str, targets_dir: Path | str = "config/targets") -> Target
259
259
  # directory is the bug that hid `<project>/config/targets/` the moment anything
260
260
  # wrote into `.qaas/config/targets/`; profiles layer across every config
261
261
  # directory, and `config.target_files(dirs)` is the one place that knows it.
262
+
263
+
264
+ def agent_usable(agent_name: str, caps: dict[str, bool]) -> bool:
265
+ """Whether an agent can do useful work with the capabilities available.
266
+
267
+ Lives here, beside `capabilities()`, because it has two callers that must
268
+ agree: `qaas doctor` reports it, and the conductor acts on it. They did not
269
+ agree for a while -- doctor would say "agents that cannot: SURFACE" and then
270
+ a run would dispatch SURFACE anyway and spend its whole budget looking for a
271
+ browser that was never there. Being told an agent cannot work and then
272
+ watching it run is worse than not being told.
273
+
274
+ Everything except SURFACE can contribute from static analysis alone, at
275
+ lower confidence. SURFACE without a reachable UI has nothing to do at all.
276
+ """
277
+ if agent_name == "SURFACE":
278
+ return caps.get("live_ui", False)
279
+ return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qaas-python
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A multi-agent QA system: finds real defects, reproduces them, files tickets, fixes them, and proves the fix
5
5
  Project-URL: Homepage, https://github.com/allaabdella2-us/qa-multi-agent-system
6
6
  Project-URL: Repository, https://github.com/allaabdella2-us/qa-multi-agent-system
@@ -1,5 +1,5 @@
1
- qaas/cli.py,sha256=L12m7SGyCYNcraUXzu0bCp9A1UtiSF0L6CLzS7xVnVc,65477
2
- qaas/conductor.py,sha256=pURmyPm825s3xg1y-ypFRToeB_OoO89OQxI0oy-Gx8E,23075
1
+ qaas/cli.py,sha256=X8CZfVzVWxRpk3No1i-Ev0vD_Sle8Zba-b_uY9jv8c8,65366
2
+ qaas/conductor.py,sha256=woPR7tGiGWTWIqikn69ucMP_C5Bjo4NGwBK6RUpE9fI,24181
3
3
  qaas/config.py,sha256=ZzgK0KUy7MR31w0o7fe1D2tYl--jkZCN_VaWR2kK1Xs,17528
4
4
  qaas/discover.py,sha256=L5ejBsYs_s41OWAL-Dhc8VlQ5EWw2hGayWTDzfj05R8,8524
5
5
  qaas/envelope.py,sha256=IiqyOy96CHZw2A0pSDWBNIg6yQ2MzfcwkpQWmgMNvzY,9095
@@ -10,7 +10,7 @@ qaas/runner.py,sha256=ED0arzgx0_Y6R_mcG6OXqzh3GeSOpqVUNa4NJ0QcRk8,7417
10
10
  qaas/scorecard.py,sha256=aUU7g5OtXIW4752A4NxpIZH-OdC8bpNtzJUvCi41JYg,15809
11
11
  qaas/sdk_compat.py,sha256=ftE6PK0jZY85zkYqS7UJTGYwRkYDlH4NspiKbKVfVXQ,1678
12
12
  qaas/store.py,sha256=aDJmeCog17zo_Dw2Pw_JHTcWnDQlDW3QKzNnUttVvg8,11038
13
- qaas/target.py,sha256=-wgFDOPm8tCYzideEJV4hdVb1aakLqAM-KJT4Egfgzw,10378
13
+ qaas/target.py,sha256=j0G7EGlI6FtdzM5vTvLOjhTIsX2qDU8kFiNrSrq83Gs,11222
14
14
  qaas/tasks.py,sha256=vQh3leld5OE6zK3gfxZxbCM5ZixOQOzheJ_8ZomgHgE,17146
15
15
  qaas/trace.py,sha256=V-uFqh1iCYRqgWL3VzDbRdHgAkwLsr1uRFfwwycWZ94,11461
16
16
  qaas/adapters/__init__.py,sha256=bw2pqtDqhZGP730gwV28BJ-8TF-rhanwCEjdIizjP6A,882
@@ -78,8 +78,8 @@ qaas/prompts/SURFACE.md,sha256=cZ9df27bXXRh39yEkwByyxvHskpcNmh6HvC9C3Jt83Y,2220
78
78
  qaas/prompts/VAULT.md,sha256=Ansowimx-wMbinQkn9_gGgZFmvmMFMc9v_N8s2Ahws4,2915
79
79
  qaas/prompts/WARDEN.md,sha256=39KsbwWRwe7mtjYEik1owBIDgu4qyD52UHG_T_7gTMw,2950
80
80
  qaas/prompts/_shared.md,sha256=lN_s_rAmakhGuyRuWItC--iyy-Er6ohT_dzGeE_g-fo,2620
81
- qaas_python-0.2.0.dist-info/METADATA,sha256=HZx6pPuXaxXYhL2HwjThoiTpbB9o3LUGnh4ffziVdcE,15528
82
- qaas_python-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
83
- qaas_python-0.2.0.dist-info/entry_points.txt,sha256=6UScfruyhP9N_xGx3tXJGkaoAiB36dkINuKyOH6OkK4,38
84
- qaas_python-0.2.0.dist-info/licenses/LICENSE,sha256=pHWke5oMtv7PLjIQbN6hRa31J0AKj51VCd5TCTUbbX0,1069
85
- qaas_python-0.2.0.dist-info/RECORD,,
81
+ qaas_python-0.2.2.dist-info/METADATA,sha256=14s_84tja39SMIyEwaYPKZ_fLHtFJr9rgSpPmAykY5s,15528
82
+ qaas_python-0.2.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
83
+ qaas_python-0.2.2.dist-info/entry_points.txt,sha256=6UScfruyhP9N_xGx3tXJGkaoAiB36dkINuKyOH6OkK4,38
84
+ qaas_python-0.2.2.dist-info/licenses/LICENSE,sha256=pHWke5oMtv7PLjIQbN6hRa31J0AKj51VCd5TCTUbbX0,1069
85
+ qaas_python-0.2.2.dist-info/RECORD,,