Skip to content

Conversation

@robholland
Copy link

What was changed

Adds a recipe for a human in the loop workflow.

Copy link
Collaborator

@jssmith jssmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good. See various small comments.

- Slack/Teams messages
- Push notifications to mobile apps
- Updates to approval queue UI
"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add that this implementation instead is logging.

from typing import Optional
import asyncio

with workflow.unsafe.imports_passed_through():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is unsafe.imports_passed_through required here?

)

@workflow.run
async def run(self, user_request: str, approval_timeout_seconds: int = 300) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: put @workflow.run at the top of the class because it is the entrypoint.

# Step 1: AI analyzes the request and proposes an action
proposed_action = await self._analyze_and_propose_action(user_request)

workflow.logger.info(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this logging valuable or is it clutter? How much logging do we want to put in the recipes?

)

# Step 2: Request human approval
approval_result = await self._request_approval(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add logic where the approval is required for transactions above a threshold amount.

reviewer_notes = self.current_decision.reviewer_notes or 'None provided'
return f"Action rejected. Reviewer notes: {reviewer_notes}"

else: # timeout
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check timeout + add final else: with Exception for invalid result.

return timeout_msg

async def _analyze_and_propose_action(self, user_request: str) -> ProposedAction:
"""Use LLM to analyze request and propose an action."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving prompts to a separate file

@@ -0,0 +1 @@
# Activities for human-in-the-loop workflow
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need __init__.py in Python 3.3+. If the file has content it can be ok to put it, but empty ones don't serve a purpose.

@workflow.signal
async def approval_decision(self, decision: ApprovalDecision):
if decision.request_id == self.pending_request_id:
self.approval_decision = decision
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else...

At a minimum, log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants