refactor: store cron origin delivery context

This commit is contained in:
chengyongru
2026-06-12 15:07:25 +08:00
parent b232a52794
commit 5ae907bc2f
10 changed files with 171 additions and 96 deletions
+22
View File
@@ -138,6 +138,19 @@ class CronService:
or {}
),
session_key=j["payload"].get("sessionKey") or j["payload"].get("session_key"),
origin_channel=(
j["payload"].get("originChannel")
or j["payload"].get("origin_channel")
),
origin_chat_id=(
j["payload"].get("originChatId")
or j["payload"].get("origin_chat_id")
),
origin_metadata=(
j["payload"].get("originMetadata")
or j["payload"].get("origin_metadata")
or {}
),
),
state=CronJobState(
next_run_at_ms=j.get("state", {}).get("nextRunAtMs"),
@@ -268,6 +281,9 @@ class CronService:
"to": j.payload.to,
"channelMeta": j.payload.channel_meta,
"sessionKey": j.payload.session_key,
"originChannel": j.payload.origin_channel,
"originChatId": j.payload.origin_chat_id,
"originMetadata": j.payload.origin_metadata,
},
"state": {
"nextRunAtMs": j.state.next_run_at_ms,
@@ -524,6 +540,9 @@ class CronService:
delete_after_run: bool = False,
channel_meta: dict | None = None,
session_key: str | None = None,
origin_channel: str | None = None,
origin_chat_id: str | None = None,
origin_metadata: dict | None = None,
) -> CronJob:
"""Add a new job."""
_validate_schedule_for_add(schedule)
@@ -542,6 +561,9 @@ class CronService:
to=to,
channel_meta=channel_meta or {},
session_key=session_key,
origin_channel=origin_channel,
origin_chat_id=origin_chat_id,
origin_metadata=origin_metadata or {},
),
state=CronJobState(next_run_at_ms=_compute_next_run(schedule, now)),
created_at_ms=now,
+7 -49
View File
@@ -4,54 +4,12 @@ from __future__ import annotations
from typing import Any
from nanobot.cron.types import CronJob
def bound_session_inbound_context(session_key: str) -> tuple[str, str, dict[str, Any]]:
"""Return ``(channel, chat_id, metadata)`` for a bound cron session key."""
if ":" not in session_key:
raise ValueError(f"bound cron session_key is invalid: {session_key!r}")
channel, rest = session_key.split(":", 1)
if not channel or not rest:
raise ValueError(f"bound cron session_key is invalid: {session_key!r}")
metadata: dict[str, Any] = {}
if channel == "discord" and ":thread:" in rest:
parent_channel_id, thread_id = rest.split(":thread:", 1)
if parent_channel_id and thread_id:
metadata.update({
"context_chat_id": parent_channel_id,
"parent_channel_id": parent_channel_id,
"thread_id": thread_id,
})
return channel, thread_id, metadata
if channel == "feishu" and ":" in rest:
chat_id, thread_id = rest.split(":", 1)
if chat_id and thread_id:
metadata.update({
"chat_type": "group",
"message_id": thread_id,
"thread_id": thread_id,
})
return channel, chat_id, metadata
if channel == "slack" and ":" in rest:
chat_id, thread_ts = rest.split(":", 1)
if thread_ts:
metadata["slack"] = {"thread_ts": thread_ts}
return channel, chat_id, metadata
if channel == "telegram" and ":topic:" in rest:
chat_id, thread_id = rest.split(":topic:", 1)
if thread_id:
metadata["message_thread_id"] = (
int(thread_id) if thread_id.isdigit() else thread_id
)
return channel, chat_id, metadata
if channel == "dingtalk" and rest.startswith("group:"):
parts = rest.split(":", 2)
if len(parts) >= 2 and parts[1]:
return channel, f"group:{parts[1]}", metadata
return channel, rest, metadata
def origin_delivery_context(job: CronJob) -> tuple[str, str, dict[str, Any]]:
"""Return ``(channel, chat_id, metadata)`` for a session-bound cron job."""
payload = job.payload
if not payload.origin_channel or not payload.origin_chat_id:
raise ValueError(f"cron job {job.id} is missing origin delivery context")
return payload.origin_channel, payload.origin_chat_id, dict(payload.origin_metadata or {})
+6 -3
View File
@@ -1,7 +1,7 @@
"""Cron types."""
from dataclasses import dataclass, field
from typing import Literal
from typing import Any, Literal
@dataclass
@@ -23,12 +23,15 @@ class CronPayload:
"""What to do when the job runs."""
kind: Literal["system_event", "agent_turn"] = "agent_turn"
message: str = ""
# Deliver response to channel
# Legacy delivery fields used by pre-session-bound cron jobs.
deliver: bool = False
channel: str | None = None # e.g. "whatsapp"
to: str | None = None # e.g. phone number
channel_meta: dict = field(default_factory=dict) # channel-specific routing (e.g. Slack thread_ts)
channel_meta: dict[str, Any] = field(default_factory=dict)
session_key: str | None = None # original session key for correct session recording
origin_channel: str | None = None
origin_chat_id: str | None = None
origin_metadata: dict[str, Any] = field(default_factory=dict)
@dataclass