Skip to content

feat: add explicit HITL decision statuses#2

Open
SeCuReDmE-main-dev wants to merge 1 commit into
feature/haystack-retrieval-confidence-phase2from
feature/haystack-hitl-decision-richness-phase3
Open

feat: add explicit HITL decision statuses#2
SeCuReDmE-main-dev wants to merge 1 commit into
feature/haystack-retrieval-confidence-phase2from
feature/haystack-hitl-decision-richness-phase3

Conversation

@SeCuReDmE-main-dev

Copy link
Copy Markdown
Owner

Summary

  • add explicit approved / modified / rejected statuses to ToolExecutionDecision
  • normalize built-in ConfirmationUIResult actions into explicit HITL decision statuses
  • keep the legacy execute boolean and infer status for older serialized payloads

Compatibility

  • preserves the existing execute field
  • keeps ToolExecutionDecision.from_dict() working for payloads without status
  • does not require agent runtime redesign or deferred/pause semantics

Not included

  • no new governance or guardrail abstractions
  • no router or broader runtime consumption changes
  • no Phase 4 work

Validation

  • .venv\\Scripts\\python.exe -m pytest test/human_in_the_loop/test_dataclasses.py test/human_in_the_loop/test_policies.py test/human_in_the_loop/test_strategies.py -k "not asyncio and not async"
  • .venv\\Scripts\\python.exe -m pytest test/components/agents/test_agent_hitl.py -k "to_dict or from_dict"
  • .venv\\Scripts\\ruff.exe check haystack/human_in_the_loop/dataclasses.py haystack/human_in_the_loop/policies.py haystack/human_in_the_loop/strategies.py test/human_in_the_loop/test_dataclasses.py
  • async smoke test executed directly via .venv\\Scripts\\python.exe because pytest-asyncio is not active in this venv

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a standardized DecisionStatus literal and adds a status field to both ConfirmationUIResult and ToolExecutionDecision to improve the clarity of Human-In-The-Loop (HITL) decisions. The changes include logic to map legacy actions to the new status values and ensure backward compatibility when status fields are missing. Review feedback suggests enhancing the error message for unsupported confirmation actions to aid debugging and improving the robustness of the resolved_status method in ToolExecutionDecision by providing a fallback to the inference logic.

Comment on lines +52 to +54
raise ValueError(
"Unsupported confirmation action. Provide one of 'confirm', 'modify', 'reject' or set 'status' explicitly."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The error message could be more helpful by including the actual unsupported action and listing the valid values for the status field. This assists developers in debugging custom ConfirmationUI implementations.

Suggested change
raise ValueError(
"Unsupported confirmation action. Provide one of 'confirm', 'modify', 'reject' or set 'status' explicitly."
)
raise ValueError(
f"Unsupported confirmation action '{self.action}'. "
"Provide one of 'confirm', 'modify', 'reject' or set 'status' to one of "
"'approved', 'modified', 'rejected' explicitly."
)

Comment on lines +100 to +104
def resolved_status(self) -> DecisionStatus:
"""
Return the normalized decision status for this execution decision.
"""
return self.status

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The resolved_status method currently returns self.status directly. Since self.status is typed as DecisionStatus | None, this could return None if the object was mutated (e.g., via dataclasses.replace) or if __post_init__ was bypassed. To ensure type safety and robustness, it's better to fall back to _infer_status() if self.status is missing.

Suggested change
def resolved_status(self) -> DecisionStatus:
"""
Return the normalized decision status for this execution decision.
"""
return self.status
def resolved_status(self) -> DecisionStatus:
"""
Return the normalized decision status for this execution decision.
"""
return self.status or self._infer_status()

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35656e28f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if self.status is None:
self.status = self._infer_status()
else:
self.execute = self.status != "rejected"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate status before overriding execute

When a ToolExecutionDecision is rebuilt from an external or serialized dict and status is misspelled or from a newer value, for example {'execute': False, 'status': 'reject'}, this branch treats anything other than exactly "rejected" as executable and overwrites execute to True. That fail-open path can run a tool that the caller explicitly marked as not executable, so unknown statuses should be rejected or fall back to the legacy execute value instead of approving execution.

Useful? React with 👍 / 👎.

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.

1 participant