-
Notifications
You must be signed in to change notification settings - Fork 0
Claude/fix ci pipeline 1i wa h #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,3 +70,6 @@ logs/sentinel/ | |
|
|
||
| # Agent Core β memory persistence | ||
| .disha/ | ||
|
|
||
| # Claude Code internal state | ||
| .claude/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,9 @@ def get_capable_agents(self, capability: str) -> list: | |
| if capability in node.capabilities and node.status != "offline" | ||
| ] | ||
|
|
||
| ITERATION_THRESHOLD = 0.4 # re-run if consensus agreement falls below this | ||
| MAX_ITERATIONS = 3 # cap iterations to prevent infinite loops | ||
|
|
||
| async def collaborative_investigate( | ||
| self, | ||
| target: str, | ||
|
|
@@ -85,11 +88,12 @@ async def collaborative_investigate( | |
|
|
||
| Flow: | ||
| 1. Coordinator broadcasts task to all agents | ||
| 2. Agents claim subtasks based on capabilities | ||
| 3. Agents execute and share results | ||
| 4. Review phase: agents critique each other | ||
| 5. Consensus: agents vote on final assessment | ||
| 6. Iterate if needed | ||
| 2. Agents execute in parallel | ||
| 3. Peer review: agents score each other's results | ||
| 4. Consensus: confidence-weighted vote on risk assessment | ||
| 5. If consensus is too low, iterate with dissenting agents | ||
| re-running with additional context from the first round | ||
| 6. Compile final result | ||
| """ | ||
| conversation = self.router.create_conversation(topic=target) | ||
| context = context or {} | ||
|
|
@@ -109,14 +113,53 @@ async def collaborative_investigate( | |
| self.router.send(task_msg) | ||
| conversation.add_message(task_msg) | ||
|
|
||
| # Phase 2: Parallel execution by all capable agents | ||
| # Phase 2: Parallel execution | ||
| results = await self._parallel_execute(target, context) | ||
|
|
||
| # Phase 3: Share results for peer review | ||
| # Phase 3: Peer review | ||
| review_results = await self._peer_review(results, conversation) | ||
|
|
||
| # Phase 4: Consensus building | ||
| # Phase 4: Consensus + iterative refinement | ||
| consensus = self._build_consensus(results, review_results) | ||
| iteration = 0 | ||
|
|
||
| while ( | ||
| not consensus.get("consensus_reached", False) | ||
| and consensus.get("agreement_score", 1.0) < self.ITERATION_THRESHOLD | ||
| and iteration < self.MAX_ITERATIONS | ||
| ): | ||
| iteration += 1 | ||
| logger.info( | ||
| "consensus_below_threshold_iterating", | ||
| target=target, | ||
| iteration=iteration, | ||
| agreement=round(consensus.get("agreement_score", 0), 3), | ||
| ) | ||
|
|
||
| # Identify low-confidence agents and re-run them with shared context | ||
| low_conf_agents = self._identify_dissenting_agents(results, review_results) | ||
| if not low_conf_agents: | ||
| break | ||
|
|
||
| enriched_context = { | ||
| **context, | ||
| "prior_round": iteration, | ||
| "peer_findings": { | ||
| name: res.get("entities", [])[:5] | ||
| for name, res in results.items() | ||
| if isinstance(res, dict) and name not in low_conf_agents | ||
| }, | ||
| } | ||
|
|
||
| # Re-run only the dissenting agents | ||
| refined = await self._selective_execute(low_conf_agents, target, enriched_context) | ||
| results.update(refined) | ||
|
|
||
| # Rebuild consensus with updated results | ||
| review_results = await self._peer_review(results, conversation) | ||
| consensus = self._build_consensus(results, review_results) | ||
|
|
||
| consensus["iterations"] = iteration | ||
|
|
||
| # Phase 5: Compile final result | ||
| final_result = self._compile_results( | ||
|
|
@@ -129,12 +172,69 @@ async def collaborative_investigate( | |
| "collaborative_investigation_complete", | ||
| target=target, | ||
| agents_involved=len(results), | ||
| iterations=iteration, | ||
| consensus_score=consensus.get("score", 0), | ||
| agreement=consensus.get("agreement_score", 0), | ||
| risk_score=final_result.get("risk_score", 0), | ||
| ) | ||
|
|
||
| return final_result | ||
|
|
||
| def _identify_dissenting_agents(self, results: dict, reviews: dict) -> list[str]: | ||
| """Return names of agents whose results received the lowest peer review scores.""" | ||
| avg_scores: dict[str, list[float]] = {} | ||
| for reviewer_reviews in reviews.values(): | ||
| for name, score in reviewer_reviews.items(): | ||
| avg_scores.setdefault(name, []).append(score) | ||
|
|
||
| scored = { | ||
| name: sum(scores) / len(scores) | ||
| for name, scores in avg_scores.items() | ||
| if scores | ||
| } | ||
| if not scored: | ||
| return [] | ||
|
|
||
| # Return the bottom 50% of agents by peer-review score | ||
| sorted_agents = sorted(scored, key=scored.get) | ||
| cutoff = max(1, len(sorted_agents) // 2) | ||
| return sorted_agents[:cutoff] | ||
|
|
||
| async def _selective_execute( | ||
| self, agent_names: list[str], target: str, context: dict | ||
| ) -> dict: | ||
| """Re-run a specific subset of agents.""" | ||
| selected = [(name, node) for name, node in self.nodes.items() if name in agent_names] | ||
| if not selected: | ||
| return {} | ||
|
|
||
| results = {} | ||
|
|
||
| async def run_agent(name, node): | ||
| start = time.time() | ||
| try: | ||
| result = await node.agent.run(target, context) | ||
| node.tasks_completed += 1 | ||
| node.total_time += time.time() - start | ||
| node.last_active = time.time() | ||
| return name, result | ||
| except Exception as e: | ||
| logger.error("selective_agent_execution_failed", agent=name, error=str(e)) | ||
| return name, {"error": str(e), "status": "failed"} | ||
|
|
||
| agent_results = await asyncio.gather( | ||
| *[run_agent(name, node) for name, node in selected], | ||
| return_exceptions=True, | ||
| ) | ||
|
|
||
| for item in agent_results: | ||
| if isinstance(item, Exception): | ||
| continue | ||
| name, result = item | ||
| results[name] = result | ||
|
|
||
| return results | ||
|
Comment on lines
+203
to
+236
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mirror the busy/idle lifecycle in selective reruns. Unlike Proposed fix async def run_agent(name, node):
start = time.time()
+ node.status = "busy"
try:
result = await node.agent.run(target, context)
node.tasks_completed += 1
node.total_time += time.time() - start
node.last_active = time.time()
return name, result
except Exception as e:
logger.error("selective_agent_execution_failed", agent=name, error=str(e))
return name, {"error": str(e), "status": "failed"}
+ finally:
+ node.status = "idle"π§° Toolsπͺ Ruff (0.15.9)[warning] 213-213: Missing return type annotation for private function (ANN202) [warning] 220-220: Consider moving this statement to an (TRY300) [warning] 221-221: Do not catch blind exception: (BLE001) [warning] 222-222: Use Replace with (TRY400) π€ Prompt for AI Agents |
||
|
|
||
| async def _parallel_execute(self, target: str, context: dict) -> dict: | ||
| """Execute all available agents in parallel.""" | ||
| results = {} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| """ | ||
| DISHA-MIND β Cognitive Engine Package. | ||
|
|
||
| Entry point for the 7-stage cognitive loop, three-layer memory architecture, | ||
| multi-agent deliberation, hybrid reasoning, and quantum-inspired decisions. | ||
| """ | ||
|
|
||
| from cognitive_engine.cognitive_loop import CognitiveEngine, CognitiveState | ||
|
|
||
| __all__ = ["CognitiveEngine", "CognitiveState"] | ||
| __version__ = "1.0.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| """ | ||
| cognitive-engine/agents β Multi-Agent Deliberation for the DISHA Cognitive Architecture. | ||
|
|
||
| This subpackage implements the three-agent deliberation layer that sits between | ||
| raw reasoning hypotheses and final action selection: | ||
|
|
||
| Planner β strategic goal decomposition | ||
| Executor β concrete step-by-step action plan | ||
| Critic β quality gate and risk assessment | ||
| Vote β confidence-weighted consensus | ||
|
|
||
| The AgentDeliberator class orchestrates all three and returns a consensus dict. | ||
| """ | ||
|
|
||
| from cognitive_engine.agents.deliberation import AgentDeliberator | ||
|
|
||
| __all__ = ["AgentDeliberator"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Select dissenters by consensus deviation, not payload completeness.
_build_consensus()lowersagreement_scorefromrisk_scorevariance, but this helper reruns agents based only on peer-review scores derived from_score_result(). Since_score_result()only looks at field presence/status, equally shaped results with conflictingrisk_scores get the same score, so the retry loop can re-run arbitrary agents and never improve agreement.Proposed fix
def _identify_dissenting_agents(self, results: dict, reviews: dict) -> list[str]: """Return names of agents whose results received the lowest peer review scores.""" - avg_scores: dict[str, list[float]] = {} - for reviewer_reviews in reviews.values(): - for name, score in reviewer_reviews.items(): - avg_scores.setdefault(name, []).append(score) - - scored = { - name: sum(scores) / len(scores) - for name, scores in avg_scores.items() - if scores - } - if not scored: - return [] - - # Return the bottom 50% of agents by peer-review score - sorted_agents = sorted(scored, key=scored.get) + risk_scores = { + name: result["risk_score"] + for name, result in results.items() + if isinstance(result, dict) and "risk_score" in result + } + if risk_scores: + avg_risk = sum(risk_scores.values()) / len(risk_scores) + sorted_agents = sorted( + risk_scores, + key=lambda name: abs(risk_scores[name] - avg_risk), + reverse=True, + ) + cutoff = max(1, len(sorted_agents) // 2) + return sorted_agents[:cutoff] + + avg_scores: dict[str, list[float]] = {} + for reviewer_reviews in reviews.values(): + for name, score in reviewer_reviews.items(): + avg_scores.setdefault(name, []).append(score) + + scored = { + name: sum(scores) / len(scores) + for name, scores in avg_scores.items() + if scores + } + if not scored: + return [] + + sorted_agents = sorted(scored, key=scored.get) cutoff = max(1, len(sorted_agents) // 2) return sorted_agents[:cutoff]π§° Tools
πͺ Ruff (0.15.9)
[warning] 183-183: Unused method argument:
results(ARG002)
π€ Prompt for AI Agents