Add clickup_query_tasks tool and Press Advantage API integration plan

New tool queries ClickUp API live for tasks, with optional status and
task_type filters. Fixes the execution brain instantiation bug by
providing a proper @tool wrapper around ClickUpClient.

Also saves the Press Advantage API integration plan for future work
once API access is restored.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cora-start
PeninsulaInd 2026-02-16 13:21:04 -06:00
parent 019bf0ee3c
commit 7153e65ae6
2 changed files with 126 additions and 0 deletions

View File

@ -10,6 +10,20 @@ from . import tool
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def _get_clickup_client(ctx: dict):
"""Create a ClickUpClient from the agent's config."""
from ..clickup import ClickUpClient
cfg = ctx["config"].clickup
if not cfg.api_token:
return None
return ClickUpClient(
api_token=cfg.api_token,
workspace_id=cfg.workspace_id,
task_type_field_name=cfg.task_type_field_name,
)
def _get_clickup_states(db) -> dict[str, dict]: def _get_clickup_states(db) -> dict[str, dict]:
"""Load all tracked ClickUp task states from kv_store.""" """Load all tracked ClickUp task states from kv_store."""
pairs = db.kv_scan("clickup:task:") pairs = db.kv_scan("clickup:task:")
@ -26,6 +40,58 @@ def _get_clickup_states(db) -> dict[str, dict]:
return states return states
@tool(
"clickup_query_tasks",
"Query ClickUp live for tasks. Optionally filter by status (e.g. 'to do', 'in progress') "
"and/or task type (e.g. 'Press Release'). Returns task name, ID, status, type, due date, "
"and custom fields directly from the ClickUp API.",
category="clickup",
)
def clickup_query_tasks(status: str = "", task_type: str = "", ctx: dict = None) -> str:
"""Query ClickUp API for tasks, optionally filtered by status and task type."""
client = _get_clickup_client(ctx)
if not client:
return "Error: ClickUp API token not configured."
cfg = ctx["config"].clickup
if not cfg.space_id:
return "Error: ClickUp space_id not configured."
try:
statuses = [status] if status else None
tasks = client.get_tasks_from_space(cfg.space_id, statuses=statuses)
except Exception as e:
return f"Error querying ClickUp: {e}"
finally:
client.close()
if task_type:
tasks = [t for t in tasks if t.task_type.lower() == task_type.lower()]
if not tasks:
filters = []
if status:
filters.append(f"status='{status}'")
if task_type:
filters.append(f"type='{task_type}'")
filter_str = " with " + ", ".join(filters) if filters else ""
return f"No tasks found{filter_str}."
lines = []
for t in tasks:
parts = [f"**{t.name}** (ID: {t.id})"]
parts.append(f" Status: {t.status} | Type: {t.task_type or ''}")
# Show custom fields that have values
fields = {k: v for k, v in t.custom_fields.items() if v}
if fields:
field_strs = [f"{k}: {v}" for k, v in fields.items()]
parts.append(f" Fields: {', '.join(field_strs)}")
parts.append(f" URL: {t.url}")
lines.append("\n".join(parts))
return f"**ClickUp Tasks ({len(lines)}):**\n\n" + "\n\n".join(lines)
@tool( @tool(
"clickup_list_tasks", "clickup_list_tasks",
"List ClickUp tasks that Cheddah is tracking. Optionally filter by internal state " "List ClickUp tasks that Cheddah is tracking. Optionally filter by internal state "

View File

@ -0,0 +1,60 @@
# Press Advantage API Integration Plan
## Status: Blocked — waiting on PA support to fix API access
API key is in `.env` as `PRESS_ADVANTAGE_API`. Auth works (`api_token` query param) but returns "account is cancelled or past due" on all endpoints. Emailed PA support.
Test release: #81505 (draft)
## Workflow Overview
### Track 1: No Client Approval
1. `write_press_releases` tool generates 2 PRs + schemas (DONE)
2. ClickUp integration saves PRs as attachments + Google Doc (separate work, not CheddahBot)
3. Bryan picks one in chat ("I like PR A")
4. `submit_press_release` tool uploads to Press Advantage via API
5. Done
### Track 2: Client Approval Required
1. `write_press_releases` tool generates 2 PRs + schemas (DONE)
2. ClickUp integration saves PRs as attachments + Google Doc (separate work, not CheddahBot)
3. Bryan picks one, sends to client for review
4. **Waiting period** — auto-generate weekly nag email to Bryan's partner to follow up with client
5. Client approves (comes back in the doc)
6. `submit_press_release` tool uploads to Press Advantage via API
7. Done
## What To Build
### 1. `submit_press_release` tool
- New `@tool` in `cheddahbot/tools/`
- Takes: PR text (or file path), headline, organization_id, distribution type
- Calls `POST /api/customers/releases/with_content.json`
- Params: `release[organization_id]`, `release[title]`, `release[body]`, `release[distribution]`, `release[schedule_distribution]`
- Returns: release ID, status
- Need to figure out org ID mapping (company name → PA org ID)
### 2. Org ID mapping
- `GET /api/customers/organizations.json` lists all orgs with IDs
- Could cache this or add a lookup tool
- Or add PA org IDs to `skills/companies.md`
### 3. Weekly nag emails (Track 2)
- Time-driven, not chat-driven
- Options: CheddahBot heartbeat check, ClickUp automation, or cron
- Needs state tracking: which PRs are awaiting client approval and since when
## API Reference (key endpoints)
| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/api/customers/releases/with_content.json` | POST | Submit finished PR |
| `/api/customers/releases.json` | GET | List all releases |
| `/api/customers/releases/{id}.json` | GET | Get release status |
| `/api/customers/releases/{id}/approve_content.json` | POST | Approve for distribution |
| `/api/customers/releases/{id}/built_urls.json` | GET | Get published URLs |
| `/api/customers/organizations.json` | GET | List orgs (get org IDs) |
## Auth
- Query param: `?api_token=<key>`
- Key stored in `.env` as `PRESS_ADVANTAGE_API`