Metadata-Version: 2.4
Name: pushary-crewai
Version: 0.1.0
Summary: Human-in-the-loop for CrewAI: a BaseTool that asks a real human on their phone and blocks on a fail-closed answer, instead of the console human_input prompt.
Project-URL: Homepage, https://pushary.com
Project-URL: Documentation, https://pushary.com/docs/agents/adapters
Author-email: Pushary <business@pushary.com>
License: MIT
License-File: LICENSE
Keywords: ai-agents,approvals,basetool,crewai,human-in-the-loop
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: crewai<2,>=1.0
Requires-Dist: pushary>=1.3.2
Description-Content-Type: text/markdown

# pushary-crewai

Human-in-the-loop for [CrewAI](https://www.crewai.com). Replace the console
`human_input=True` prompt with a tool that reaches a real person on their phone and
blocks until they answer, fail-closed.

Requires the Pushary [Partner plan](https://pushary.com/agent-notifications-integration).

## Install

```bash
pip install pushary-crewai
```

Set `PUSHARY_API_KEY` (get it in your [dashboard](https://pushary.com/dashboard/settings)).

## Connect a phone once

```python
from pushary_crewai import connect

link = connect("user_123")  # show this to your end-user; one tap connects their phone
```

## Give an agent an ask-human tool

```python
from crewai import Agent, Task, Crew
from pushary_crewai import make_ask_human_tool

agent = Agent(
    role="Ops",
    goal="Ship safely",
    backstory="Careful operator.",
    tools=[make_ask_human_tool("user_123")],
)
task = Task(
    description="Draft the release. Before finalizing, call ask_human to get approval.",
    expected_output="approved release notes",
    agent=agent,
)
Crew(agents=[agent], tasks=[task]).kickoff()
```

The tool blocks until the person answers and returns a fail-closed instruction. The
`external_id` is bound when you build the tool, never taken from the model, so a
prompt-injected agent cannot ask the wrong person.

## Lower-level helpers

```python
from pushary_crewai import ask_human

d = ask_human("Approve this refund?", external_id="user_123", type="confirm")
if d["approved"]:
    issue_refund()
```

## API

- `connect(external_id, *, api_key=None, base_url=None)` — enroll an end-user's phone.
- `make_ask_human_tool(external_id, *, name=..., ...)` — a CrewAI `BaseTool` bound to that user.
- `ask_human(question, *, external_id, type="confirm", ...)` — blocking, returns the decision dict.
- `resolve_pushary_callback(raw_body, signature, secret)` — verify + parse a callback for a durable path.
- `describe_answer(type, result)`, `is_affirmative(answer)`, `deterministic_key(parts)`, `SIGNATURE_HEADER`.

## License

MIT
