feat(nostr adapter): 新增Nostr会话处理和线程模拟工具
新增两个文件实现Nostr适配器的基础工具能力: 1. session.py:实现聊天ID、线程键、代理路由的解析与目标标准化 2. thread_simulator.py:实现Nostr事件线程链构建、标签解析和事件缓存获取功能
This commit is contained in:
parent
7002557cf4
commit
b44aa607e0
31
backend/package/yuxi/channels/adapters/nostr/session.py
Normal file
31
backend/package/yuxi/channels/adapters/nostr/session.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from yuxi.channels.models import ChannelMessage
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_thread_key(message: ChannelMessage) -> str:
|
||||||
|
identity = message.identity
|
||||||
|
chat_id = identity.channel_chat_id
|
||||||
|
|
||||||
|
if chat_id.startswith("dm:"):
|
||||||
|
pubkey = chat_id.removeprefix("dm:")
|
||||||
|
return f"nostr:dm:{pubkey}"
|
||||||
|
if chat_id.startswith("channel:"):
|
||||||
|
channel = chat_id.removeprefix("channel:")
|
||||||
|
return f"nostr:channel:{channel}"
|
||||||
|
return f"nostr:unknown:{chat_id}"
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_chat_id(message: ChannelMessage) -> str:
|
||||||
|
return message.identity.channel_chat_id
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_agent_route(message: ChannelMessage, default_agent_id: str = "default") -> str:
|
||||||
|
thread_key = resolve_thread_key(message)
|
||||||
|
return f"agent:{default_agent_id}:{thread_key}"
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_target(target: str) -> str:
|
||||||
|
if target.startswith("nostr:"):
|
||||||
|
return target
|
||||||
|
return f"nostr:{target}"
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class NostrThreadSimulator:
|
||||||
|
def __init__(self, relay_pool: Any = None, max_depth: int = 10):
|
||||||
|
self._relay_pool = relay_pool
|
||||||
|
self._event_cache: dict[str, dict] = {}
|
||||||
|
self._reply_chains: dict[str, list[str]] = {}
|
||||||
|
self._max_depth = max_depth
|
||||||
|
|
||||||
|
async def build_thread_from_event(self, event: dict) -> list[dict]:
|
||||||
|
chain: list[dict] = []
|
||||||
|
current = event
|
||||||
|
|
||||||
|
for _ in range(self._max_depth):
|
||||||
|
chain.append(current)
|
||||||
|
parent_id = self._get_parent_event_id(current)
|
||||||
|
if not parent_id:
|
||||||
|
break
|
||||||
|
parent = await self._fetch_event(parent_id)
|
||||||
|
if not parent:
|
||||||
|
break
|
||||||
|
current = parent
|
||||||
|
|
||||||
|
return list(reversed(chain))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_parent_event_id(event: dict) -> str | None:
|
||||||
|
tags: list[list[str]] = event.get("tags", [])
|
||||||
|
for tag in tags:
|
||||||
|
if tag[0] == "e":
|
||||||
|
if len(tag) >= 4 and tag[3] == "reply":
|
||||||
|
return tag[1]
|
||||||
|
if len(tag) >= 2:
|
||||||
|
return tag[1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_e_tags(event: dict) -> list[str]:
|
||||||
|
tags: list[list[str]] = event.get("tags", [])
|
||||||
|
return [tag[1] for tag in tags if tag[0] == "e" and len(tag) > 1]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_p_tags(event: dict) -> list[str]:
|
||||||
|
tags: list[list[str]] = event.get("tags", [])
|
||||||
|
return [tag[1] for tag in tags if tag[0] == "p" and len(tag) > 1]
|
||||||
|
|
||||||
|
def _is_root_event(self, event: dict) -> bool:
|
||||||
|
tags: list[list[str]] = event.get("tags", [])
|
||||||
|
for tag in tags:
|
||||||
|
if tag[0] == "e" and len(tag) >= 4 and tag[3] == "root":
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def _fetch_event(self, event_id: str) -> dict | None:
|
||||||
|
if event_id in self._event_cache:
|
||||||
|
return self._event_cache[event_id]
|
||||||
|
|
||||||
|
if self._relay_pool:
|
||||||
|
try:
|
||||||
|
event = await self._relay_pool.query_event(event_id)
|
||||||
|
if event:
|
||||||
|
self._event_cache[event_id] = event
|
||||||
|
return event
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
Loading…
Reference in New Issue
Block a user