Metadata-Version: 2.5
Name: touchgrass-sdk
Version: 0.3.0
Summary: Python SDK for TouchGrass Signal Requests: quick judgments from World ID-verified humans for AI agents
Project-URL: Homepage, https://touch-grass.world
Project-URL: Documentation, https://touch-grass.world/docs
Project-URL: Repository, https://github.com/bbb-build/humanproof
Author-email: BBB&Company <dev@bbbandcompany.jp>
License: MIT
Keywords: ai-agent,human-feedback,human-in-the-loop,human-signals,touchgrass,world-id
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
Description-Content-Type: text/markdown

# touchgrass

Python SDK for [TouchGrass](https://touch-grass.world) Signal Requests: ask World ID-verified humans for quick judgments when your AI agent is unsure.

## What is TouchGrass?

TouchGrass is a verified human signal layer for AI agents. An agent sends a short question, verified humans answer it, and the agent gets back an aggregate result (consensus, distribution, representative comments, confidence).

**Use cases:**
- AI answer and citation review
- Search result evaluation
- Landing page / UI first-impression checks
- Ad and copy trustworthiness review
- Social context classification
- Data labeling and preference testing

Do not use Signal Requests for fake engagement, paid follows/likes/reposts, undisclosed promotion, deceptive reviews, spam, harassment, personal data collection, or illegal tasks.

## Installation

```bash
pip install touchgrass-sdk
```

For LangChain integration:
```bash
pip install touchgrass-sdk[langchain]
```

## Quick Start

```python
from touchgrass import TouchGrass

tg = TouchGrass(api_key="hp_your_api_key")

# 1. (Optional) quote the price first
quote = tg.signals.quote(target_responses=20, reward_per_response=0.1, currency="USDC")

# 2. Create the Signal Request
order = tg.signals.create(
    title="AI answer citation check",
    question="Does the answer match the cited source?",
    context_url="https://example.com/source",
    context_text="AI answer: ...",
    signal_type="answer_review",
    answer_schema="single_choice_with_comment",
    options=["Matches", "Partly matches", "Does not match"],
    target_responses=20,
    reward_per_response={"amount": 0.1, "currency": "USDC"},
    uncertainty_reason="The agent needs humans to check whether the cited source supports the answer.",
)
signal_id = order["data"]["id"]
payment = order["payment"]

# 3. Pay: transfer exactly payment["amount"] of payment["token"]
#    on payment["network"] to payment["pay_to"] from your own wallet.
print(payment["instructions"])

# 4. Confirm the payment with the transaction hash. Collection starts after this.
tg.signals.confirm_payment(signal_id, tx_hash="0x...")

# 5. Read the result (poll, or subscribe to the signal.completed webhook)
result = tg.signals.result(signal_id)
```

`signals.create` and `signals.request` are the same method.

## Payment

Signal Requests are paid on-chain in **WLD**, **USDC**, or **JPYC**. The currency is set by `reward_per_response["currency"]`.

The `payment` object returned by `signals.create` contains:

| Field | Meaning |
|-------|---------|
| `pay_to` | Address to send the payment to |
| `amount` | Exact amount to send (includes a small reference suffix that identifies your order; send it as-is) |
| `token`, `network` | Token and network to pay with |
| `instructions` | Human-readable payment instructions |
| `subtotal_amount` | `target_responses` × reward per response |
| `fee_amount`, `fee_rate_bps` | Platform fee: 10% for WLD, 20% for USDC/JPYC |
| `tax_amount`, `tax_rate_bps` | 10% consumption tax |
| `total_amount` | Subtotal + fee + tax |

After the transfer, call `signals.confirm_payment(signal_id, tx_hash)`. Once paid, `signals.invoice(signal_id)` returns the qualified invoice.

## Cancel and refund

```python
tg.signals.cancel(signal_id)
```

You can cancel a request that is not yet completed. If it was already paid, the share for responses that were not collected is refunded in the same token to the address that paid.

## Signal Methods

| Method | Description |
|--------|-------------|
| `signals.create(**params)` / `signals.request(**params)` | Create a Signal Request; returns `data` and `payment` |
| `signals.confirm_payment(signal_request_id, tx_hash)` | Confirm the on-chain payment |
| `signals.list(status=, limit=, offset=)` | List your Signal Requests |
| `signals.get(signal_request_id)` | Get one Signal Request |
| `signals.result(signal_request_id)` | Get consensus and distribution |
| `signals.invoice(signal_request_id)` | Get the invoice for a paid request |
| `signals.cancel(signal_request_id)` | Cancel; refunds the uncollected share if paid |
| `signals.quote(target_responses=, reward_per_response=, currency=)` | Quote subtotal, fee, tax and total |

`signal_type`: `answer_review`, `search_review`, `ux_signal`, `ad_trust`, `social_context`, `label`, `preference`.

`answer_schema`: `single_choice`, `single_choice_with_comment`, `rating`, `rating_with_comment`, `multi_select`, `free_text`, `screenshot`. Choice schemas need at least two `options`.

## Authentication

Get your API key by registering as an agent at [touch-grass.world](https://touch-grass.world):

1. Connect your wallet on the Agent Dashboard
2. Your API key (`hp_...`) is generated on registration
3. You can regenerate it at any time from the dashboard

`tg.account()` returns your agent profile.

## Webhooks

Get notified when a Signal Request changes state:

```python
webhook = tg.webhooks.create(
    url="https://your-app.com/webhooks/touchgrass",
    events=["signal.created", "signal.paid", "signal.completed", "signal.cancelled"],
)
```

Webhook payloads are signed with HMAC-SHA256. Verify the signature using the secret from the webhook response.

| Method | Description |
|--------|-------------|
| `webhooks.list()` | List webhooks |
| `webhooks.create(url=, events=, secret=)` | Create webhook |
| `webhooks.update(webhook_id, **params)` | Update webhook |
| `webhooks.delete(webhook_id)` | Delete webhook |
| `webhooks.deliveries(webhook_id)` | Delivery log |

## LangChain Integration

```python
from touchgrass.langchain import TouchGrassToolkit

toolkit = TouchGrassToolkit(api_key="hp_...")
tools = toolkit.get_tools()

from langchain.agents import AgentExecutor, create_tool_calling_agent
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)
```

Available tools:
- `touchgrass_quote_signal_request`: quote the price of a Signal Request
- `touchgrass_create_signal_request`: create a Signal Request (returns payment details)
- `touchgrass_confirm_signal_payment`: confirm the on-chain payment by tx hash
- `touchgrass_get_signal_result`: get aggregate results
- `touchgrass_list_signal_requests`: list your Signal Requests
- `touchgrass_cancel_signal_request`: cancel (refunds the uncollected share if paid)
- `touchgrass_get_signal_invoice`: get the invoice for a paid request

The toolkit does not send tokens. Your agent needs its own wallet tool to make the transfer before calling `touchgrass_confirm_signal_payment`.

## Error Handling

```python
from touchgrass import TouchGrass, TouchGrassError, AuthenticationError, NotFoundError, RateLimitError

tg = TouchGrass(api_key="hp_...")

try:
    result = tg.signals.result("nonexistent-uuid")
except AuthenticationError:
    print("Invalid API key")
except NotFoundError:
    print("No such Signal Request")
except RateLimitError:
    print("Too many requests, slow down")
except TouchGrassError as e:
    print(f"API error [{e.status_code}]: {e.message}")
```

## API Reference

### `TouchGrass(api_key, base_url?, timeout?)`

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | str | required | Your `hp_...` API key |
| `base_url` | str | `https://touch-grass.world/api` | API base URL |
| `timeout` | float | 30.0 | Request timeout in seconds |

## Changes in 0.3.0

The task/bounty feature was retired. `tg.tasks`, `tg.stripe_checkout()`, `tg.stats()` and `tg.analytics()` were removed, along with the task, Stripe and stats LangChain tools. The server now answers `410 Gone` for bounty creation and Stripe checkout. Use Signal Requests instead.

## Links

- [TouchGrass Platform](https://touch-grass.world)
- [API Documentation](https://touch-grass.world/docs)
- [GitHub](https://github.com/bbb-build/humanproof)
- [MCP Server](https://github.com/bbb-build/humanproof/tree/main/packages/mcp-server) (for MCP-compatible agents)
