mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 00:40:45 +08:00
Productize scheduled success delivery, close WA pending, and clarify SQL scope grants.
Wrap successful scheduled jobs with a short WA header (+ attachment count), expire stale access pending and DM requesters on admin approve/deny, and add concrete next_steps for insufficient_scope:sql:query. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
dff8901ae3
commit
4898adf7d0
10 changed files with 334 additions and 12 deletions
|
|
@ -7,8 +7,12 @@ from pathlib import Path
|
|||
from unittest.mock import patch
|
||||
|
||||
from runtime.extensions.whatsapp.access_control import denied_reply_text
|
||||
from runtime.scheduler.turn_text import format_scheduled_failure_summary, format_scheduled_user_reminder
|
||||
from runtime.scheduler.worker_turn import finalize_scheduled_turn_failure
|
||||
from runtime.scheduler.turn_text import (
|
||||
format_scheduled_failure_summary,
|
||||
format_scheduled_success_summary,
|
||||
format_scheduled_user_reminder,
|
||||
)
|
||||
from runtime.scheduler.worker_turn import finalize_scheduled_turn_failure, finalize_scheduled_turn_success
|
||||
from svc.persistence.sqlite_store import SqliteStore
|
||||
|
||||
|
||||
|
|
@ -24,6 +28,18 @@ class ScheduledFailureTextTests(unittest.TestCase):
|
|||
self.assertIn("TimeoutError", text)
|
||||
self.assertNotIn("定时", text)
|
||||
|
||||
def test_success_summary_wraps_body_and_attachments(self) -> None:
|
||||
text = format_scheduled_success_summary(
|
||||
job_name="Bandwidth watch",
|
||||
reply_text="Critical: 3\nMajor: 1",
|
||||
attachment_count=1,
|
||||
lang="en",
|
||||
)
|
||||
self.assertIn("[Scheduled job done]", text)
|
||||
self.assertIn("Bandwidth watch", text)
|
||||
self.assertIn("Attachments: 1", text)
|
||||
self.assertIn("Critical: 3", text)
|
||||
|
||||
def test_reminder_fallback_english(self) -> None:
|
||||
self.assertIn("Reminder", format_scheduled_user_reminder("stretch", lang="en"))
|
||||
self.assertIn("提醒", format_scheduled_user_reminder("活动一下", lang="zh"))
|
||||
|
|
@ -101,6 +117,56 @@ class ScheduledFailureDeliveryTests(unittest.TestCase):
|
|||
updated = self.store.scheduled_job_run_get(run_id=str(run.id), tenant_id=self.tenant_id)
|
||||
self.assertEqual(str(getattr(updated, "status", "") or ""), "failed")
|
||||
|
||||
def test_finalize_success_enqueues_wrapped_summary(self) -> None:
|
||||
job = self.store.scheduled_job_create(
|
||||
tenant_id=self.tenant_id,
|
||||
created_by_user_id=self.user_id,
|
||||
name="License daily",
|
||||
prompt_text="license report",
|
||||
schedule_kind="cron",
|
||||
schedule_expr="0 11 * * *",
|
||||
lang="en",
|
||||
delivery={
|
||||
"whatsapp": {
|
||||
"enabled": True,
|
||||
"target_type": "group",
|
||||
"chat_id": "120363011111111111@g.us",
|
||||
"account_id": "wa-default",
|
||||
}
|
||||
},
|
||||
timezone_name="UTC",
|
||||
status="active",
|
||||
)
|
||||
run = self.store.scheduled_job_run_create(
|
||||
job_id=str(job.id),
|
||||
tenant_id=self.tenant_id,
|
||||
scheduled_at="2026-08-10T00:00:00+00:00",
|
||||
)
|
||||
payload = {
|
||||
"tenant_id": self.tenant_id,
|
||||
"job_id": str(job.id),
|
||||
"run_id_scheduled": str(run.id),
|
||||
"lang": "en",
|
||||
"resolved_channel": "whatsapp",
|
||||
"resolved_chat_id": "120363011111111111@g.us",
|
||||
"resolved_account_id": "wa-default",
|
||||
"session_id": "",
|
||||
}
|
||||
finalize_scheduled_turn_success(
|
||||
self.store,
|
||||
task=None,
|
||||
payload=payload,
|
||||
base_result={"reply_text": "Found 2 license alarms.", "turn_uuid": "tu1"},
|
||||
)
|
||||
pending = self.store.list_pending_channel_outbound_messages(
|
||||
channel="whatsapp", account_id="wa-default", limit=5
|
||||
)
|
||||
self.assertEqual(len(pending), 1)
|
||||
body = str(pending[0].get("text") or "")
|
||||
self.assertIn("[Scheduled job done]", body)
|
||||
self.assertIn("License daily", body)
|
||||
self.assertIn("Found 2 license alarms.", body)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ def test_enrich_mcp_scope_sql() -> None:
|
|||
assert out["required_scope"] == "sql:query"
|
||||
assert "fallback_tools" in out
|
||||
assert "ume_alarm_xlsx_report" in out["fallback_tools"]
|
||||
assert out.get("next_steps")
|
||||
assert out.get("admin_action", {}).get("required_scope") == "sql:query"
|
||||
assert "Admin" in str(out.get("user_facing_hint") or "")
|
||||
|
||||
|
||||
def test_build_finalize_system_suffix() -> None:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,36 @@ def test_access_granted_guide_includes_ops_help() -> None:
|
|||
assert "YES" in text or "continue" in text.lower()
|
||||
|
||||
|
||||
def test_expire_stale_whatsapp_access_pending(tmp_path) -> None:
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from svc.persistence.sqlite_store import SqliteStore
|
||||
|
||||
store = SqliteStore(str(tmp_path / "exp.sqlite"))
|
||||
tenant = store.create_tenant("T")
|
||||
tid = str(tenant["id"])
|
||||
aid = "wa-default"
|
||||
old_id = store.create_whatsapp_access_pending(
|
||||
tenant_id=tid,
|
||||
account_id=aid,
|
||||
external_user_id="8611111111111@s.whatsapp.net",
|
||||
phone="8611111111111",
|
||||
request_text="hi",
|
||||
)
|
||||
assert old_id
|
||||
# Backdate created_at beyond 7 days.
|
||||
old_ts = (datetime.now(timezone.utc) - timedelta(days=10)).isoformat()
|
||||
with store._connect() as conn: # noqa: SLF001
|
||||
conn.execute(
|
||||
"UPDATE whatsapp_access_pending SET created_at = ? WHERE id = ?",
|
||||
(old_ts, old_id),
|
||||
)
|
||||
n = store.expire_stale_whatsapp_access_pending(tenant_id=tid, account_id=aid, older_than_hours=168)
|
||||
assert n == 1
|
||||
row = store.get_whatsapp_access_pending_by_id(pending_id=str(old_id))
|
||||
assert row and str(row.get("status") or "") == "dismissed"
|
||||
|
||||
|
||||
def test_menu_text_whatsapp_not_productivity_chinese() -> None:
|
||||
text = _menu_text(channel="whatsapp")
|
||||
assert "记待办" not in text
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue