Add "automation underway" and "error" ClickUp statuses for bot visibility
Tasks now show "automation underway" when the bot picks them up and "error" on failure, replacing the old "in progress" / "to do" fallbacks that were invisible on Bryan's ClickUp board. Folder watcher also syncs ClickUp status on match, missing IMSURL, pipeline failure, success, and exceptions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>cora-start
parent
62186d8dec
commit
3f2798d338
|
|
@ -44,6 +44,8 @@ class ClickUpConfig:
|
|||
poll_statuses: list[str] = field(default_factory=lambda: ["to do"])
|
||||
review_status: str = "internal review"
|
||||
in_progress_status: str = "in progress"
|
||||
automation_status: str = "automation underway"
|
||||
error_status: str = "error"
|
||||
task_type_field_name: str = "Work Category"
|
||||
default_auto_execute: bool = False
|
||||
skill_map: dict = field(default_factory=dict)
|
||||
|
|
|
|||
|
|
@ -339,8 +339,8 @@ class Scheduler:
|
|||
"custom_fields": task.custom_fields,
|
||||
}
|
||||
|
||||
# Move to "in progress" on ClickUp immediately
|
||||
client.update_task_status(task_id, self.config.clickup.in_progress_status)
|
||||
# Move to "automation underway" on ClickUp immediately
|
||||
client.update_task_status(task_id, self.config.clickup.automation_status)
|
||||
self.db.kv_set(kv_key, json.dumps(state))
|
||||
|
||||
log.info("Executing ClickUp task: %s → %s", task.name, tool_name)
|
||||
|
|
@ -371,8 +371,8 @@ class Scheduler:
|
|||
task_id,
|
||||
f"⚠️ CheddahBot could not execute this task.\n\n{result[:2000]}",
|
||||
)
|
||||
# Move back to "to do" so it can be retried
|
||||
client.update_task_status(task_id, "to do")
|
||||
# Move to "error" so Bryan can see what happened
|
||||
client.update_task_status(task_id, self.config.clickup.error_status)
|
||||
|
||||
self._notify(
|
||||
f"ClickUp task skipped: **{task.name}**\n"
|
||||
|
|
@ -428,8 +428,8 @@ class Scheduler:
|
|||
client.add_comment(
|
||||
task_id, f"❌ CheddahBot failed to complete this task.\n\nError: {str(e)[:2000]}"
|
||||
)
|
||||
# Move back to "to do" so it can be retried after reset
|
||||
client.update_task_status(task_id, "to do")
|
||||
# Move to "error" so Bryan can see what happened
|
||||
client.update_task_status(task_id, self.config.clickup.error_status)
|
||||
|
||||
self._notify(
|
||||
f"ClickUp task failed: **{task.name}**\n"
|
||||
|
|
@ -547,6 +547,11 @@ class Scheduler:
|
|||
# Extract tool args from matched task
|
||||
task_id = matched_task.id
|
||||
log.info("Matched '%s' to ClickUp task %s (%s)", filename, task_id, matched_task.name)
|
||||
|
||||
# Set ClickUp status to "automation underway"
|
||||
client = self._get_clickup_client()
|
||||
client.update_task_status(task_id, self.config.clickup.automation_status)
|
||||
|
||||
self._notify(
|
||||
f"Folder watcher: matched **{filename}** to ClickUp task **{matched_task.name}**.\n"
|
||||
f"Starting Cora Backlinks pipeline...",
|
||||
|
|
@ -570,6 +575,8 @@ class Scheduler:
|
|||
}
|
||||
),
|
||||
)
|
||||
# Set ClickUp status to "error" so it's visible on the board
|
||||
client.update_task_status(task_id, self.config.clickup.error_status)
|
||||
self._notify(
|
||||
f"Folder watcher: **{filename}** matched task **{matched_task.name}** "
|
||||
f"but **IMSURL is empty**. Set the IMSURL field in ClickUp before "
|
||||
|
|
@ -614,6 +621,7 @@ class Scheduler:
|
|||
}
|
||||
),
|
||||
)
|
||||
client.update_task_status(task_id, self.config.clickup.error_status)
|
||||
self._notify(
|
||||
f"Folder watcher: pipeline **failed** for **{filename}**.\n"
|
||||
f"Error: {result[:200]}",
|
||||
|
|
@ -641,6 +649,7 @@ class Scheduler:
|
|||
}
|
||||
),
|
||||
)
|
||||
client.update_task_status(task_id, self.config.clickup.review_status)
|
||||
self._notify(
|
||||
f"Folder watcher: pipeline **completed** for **{filename}**.\n"
|
||||
f"ClickUp task: {matched_task.name}",
|
||||
|
|
@ -661,6 +670,7 @@ class Scheduler:
|
|||
}
|
||||
),
|
||||
)
|
||||
client.update_task_status(task_id, self.config.clickup.error_status)
|
||||
|
||||
def _match_xlsx_to_clickup(self, normalized_stem: str):
|
||||
"""Find a ClickUp Link Building task whose Keyword matches the file stem.
|
||||
|
|
|
|||
|
|
@ -275,11 +275,11 @@ def _find_clickup_task(ctx: dict, keyword: str) -> str:
|
|||
if db:
|
||||
db.kv_set(f"clickup:task:{task_id}:state", json.dumps(state))
|
||||
|
||||
# Move to "in progress"
|
||||
# Move to "automation underway"
|
||||
cu_client2 = _get_clickup_client(ctx)
|
||||
if cu_client2:
|
||||
try:
|
||||
cu_client2.update_task_status(task_id, config.clickup.in_progress_status)
|
||||
cu_client2.update_task_status(task_id, config.clickup.automation_status)
|
||||
except Exception as e:
|
||||
log.warning("Failed to update ClickUp status for %s: %s", task_id, e)
|
||||
finally:
|
||||
|
|
@ -361,9 +361,7 @@ def _fail_clickup_task(ctx: dict | None, task_id: str, error_msg: str) -> None:
|
|||
return
|
||||
|
||||
config = ctx.get("config")
|
||||
skill_map = config.clickup.skill_map if config else {}
|
||||
lb_map = skill_map.get("Link Building", {})
|
||||
error_status = lb_map.get("error_status", "internal review")
|
||||
error_status = config.clickup.error_status if config else "error"
|
||||
|
||||
db = ctx.get("db")
|
||||
if db:
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@ def _find_clickup_task(ctx: dict, company_name: str) -> str:
|
|||
if db:
|
||||
db.kv_set(f"clickup:task:{task_id}:state", json.dumps(state))
|
||||
|
||||
# Move to "in progress" on ClickUp
|
||||
# Move to "automation underway" on ClickUp
|
||||
cu_client2 = _get_clickup_client(ctx)
|
||||
if cu_client2:
|
||||
try:
|
||||
cu_client2.update_task_status(task_id, config.clickup.in_progress_status)
|
||||
cu_client2.update_task_status(task_id, config.clickup.automation_status)
|
||||
except Exception as e:
|
||||
log.warning("Failed to update ClickUp status for %s: %s", task_id, e)
|
||||
finally:
|
||||
|
|
@ -516,13 +516,13 @@ def write_press_releases(
|
|||
if cu_client:
|
||||
try:
|
||||
config = ctx["config"]
|
||||
cu_client.update_task_status(clickup_task_id, config.clickup.in_progress_status)
|
||||
cu_client.update_task_status(clickup_task_id, config.clickup.automation_status)
|
||||
cu_client.add_comment(
|
||||
clickup_task_id,
|
||||
f"🔄 CheddahBot starting press release creation.\n\n"
|
||||
f"Topic: {topic}\nCompany: {company_name}",
|
||||
)
|
||||
log.info("ClickUp task %s set to in-progress", clickup_task_id)
|
||||
log.info("ClickUp task %s set to automation-underway", clickup_task_id)
|
||||
except Exception as e:
|
||||
log.warning("ClickUp start-sync failed for %s: %s", clickup_task_id, e)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ clickup:
|
|||
poll_statuses: ["to do"]
|
||||
review_status: "internal review"
|
||||
in_progress_status: "in progress"
|
||||
automation_status: "automation underway"
|
||||
error_status: "error"
|
||||
task_type_field_name: "Work Category"
|
||||
default_auto_execute: false
|
||||
skill_map:
|
||||
|
|
@ -60,7 +62,7 @@ clickup:
|
|||
tool: "run_link_building"
|
||||
auto_execute: false
|
||||
complete_status: "complete"
|
||||
error_status: "internal review"
|
||||
error_status: "error"
|
||||
field_mapping:
|
||||
lb_method: "LB Method"
|
||||
project_name: "task_name"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ class _FakeClickUpConfig:
|
|||
poll_statuses: list[str] = field(default_factory=lambda: ["to do"])
|
||||
review_status: str = "internal review"
|
||||
in_progress_status: str = "in progress"
|
||||
automation_status: str = "automation underway"
|
||||
error_status: str = "error"
|
||||
task_type_field_name: str = "Work Category"
|
||||
default_auto_execute: bool = True
|
||||
skill_map: dict = field(default_factory=lambda: {"Press Release": _PR_MAPPING})
|
||||
|
|
@ -220,7 +222,7 @@ class TestExecuteTask:
|
|||
|
||||
mock_client.update_task_status.assert_any_call(
|
||||
"t1",
|
||||
"in progress",
|
||||
"automation underway",
|
||||
)
|
||||
|
||||
raw = tmp_db.kv_get("clickup:task:t1:state")
|
||||
|
|
@ -266,7 +268,7 @@ class TestExecuteTask:
|
|||
assert "output/pr.docx" in state["deliverable_paths"]
|
||||
|
||||
def test_failure_flow(self, tmp_db):
|
||||
"""Failed: state=failed, error comment, back to 'to do'."""
|
||||
"""Failed: state=failed, error comment, status set to 'error'."""
|
||||
config = _FakeConfig()
|
||||
agent = MagicMock()
|
||||
agent._tools = MagicMock()
|
||||
|
|
@ -288,7 +290,7 @@ class TestExecuteTask:
|
|||
)
|
||||
scheduler._execute_task(task)
|
||||
|
||||
mock_client.update_task_status.assert_any_call("t1", "to do")
|
||||
mock_client.update_task_status.assert_any_call("t1", "error")
|
||||
mock_client.add_comment.assert_called_once()
|
||||
comment_text = mock_client.add_comment.call_args[0][1]
|
||||
assert "failed" in comment_text.lower()
|
||||
|
|
|
|||
Loading…
Reference in New Issue