-
Notifications
You must be signed in to change notification settings - Fork 0
feat: enhance Hivemind agent execution with max iterations and improve error handling! #48
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 | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||
| import asyncio | ||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import nest_asyncio | ||||||||||||||||||||||||||||||||||||||
| from dotenv import load_dotenv | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -8,6 +9,7 @@ | |||||||||||||||||||||||||||||||||||||
| from tc_temporal_backend.client import TemporalClient | ||||||||||||||||||||||||||||||||||||||
| from tc_temporal_backend.schema.hivemind import HivemindQueryPayload | ||||||||||||||||||||||||||||||||||||||
| from temporalio.common import RetryPolicy | ||||||||||||||||||||||||||||||||||||||
| from temporalio.client import WorkflowFailureError | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| nest_asyncio.apply() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -42,13 +44,30 @@ async def query(self, query: str) -> str | None: | |||||||||||||||||||||||||||||||||||||
| payload.workflow_id = self.workflow_id | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| hivemind_queue = self.load_hivemind_queue() | ||||||||||||||||||||||||||||||||||||||
| result = await client.execute_workflow( | ||||||||||||||||||||||||||||||||||||||
| "HivemindWorkflow", | ||||||||||||||||||||||||||||||||||||||
| payload, | ||||||||||||||||||||||||||||||||||||||
| id=f"hivemind-query-{self.community_id}-{self.workflow_id}", | ||||||||||||||||||||||||||||||||||||||
| task_queue=hivemind_queue, | ||||||||||||||||||||||||||||||||||||||
| retry_policy=RetryPolicy(maximum_attempts=3), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| result = await client.execute_workflow( | ||||||||||||||||||||||||||||||||||||||
| "HivemindWorkflow", | ||||||||||||||||||||||||||||||||||||||
| payload, | ||||||||||||||||||||||||||||||||||||||
| id=f"hivemind-query-{self.community_id}-{self.workflow_id}", | ||||||||||||||||||||||||||||||||||||||
| task_queue=hivemind_queue, | ||||||||||||||||||||||||||||||||||||||
| retry_policy=RetryPolicy(maximum_attempts=3), | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
| except WorkflowFailureError as e: | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+47
to
+55
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. 🛠️ Refactor suggestion Ensure workflow ID uniqueness when workflow_id is absent Using id=f"hivemind-query-{community_id}-{workflow_id}" will collide across requests when workflow_id is None, leading to WorkflowAlreadyStarted-like errors. Fallback to a random suffix when no workflow_id is provided. - id=f"hivemind-query-{self.community_id}-{self.workflow_id}",
+ id=f"hivemind-query-{self.community_id}-{self.workflow_id or os.urandom(8).hex()}",
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| logging.error(f"WorkflowFailureError: {e} for workflow {self.workflow_id}", exc_info=True) | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||
| logging.error(f"Exception: {e} for workflow {self.workflow_id}", exc_info=True) | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Normalize Temporal failure-shaped responses that may be returned as data | ||||||||||||||||||||||||||||||||||||||
| if isinstance(result, dict) and ( | ||||||||||||||||||||||||||||||||||||||
| "workflowExecutionFailedEventAttributes" in result or "failure" in result | ||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
| logging.error(f"WorkflowFailureError: {result} for workflow {self.workflow_id}", exc_info=True) | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
| if isinstance(result, str) and "workflowExecutionFailedEventAttributes" in result: | ||||||||||||||||||||||||||||||||||||||
| logging.error(f"WorkflowFailureError: {result} for workflow {self.workflow_id}", exc_info=True) | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+62
to
+70
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. 🛠️ Refactor suggestion Don’t log exc_info for non-exceptions These branches handle failure-shaped payloads, not exceptions. exc_info=True prints a spurious “NoneType: None” stack trace. Remove exc_info here. - logging.error(f"WorkflowFailureError: {result} for workflow {self.workflow_id}", exc_info=True)
+ logging.error(f"WorkflowFailureError-shaped payload for workflow {self.workflow_id}: {result}")
...
- logging.error(f"WorkflowFailureError: {result} for workflow {self.workflow_id}", exc_info=True)
+ logging.error(f"WorkflowFailureError-shaped payload for workflow {self.workflow_id}: {result}")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+62
to
71
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. 💡 Verification agent 🧩 Analysis chainVerify return type consistency (may not always be str) You normalize failure-shaped dict/str responses, but a successful result could also be a dict depending on the workflow. The method signature declares str | None, and the tool wrapper returns response as-is. If success can be non-str, adjust types or coerce to str before returning. Possible adjustments:
if not isinstance(result, str):
result = json.dumps(result, ensure_ascii=False)
return resultIf you want, I can scan this repo for consumers that assume a string and propose end-to-end changes. I’ll inspect the function signature to confirm what types it may return. Running a quick search and file excerpt now. 🏁 Script executed: #!/bin/bash
# Locate the function definition and show its signature
rg -n "def " tasks/hivemind/query_data_sources.py
# Show the first 200 lines to capture imports and the method signature
sed -n '1,200p' tasks/hivemind/query_data_sources.pyLength of output: 4699 Ensure The Locations to update in
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| return result | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
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.
Incorrect import for WorkflowFailureError
WorkflowFailureError is exposed from temporalio.exceptions, not temporalio.client. This will raise ImportError at runtime.
📝 Committable suggestion
🤖 Prompt for AI Agents