refactor: store cron origin delivery context
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 {})
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user