tapps-agents 3.5.40__py3-none-any.whl → 3.5.41__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.
tapps_agents/__init__.py CHANGED
@@ -24,8 +24,8 @@ Example:
24
24
  ```
25
25
  """
26
26
 
27
- __version__: str = "3.5.40"
27
+ __version__: str = "3.5.41"
28
28
 
29
29
  # Also expose as _version_ for compatibility with some import mechanisms
30
30
  # This helps with editable installs where __version__ might not be importable
31
- _version_: str = "3.5.40"
31
+ _version_: str = "3.5.41"
@@ -207,13 +207,21 @@ def _handle_run(args: object) -> None:
207
207
  spec = spec.model_copy(update={"status": "done"})
208
208
  save_task_spec(spec, root)
209
209
  print(f"Task {task_id} completed.")
210
+ elif final_state.status == "blocked":
211
+ # BUG-003B fix: Set status to "blocked" when workflow fails
212
+ spec = spec.model_copy(update={"status": "blocked"})
213
+ save_task_spec(spec, root)
214
+ print(f"Workflow blocked: {final_state.error or 'Required step failed'}", file=sys.stderr)
215
+ sys.exit(1)
210
216
  else:
217
+ # Other statuses (paused, etc.) - set to todo for retry
211
218
  spec = spec.model_copy(update={"status": "todo"})
212
219
  save_task_spec(spec, root)
213
220
  print(f"Workflow ended with status: {final_state.status}", file=sys.stderr)
214
221
  sys.exit(1)
215
222
  except Exception as e:
216
- spec = spec.model_copy(update={"status": "todo"})
223
+ # BUG-003B fix: Set status to "blocked" on exception
224
+ spec = spec.model_copy(update={"status": "blocked"})
217
225
  save_task_spec(spec, root)
218
226
  print(f"Error running workflow: {e}", file=sys.stderr)
219
227
  sys.exit(1)
@@ -27,6 +27,7 @@ from __future__ import annotations
27
27
  import asyncio
28
28
  import hashlib
29
29
  import os
30
+ import traceback
30
31
  from collections.abc import AsyncIterator
31
32
  from contextlib import asynccontextmanager
32
33
  from dataclasses import asdict
@@ -52,7 +53,7 @@ from .event_bus import FileBasedEventBus
52
53
  from .events import EventType, WorkflowEvent
53
54
  from .logging_helper import WorkflowLogger
54
55
  from .marker_writer import MarkerWriter
55
- from .models import Artifact, StepExecution, Workflow, WorkflowState, WorkflowStep
56
+ from .models import Artifact, StepExecution, StepResult, Workflow, WorkflowState, WorkflowStep
56
57
  from .parallel_executor import ParallelStepExecutor
57
58
  from .progress_manager import ProgressUpdateManager
58
59
  from .skill_invoker import SkillInvoker
@@ -602,11 +603,74 @@ class CursorWorkflowExecutor:
602
603
 
603
604
  # Execute ready steps in parallel
604
605
  running_step_ids.update(step.id for step in ready_steps)
605
-
606
+
607
+ # Store completed steps with their results for dependency validation (BUG-003B)
608
+ completed_step_results: dict[str, StepResult] = {}
609
+
606
610
  async def execute_step_wrapper(step: WorkflowStep) -> dict[str, Any]:
607
- """Wrapper to adapt _execute_step_for_parallel to parallel executor interface."""
608
- artifacts = await self._execute_step_for_parallel(step=step, target_path=target_path)
609
- return artifacts or {}
611
+ """Wrapper to adapt _execute_step_for_parallel to parallel executor interface (BUG-003B fix)."""
612
+ # Validate dependencies before execution (BUG-003B)
613
+ can_execute, skip_reason = self._can_execute_step(step, completed_step_results)
614
+
615
+ if not can_execute:
616
+ # Create skipped StepResult
617
+ now = datetime.now()
618
+ skipped_result = StepResult(
619
+ step_id=step.id,
620
+ status="skipped",
621
+ success=False,
622
+ duration=0.0,
623
+ started_at=now,
624
+ completed_at=now,
625
+ skip_reason=skip_reason,
626
+ artifacts=[],
627
+ )
628
+ completed_step_results[step.id] = skipped_result
629
+
630
+ # Print skip message
631
+ from ..core.unicode_safe import safe_print
632
+ safe_print(f"\n⏭️ Skipping step '{step.id}': {skip_reason}\n")
633
+
634
+ # Return empty artifacts (step was skipped)
635
+ return {}
636
+
637
+ # Execute step
638
+ step_result = await self._execute_step_for_parallel(step=step, target_path=target_path)
639
+ completed_step_results[step.id] = step_result
640
+
641
+ # Check if step failed (BUG-003B)
642
+ if not step_result.success:
643
+ # Check if step is required
644
+ is_required = step.condition == "required"
645
+
646
+ if is_required:
647
+ # Halt workflow for required step failure
648
+ from ..core.unicode_safe import safe_print
649
+ safe_print(
650
+ f"\n❌ Workflow halted: Required step '{step.id}' failed\n"
651
+ f"Error: {step_result.error}\n"
652
+ )
653
+
654
+ # Update workflow status
655
+ if self.state:
656
+ self.state.status = "blocked"
657
+ self.state.error = step_result.error
658
+
659
+ # Raise error to stop execution
660
+ raise RuntimeError(step_result.error or "Step failed")
661
+
662
+ # Convert StepResult artifacts (list of names) back to dict format for compatibility
663
+ artifacts_dict: dict[str, dict[str, Any]] = {}
664
+ for artifact_name in step_result.artifacts:
665
+ artifacts_dict[artifact_name] = {
666
+ "name": artifact_name,
667
+ "path": artifact_name,
668
+ "status": "complete",
669
+ "created_by": step.id,
670
+ "created_at": step_result.completed_at.isoformat(),
671
+ }
672
+
673
+ return artifacts_dict
610
674
 
611
675
  try:
612
676
  results = await self.parallel_executor.execute_parallel(
@@ -1325,11 +1389,14 @@ class CursorWorkflowExecutor:
1325
1389
 
1326
1390
  async def _execute_step_for_parallel(
1327
1391
  self, step: WorkflowStep, target_path: Path | None
1328
- ) -> dict[str, dict[str, Any]] | None:
1392
+ ) -> StepResult:
1329
1393
  """
1330
- Execute a single workflow step using Cursor Skills and return artifacts (for parallel execution).
1331
-
1332
- This is similar to _execute_step but returns artifacts instead of updating state.
1394
+ Execute a single workflow step using Cursor Skills and return result (BUG-003B fix).
1395
+
1396
+ This method now returns StepResult with proper error handling:
1397
+ - success=True + artifacts on success
1398
+ - success=False + error details on failure (no exception raised)
1399
+
1333
1400
  State updates (step_execution tracking) are handled by ParallelStepExecutor.
1334
1401
  """
1335
1402
  if not self.state or not self.workflow:
@@ -1356,8 +1423,17 @@ class CursorWorkflowExecutor:
1356
1423
 
1357
1424
  # Handle completion/finalization steps that don't require agent execution
1358
1425
  if agent_name == "orchestrator" and action in ["finalize", "complete"]:
1359
- # Return empty artifacts for completion steps
1360
- return {}
1426
+ # Return successful result for completion steps (no artifacts)
1427
+ now = datetime.now()
1428
+ return StepResult(
1429
+ step_id=step.id,
1430
+ status="completed",
1431
+ success=True,
1432
+ duration=0.0,
1433
+ started_at=now,
1434
+ completed_at=now,
1435
+ artifacts=[],
1436
+ )
1361
1437
 
1362
1438
  # Track step start time for duration calculation
1363
1439
  step_started_at = datetime.now()
@@ -1407,16 +1483,12 @@ class CursorWorkflowExecutor:
1407
1483
  # Worktree is only used for skill invocation fallback
1408
1484
  created_artifacts_list = await handler.execute(step, action, target_path)
1409
1485
 
1410
- # Convert handler artifacts to dict format
1411
- artifacts_dict: dict[str, dict[str, Any]] = {}
1412
- for art in (created_artifacts_list or []):
1413
- artifacts_dict[art["name"]] = art
1414
-
1415
1486
  # Write success marker
1416
1487
  step_completed_at = datetime.now()
1417
1488
  duration = (step_completed_at - step_started_at).total_seconds()
1418
1489
 
1419
1490
  found_artifact_paths = [art["path"] for art in (created_artifacts_list or [])]
1491
+ artifact_names = [art["name"] for art in (created_artifacts_list or [])]
1420
1492
 
1421
1493
  marker_path = self.marker_writer.write_done_marker(
1422
1494
  workflow_id=self.state.workflow_id,
@@ -1438,7 +1510,16 @@ class CursorWorkflowExecutor:
1438
1510
  marker_path=str(marker_path),
1439
1511
  )
1440
1512
 
1441
- return artifacts_dict if artifacts_dict else None
1513
+ # Return successful StepResult (BUG-003B fix)
1514
+ return StepResult(
1515
+ step_id=step.id,
1516
+ status="completed",
1517
+ success=True,
1518
+ duration=duration,
1519
+ started_at=step_started_at,
1520
+ completed_at=step_completed_at,
1521
+ artifacts=artifact_names,
1522
+ )
1442
1523
  else:
1443
1524
  # Fall back to SkillInvoker for steps without handlers
1444
1525
  safe_print(f"\n[EXEC] Executing {agent_name}/{action} via skill...", flush=True)
@@ -1459,19 +1540,12 @@ class CursorWorkflowExecutor:
1459
1540
  step=step,
1460
1541
  )
1461
1542
 
1462
- # Convert artifacts to dict format
1463
- artifacts_dict: dict[str, dict[str, Any]] = {}
1543
+ # Extract artifact paths and names
1464
1544
  found_artifact_paths = []
1545
+ artifact_names = []
1465
1546
  for artifact in artifacts:
1466
- artifacts_dict[artifact.name] = {
1467
- "name": artifact.name,
1468
- "path": artifact.path,
1469
- "status": artifact.status,
1470
- "created_by": artifact.created_by,
1471
- "created_at": artifact.created_at.isoformat() if artifact.created_at else None,
1472
- "metadata": artifact.metadata or {},
1473
- }
1474
1547
  found_artifact_paths.append(artifact.path)
1548
+ artifact_names.append(artifact.name)
1475
1549
 
1476
1550
  # Write DONE marker for successful completion
1477
1551
  step_completed_at = datetime.now()
@@ -1497,8 +1571,17 @@ class CursorWorkflowExecutor:
1497
1571
  marker_path=str(marker_path),
1498
1572
  )
1499
1573
 
1574
+ # Return successful StepResult (BUG-003B fix)
1500
1575
  # Worktree cleanup is handled by context manager
1501
- return artifacts_dict if artifacts_dict else None
1576
+ return StepResult(
1577
+ step_id=step.id,
1578
+ status="completed",
1579
+ success=True,
1580
+ duration=duration,
1581
+ started_at=step_started_at,
1582
+ completed_at=step_completed_at,
1583
+ artifacts=artifact_names,
1584
+ )
1502
1585
 
1503
1586
  except (TimeoutError, RuntimeError) as e:
1504
1587
  # Write FAILED marker for timeout or execution errors
@@ -1506,7 +1589,8 @@ class CursorWorkflowExecutor:
1506
1589
  duration = (step_failed_at - step_started_at).total_seconds()
1507
1590
  error_type = type(e).__name__
1508
1591
  error_msg = str(e)
1509
-
1592
+ error_tb = traceback.format_exc()
1593
+
1510
1594
  # Try to get completion status if available (for missing artifacts)
1511
1595
  found_artifact_paths = []
1512
1596
  try:
@@ -1518,7 +1602,7 @@ class CursorWorkflowExecutor:
1518
1602
  found_artifact_paths = completion_status.get("found_artifacts", [])
1519
1603
  except Exception:
1520
1604
  pass
1521
-
1605
+
1522
1606
  marker_path = self.marker_writer.write_failed_marker(
1523
1607
  workflow_id=self.state.workflow_id,
1524
1608
  step_id=step.id,
@@ -1537,30 +1621,41 @@ class CursorWorkflowExecutor:
1537
1621
  "marker_location": f".tapps-agents/workflows/markers/{self.state.workflow_id}/step-{step.id}/FAILED.json",
1538
1622
  },
1539
1623
  )
1540
-
1624
+
1541
1625
  if self.logger:
1542
1626
  self.logger.warning(
1543
1627
  f"FAILED marker written for step {step.id}",
1544
1628
  marker_path=str(marker_path),
1545
1629
  error=error_msg,
1546
1630
  )
1547
-
1631
+
1548
1632
  # Include marker location in error message for better troubleshooting
1549
1633
  from ..core.unicode_safe import safe_print
1550
1634
  safe_print(
1551
1635
  f"\n[INFO] Failure marker written to: {marker_path}",
1552
1636
  flush=True,
1553
1637
  )
1554
-
1555
- # Re-raise the exception
1556
- raise
1638
+
1639
+ # Return failed StepResult (BUG-003B fix - don't raise)
1640
+ return StepResult(
1641
+ step_id=step.id,
1642
+ status="failed",
1643
+ success=False,
1644
+ duration=duration,
1645
+ started_at=step_started_at,
1646
+ completed_at=step_failed_at,
1647
+ error=error_msg,
1648
+ error_traceback=error_tb,
1649
+ artifacts=[],
1650
+ )
1557
1651
  except Exception as e:
1558
1652
  # Write FAILED marker for unexpected errors
1559
1653
  step_failed_at = datetime.now()
1560
1654
  duration = (step_failed_at - step_started_at).total_seconds()
1561
1655
  error_type = type(e).__name__
1562
1656
  error_msg = str(e)
1563
-
1657
+ error_tb = traceback.format_exc()
1658
+
1564
1659
  marker_path = self.marker_writer.write_failed_marker(
1565
1660
  workflow_id=self.state.workflow_id,
1566
1661
  step_id=step.id,
@@ -1579,7 +1674,7 @@ class CursorWorkflowExecutor:
1579
1674
  "marker_location": f".tapps-agents/workflows/markers/{self.state.workflow_id}/step-{step.id}/FAILED.json",
1580
1675
  },
1581
1676
  )
1582
-
1677
+
1583
1678
  if self.logger:
1584
1679
  self.logger.error(
1585
1680
  f"FAILED marker written for step {step.id} (unexpected error)",
@@ -1587,9 +1682,19 @@ class CursorWorkflowExecutor:
1587
1682
  error=error_msg,
1588
1683
  exc_info=True,
1589
1684
  )
1590
-
1591
- # Re-raise the exception
1592
- raise
1685
+
1686
+ # Return failed StepResult (BUG-003B fix - don't raise)
1687
+ return StepResult(
1688
+ step_id=step.id,
1689
+ status="failed",
1690
+ success=False,
1691
+ duration=duration,
1692
+ started_at=step_started_at,
1693
+ completed_at=step_failed_at,
1694
+ error=error_msg,
1695
+ error_traceback=error_tb,
1696
+ artifacts=[],
1697
+ )
1593
1698
 
1594
1699
  @asynccontextmanager
1595
1700
  async def _worktree_context(
@@ -1843,6 +1948,42 @@ class CursorWorkflowExecutor:
1843
1948
  finally:
1844
1949
  self.save_state()
1845
1950
 
1951
+ def _can_execute_step(
1952
+ self,
1953
+ step: WorkflowStep,
1954
+ completed_steps: dict[str, StepResult]
1955
+ ) -> tuple[bool, str]:
1956
+ """
1957
+ Check if step can execute based on dependencies (BUG-003B fix).
1958
+
1959
+ Validates that all required dependencies have been executed and succeeded.
1960
+ If any dependency is missing or failed, the step cannot execute.
1961
+
1962
+ Args:
1963
+ step: Step to check
1964
+ completed_steps: Results of previously executed steps
1965
+
1966
+ Returns:
1967
+ (can_execute, skip_reason) tuple:
1968
+ - (True, "") if all dependencies met
1969
+ - (False, reason) if dependencies not met
1970
+
1971
+ Example:
1972
+ can_run, reason = self._can_execute_step(step, completed_steps)
1973
+ if not can_run:
1974
+ # Skip step with reason
1975
+ skip_result = StepResult(status="skipped", skip_reason=reason, ...)
1976
+ """
1977
+ for dep in step.requires or []:
1978
+ if dep not in completed_steps:
1979
+ return False, f"Dependency '{dep}' not executed"
1980
+
1981
+ dep_result = completed_steps[dep]
1982
+ if not dep_result.success:
1983
+ return False, f"Dependency '{dep}' failed: {dep_result.error}"
1984
+
1985
+ return True, ""
1986
+
1846
1987
  def _normalize_action(self, action: str) -> str:
1847
1988
  """
1848
1989
  Normalize action name to use underscores (Python convention).
@@ -5,7 +5,7 @@ Workflow models - Data structures for workflow definitions.
5
5
  from dataclasses import dataclass, field
6
6
  from datetime import datetime
7
7
  from enum import Enum
8
- from typing import Any
8
+ from typing import Any, Literal
9
9
 
10
10
 
11
11
  class WorkflowType(Enum):
@@ -95,6 +95,43 @@ class StepExecution:
95
95
  error: str | None = None
96
96
 
97
97
 
98
+ @dataclass
99
+ class StepResult:
100
+ """Result of step execution with proper error handling.
101
+
102
+ This class represents the outcome of executing a workflow step,
103
+ including success/failure status, error details, and artifacts created.
104
+ Used by CursorExecutor to properly track step outcomes and halt
105
+ workflows when required steps fail.
106
+ """
107
+
108
+ step_id: str
109
+ status: Literal["completed", "failed", "skipped"]
110
+ success: bool
111
+ duration: float
112
+ started_at: datetime
113
+ completed_at: datetime
114
+ error: str | None = None
115
+ error_traceback: str | None = None
116
+ artifacts: list[str] = field(default_factory=list)
117
+ skip_reason: str | None = None
118
+
119
+ def to_dict(self) -> dict[str, Any]:
120
+ """Convert to dictionary for serialization."""
121
+ return {
122
+ "step_id": self.step_id,
123
+ "status": self.status,
124
+ "success": self.success,
125
+ "duration": self.duration,
126
+ "started_at": self.started_at.isoformat(),
127
+ "completed_at": self.completed_at.isoformat(),
128
+ "error": self.error,
129
+ "error_traceback": self.error_traceback,
130
+ "artifacts": self.artifacts,
131
+ "skip_reason": self.skip_reason,
132
+ }
133
+
134
+
98
135
  @dataclass
99
136
  class WorkflowState:
100
137
  """Workflow execution state."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tapps-agents
3
- Version: 3.5.40
3
+ Version: 3.5.41
4
4
  Summary: A specification framework for defining, configuring, and orchestrating coding agents
5
5
  Author: Tapps
6
6
  Maintainer: Tapps
@@ -1,4 +1,4 @@
1
- tapps_agents/__init__.py,sha256=PRiG3PBenRzWH5o_UapUUWxh2l2A7N_mHD-ute_PzjY,1180
1
+ tapps_agents/__init__.py,sha256=ZnBHeqZtNulBHToeSdRA1bK58J9YrYT2DvheuT3MrEQ,1180
2
2
  tapps_agents/agents/__init__.py,sha256=w0Aj0bEdmIoPY1OcVTK0KFRSkYeAk-66CM2zmGTLjW0,698
3
3
  tapps_agents/agents/analyst/__init__.py,sha256=zLFkB6j1PkcpeaOk8Vnx76oYzVYyUqdULWj-pOyfLZY,135
4
4
  tapps_agents/agents/analyst/agent.py,sha256=YgPvWOqdZfIA24jIrbmHSdj3EVGIrGpwVIv5ep9uc8U,32033
@@ -133,7 +133,7 @@ tapps_agents/cli/commands/planner.py,sha256=dB43ux1hF5Z_bJImP06CpKocCRWcSGd2LG90
133
133
  tapps_agents/cli/commands/reviewer.py,sha256=TjuTgaQaCfaFfZfW-7Hm4X6JjUKz9vVzDodO1uA6Om4,78081
134
134
  tapps_agents/cli/commands/simple_mode.py,sha256=JjuaaPKo0DZXOqMNyvFNNqz98sNE78EZFeMIcu77lOU,31820
135
135
  tapps_agents/cli/commands/status.py,sha256=XrkCnxdiaieZrXExAW0_YrCDlkVGa9iRIiJ74DwP_5o,10661
136
- tapps_agents/cli/commands/task.py,sha256=YQTEopFPw7QUeSHG5xe98aJUG8YNy-tEOE794Kl0Vq4,7956
136
+ tapps_agents/cli/commands/task.py,sha256=11mWEyAL-Mo3PzH6P1cg84o7Mn4xKuoCzzBCOy1IB5o,8445
137
137
  tapps_agents/cli/commands/tester.py,sha256=ZGwSw8O6wMOx1UO5kCgmawZUccC0MBL3kvRH-7dEic4,8481
138
138
  tapps_agents/cli/commands/top_level.py,sha256=dTh_rdoSiXrLgnDN04YIvlNITPnEnxoek7E8NusARho,149034
139
139
  tapps_agents/cli/help/__init__.py,sha256=2hO-whwGhNM4efFc7fc7ihTmE5PmxFl7jaQ2H7ywUbA,147
@@ -659,7 +659,7 @@ tapps_agents/workflow/confirmation_handler.py,sha256=iH6WCI08pDin5FBztzMYgRMWaO3
659
659
  tapps_agents/workflow/context_analyzer.py,sha256=-Nxq8okaqQD1rTAsOtNy0BNN_AcMQweM6KCxV8S6j34,8455
660
660
  tapps_agents/workflow/context_artifact.py,sha256=ps8sZgMXIemKNK1nADxpHfi5NQdFIVtmDMp48jDb5rI,8125
661
661
  tapps_agents/workflow/cursor_chat.py,sha256=e_2eXbr3yFYRdnu9iYcWIsuRgubd5-R68DsJrFN9buU,3180
662
- tapps_agents/workflow/cursor_executor.py,sha256=9wbMDAX4k18OVdGQYvPmd8IYS6Sxt2La18Pqo8tBWjQ,93712
662
+ tapps_agents/workflow/cursor_executor.py,sha256=pdWZk3C4xMSD5JazEJFXwWK5SSSbB3363U__HYcKKEw,99476
663
663
  tapps_agents/workflow/cursor_skill_helper.py,sha256=QZCNCIBpwdZiP5piH9qB2l3Fseh4bMulCg8QcHyAfVA,19481
664
664
  tapps_agents/workflow/dependency_resolver.py,sha256=f_2a0uUBADHPEgNvdOdA-tCs-qYXwKyMkbvep2mwlrI,8923
665
665
  tapps_agents/workflow/design_artifact.py,sha256=HgEyNndiItMBPTTalOtiUrB600LF3EwwIL557034w7k,5510
@@ -693,7 +693,7 @@ tapps_agents/workflow/metadata_models.py,sha256=xsigrFQgIgFzLJn7qwCa242w49iEv-Qw
693
693
  tapps_agents/workflow/metrics_enhancements.py,sha256=6u5EnXCJTyLbi5BcouKamW2Pzutmzjv-Fy-ZGCHVgxk,25800
694
694
  tapps_agents/workflow/metrics_integration.py,sha256=NXhbw77zrS4X0xE61hCCNLt4lucfadKH1dSjANYowYI,7511
695
695
  tapps_agents/workflow/migration_utils.py,sha256=46kMrHV3yxujDpcDxtPytg9aL7N_BPRch1bEUIP_Ahc,3877
696
- tapps_agents/workflow/models.py,sha256=1lDPzWaKDEqfVNjRe20fSfe892nPvpLrItb85nFLfWk,2959
696
+ tapps_agents/workflow/models.py,sha256=-IuecSogkRpYjOWjm4Qx-dpZ4uCnSbeVGcGPq7kvYHQ,4235
697
697
  tapps_agents/workflow/nlp_config.py,sha256=KesPjPzDfBa3WnnWT5IRkaNzzLbS4MLfr5UqdmTkYSI,6790
698
698
  tapps_agents/workflow/nlp_error_handler.py,sha256=Kgdu1XrPFiHTTJ3WctbaezsBP4v4DwfSO7Nc6BSEdKo,7352
699
699
  tapps_agents/workflow/nlp_executor.py,sha256=IiWv4ybBHWtccn0rN8Tp0ckpVVMdRA4V0DmiV_VbkFE,6806
@@ -752,9 +752,9 @@ tapps_agents/workflow/agent_handlers/planner_handler.py,sha256=9oVSsA6Lso5NncYPS
752
752
  tapps_agents/workflow/agent_handlers/registry.py,sha256=aYMU59da4SBgDgqMy4Basu1yL8CvDvdi929n6XM50ro,3613
753
753
  tapps_agents/workflow/agent_handlers/reviewer_handler.py,sha256=D4spVUk4l9mJsSsDIKC88EL-2k43YObNz5v439EtDRc,4285
754
754
  tapps_agents/workflow/agent_handlers/tester_handler.py,sha256=e44Eqn1CIpcqYqCrjaTK748yb4k7PlzGdK9zSne-SfY,2249
755
- tapps_agents-3.5.40.dist-info/licenses/LICENSE,sha256=xwT0RCg0KluJ63lZcgkSOiYkpEIEXYlIGqRtkGGsPe0,1085
756
- tapps_agents-3.5.40.dist-info/METADATA,sha256=jkhzTrjCsNOgFVIFPZwvARmAQ7EstqhNdZYHtMcUrWU,41413
757
- tapps_agents-3.5.40.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
758
- tapps_agents-3.5.40.dist-info/entry_points.txt,sha256=b8WhZxYg2xA-ocElPeY0LDSqRCOgzw6PuEksZD6BB2E,55
759
- tapps_agents-3.5.40.dist-info/top_level.txt,sha256=AR0UfcM1nJhQ413h8j1ObAGsUrbfys55D-qKUBGzYtk,13
760
- tapps_agents-3.5.40.dist-info/RECORD,,
755
+ tapps_agents-3.5.41.dist-info/licenses/LICENSE,sha256=xwT0RCg0KluJ63lZcgkSOiYkpEIEXYlIGqRtkGGsPe0,1085
756
+ tapps_agents-3.5.41.dist-info/METADATA,sha256=WeP5io4GWolPJjOHH-c1GO6jHwqQ6YY-SJKF3hJvVO8,41413
757
+ tapps_agents-3.5.41.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
758
+ tapps_agents-3.5.41.dist-info/entry_points.txt,sha256=b8WhZxYg2xA-ocElPeY0LDSqRCOgzw6PuEksZD6BB2E,55
759
+ tapps_agents-3.5.41.dist-info/top_level.txt,sha256=AR0UfcM1nJhQ413h8j1ObAGsUrbfys55D-qKUBGzYtk,13
760
+ tapps_agents-3.5.41.dist-info/RECORD,,