Metadata-Version: 2.5
Name: pushary-crewai
Version: 0.3.1
Summary: Phone approvals for CrewAI agents. Your agent asks, your user taps Approve or Deny.
Project-URL: Homepage, https://pushary.com/human-in-the-loop-crewai
Project-URL: Repository, https://github.com/Pushary/pushary-crewai
Project-URL: Documentation, https://pushary.com/docs/agents/adapters
Author-email: Pushary <business@pushary.com>
License: MIT
License-File: LICENSE
Keywords: ai-agents,approval,approvals,basetool,crewai,human-in-the-loop,tool-approval
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<3,>=2.0.0
Description-Content-Type: text/markdown

# pushary-crewai

Phone approvals for CrewAI agents. Your agent asks, your user taps Approve or Deny.

[Full walkthrough: Human-in-the-loop for CrewAI](https://pushary.com/human-in-the-loop-crewai?utm_source=github&utm_medium=oss-adapter&utm_campaign=pushary-crewai&utm_content=readme)

[![CI](https://github.com/Pushary/pushary-crewai/actions/workflows/ci.yml/badge.svg)](https://github.com/Pushary/pushary-crewai/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/pushary-crewai)](https://pypi.org/project/pushary-crewai/)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

## What you need

- A Pushary Partner plan, from $99 a month. [Start the trial](https://pushary.com/sign-up?from=agent&plan=partner&utm_source=github&utm_medium=oss-adapter&utm_campaign=pushary-crewai&utm_content=partner-start).
- An API key from [Partner onboarding](https://pushary.com/onboarding/partner), set as `PUSHARY_API_KEY`.
- Your users install the free Pushary app ([iPhone](https://apps.apple.com/us/app/pushary/id6785677563), [Android](https://play.google.com/store/apps/details?id=com.pushary.app)). They never sign up or pay.

## Quick start

```bash
pip install pushary-crewai
export PUSHARY_API_KEY=pk_xxx.sk_xxx
```

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

link = connect("user_123")  # once per user: show them this link

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()
```

This replaces the console `human_input=True` prompt. The tool waits until the person
answers on their phone. A no, or no answer, tells the agent not to proceed. 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.

CrewAI's own docs on this: [Human feedback in Flows](https://docs.crewai.com/en/learn/human-feedback-in-flows).

## 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`.

## Example

The [basic example](examples/basic.py) gives an agent a blocking ask-human tool.

The [Flow example](examples/flow_feedback.py) uses CrewAI's native
`@human_feedback(provider=...)` path. It creates a Pushary decision, saves the
pending Flow, and exits. A later command reads the decision from Pushary and
resumes the same Flow. No model key or open worker is needed. Tested with
`crewai==1.15.22` and `pushary==2.1.1`.

```bash
python -m pip install -e . 'crewai==1.15.22'
export PUSHARY_API_KEY='your Partner server key'
export PUSHARY_EXTERNAL_ID='your enrolled customer ID'
export CREWAI_STORAGE_DIR="$(mktemp -d)"
python examples/flow_feedback.py start 'Send the release note'
# Answer on the connected phone. Copy flow_id and decision_id from the output.
python examples/flow_feedback.py resume FLOW_ID DECISION_ID \
  --database "$CREWAI_STORAGE_DIR/resumes.sqlite"
```

Keep `CREWAI_STORAGE_DIR` and the resume database across processes. A pending
decision returns `pending`; a decline or expiry returns `approved: false`.
The example checks the decision ID, exact question, Flow, and recipient before
resuming. Its SQLite claim prevents two local workers from resuming the same
Flow concurrently; a failed or interrupted resume stays claimed for manual
inspection. Use shared transactional storage across hosts.

The Flow only returns the review result. If you attach a business action,
bind its exact arguments and recipient in your application, and make the
action idempotent. Do not treat a model's approval claim or a direct call to
`flow.resume()` as authorization.

## License

MIT
