Release beta 2.0.0.1021
check / local-gate (push) Failing after 1m38s

This commit is contained in:
JWeBot Contributors
2026-10-21 17:05:09 +08:00
parent 5a3c4fb94c
commit e4365841ed
79 changed files with 1572 additions and 1840 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-config"
version = "1.2.8b1+1019"
version = "2.0.0b1+1021"
description = "Profile-based configuration compiler for JWeBot"
requires-python = ">=3.9"
dependencies = [
@@ -36,4 +36,4 @@ __all__ = [
"write_default_profile",
]
__version__ = "1.2.8b1+1019"
__version__ = "2.0.0b1+1021"
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-extension-host"
version = "1.2.8b1+1019"
version = "2.0.0b1+1021"
description = "Single-release, single-invocation process host for JWeBot extensions"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.2.8b1+1019",
"jwebot-kernel==1.2.8b1+1019",
"jwebot-sdk==2.0.0b1+1021",
"jwebot-kernel==2.0.0b1+1021",
]
[project.scripts]
@@ -16,4 +16,4 @@ __all__ = [
"process_request",
]
__version__ = "1.2.8b1+1019"
__version__ = "2.0.0b1+1021"
+4 -4
View File
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-kernel"
version = "1.2.8b1+1019"
version = "2.0.0b1+1021"
description = "Stable routing and extension authority for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-config==1.2.8b1+1019",
"jwebot-sdk==1.2.8b1+1019",
"jwebot-official-extensions==1.2.8b1+1019",
"jwebot-config==2.0.0b1+1021",
"jwebot-sdk==2.0.0b1+1021",
"jwebot-official-extensions==2.0.0b1+1021",
"tomli>=2; python_version < '3.11'",
]
@@ -107,4 +107,4 @@ __all__ = [
"verify_installed_release_signature",
]
__version__ = "1.2.8b1+1019"
__version__ = "2.0.0b1+1021"
@@ -0,0 +1,248 @@
"""Fail-closed conversation identities for local OCR shadow testing."""
from __future__ import annotations
import hashlib
import json
import os
import re
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Any, Mapping
SHADOW_CONFIG_ENV = "JWEBOT_CONVERSATION_SHADOW_CONFIG"
SHADOW_CONFIG_VERSION = 1
MAX_SHADOW_TARGETS = 8
MAX_EVENT_TEXT = 5_000
CONVERSATION_KEY = re.compile(r"^[a-z0-9][a-z0-9._-]{0,63}$")
TITLE_FINGERPRINT = re.compile(r"^[0-9a-f]{64}$")
class ConversationConfigError(ValueError):
"""Raised when an opt-in shadow conversation registry is invalid."""
class ConversationKind(str, Enum):
GROUP = "group"
DIRECT = "direct"
def _required_text(value: object, *, name: str, limit: int) -> str:
text = str(value or "").strip()
if not text:
raise ConversationConfigError(f"{name} is required")
if len(text) > limit:
raise ConversationConfigError(f"{name} exceeds {limit} characters")
return text
def _trigger_question(text: str, *, bot_mention: str, direct: bool) -> str:
mention_prefix = r"(?:[@@]\s*)?" if direct else r"[@@]\s*"
mention = re.compile(
rf"^\s*{mention_prefix}{re.escape(bot_mention)}"
r"(?:\s*[::,,])?\s*(\S.*)$",
re.IGNORECASE,
)
for line in text.splitlines():
stripped = line.strip()
if direct and stripped.startswith("/"):
return stripped
match = mention.match(line)
if match:
return match.group(1).strip()
return ""
@dataclass(frozen=True)
class ConversationTarget:
"""One explicitly registered title fingerprint in shadow mode."""
key: str
kind: ConversationKind
title_fingerprint: str
sender: str = ""
def __post_init__(self) -> None:
if not CONVERSATION_KEY.fullmatch(self.key):
raise ConversationConfigError("conversation key must be an opaque slug")
if not TITLE_FINGERPRINT.fullmatch(self.title_fingerprint):
raise ConversationConfigError(
"title_fingerprint must be a lowercase SHA-256 digest"
)
if self.kind is ConversationKind.DIRECT:
_required_text(self.sender, name="direct sender", limit=120)
elif self.sender:
raise ConversationConfigError("group targets cannot define a fixed sender")
@classmethod
def from_mapping(cls, value: Mapping[str, Any]) -> "ConversationTarget":
if not isinstance(value, Mapping):
raise ConversationConfigError("conversation target must be an object")
unknown = set(value) - {
"key",
"kind",
"title_fingerprint",
"sender",
}
if unknown:
raise ConversationConfigError("conversation target has unknown fields")
try:
kind = ConversationKind(str(value.get("kind", "")))
except ValueError as error:
raise ConversationConfigError("conversation kind is invalid") from error
return cls(
key=_required_text(value.get("key"), name="conversation key", limit=64),
kind=kind,
title_fingerprint=_required_text(
value.get("title_fingerprint"),
name="title_fingerprint",
limit=64,
).casefold(),
sender=str(value.get("sender", "")).strip(),
)
def question(self, text: str, *, bot_mention: str) -> str:
return _trigger_question(
text,
bot_mention=bot_mention,
direct=self.kind is ConversationKind.DIRECT,
)
@dataclass(frozen=True)
class ShadowConversationRegistry:
"""A registry that can observe but can never authorize delivery."""
enabled: bool = False
targets: tuple[ConversationTarget, ...] = ()
def __post_init__(self) -> None:
keys = [target.key for target in self.targets]
fingerprints = [target.title_fingerprint for target in self.targets]
if len(keys) != len(set(keys)):
raise ConversationConfigError("conversation keys must be unique")
if len(fingerprints) != len(set(fingerprints)):
raise ConversationConfigError("title fingerprints must be unique")
@classmethod
def disabled(cls) -> "ShadowConversationRegistry":
return cls()
@classmethod
def from_mapping(cls, value: Mapping[str, Any]) -> "ShadowConversationRegistry":
if not isinstance(value, Mapping):
raise ConversationConfigError("shadow registry must be an object")
unknown = set(value) - {"format_version", "enabled", "targets"}
if unknown:
raise ConversationConfigError("shadow registry has unknown fields")
if value.get("format_version") != SHADOW_CONFIG_VERSION:
raise ConversationConfigError("unsupported shadow registry version")
enabled = value.get("enabled", False)
if not isinstance(enabled, bool):
raise ConversationConfigError("shadow registry enabled must be boolean")
raw_targets = value.get("targets", [])
if not isinstance(raw_targets, list):
raise ConversationConfigError("shadow registry targets must be a list")
if len(raw_targets) > MAX_SHADOW_TARGETS:
raise ConversationConfigError("shadow registry has too many targets")
targets = tuple(ConversationTarget.from_mapping(item) for item in raw_targets)
if any(target.kind is not ConversationKind.DIRECT for target in targets):
raise ConversationConfigError("shadow registry accepts direct targets only")
return cls(enabled=enabled, targets=targets)
@classmethod
def from_environment(
cls,
environment: Mapping[str, str] | None = None,
) -> "ShadowConversationRegistry":
source = environment if environment is not None else os.environ
raw_path = str(source.get(SHADOW_CONFIG_ENV, "")).strip()
if not raw_path:
return cls.disabled()
path = Path(raw_path).expanduser()
if path.is_symlink() or not path.is_file():
raise ConversationConfigError("shadow registry path must be a regular file")
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as error:
raise ConversationConfigError("shadow registry cannot be read") from error
if not isinstance(value, Mapping):
raise ConversationConfigError("shadow registry must be an object")
return cls.from_mapping(value)
def target_for_fingerprint(
self,
fingerprint: str,
) -> ConversationTarget | None:
if not self.enabled:
return None
normalized = str(fingerprint).casefold()
return next(
(
target
for target in self.targets
if target.title_fingerprint == normalized
),
None,
)
def build_shadow_event(
target: ConversationTarget,
*,
observed_at: str,
text: str,
body_confidence: float,
visual_signature: str,
bot_mention: str,
observed_sender: str = "",
sender_confidence: float = 0.0,
ordinal: int = 0,
) -> dict[str, Any]:
"""Build a non-dispatchable observation for synthetic and shadow tests."""
content = _required_text(text, name="event text", limit=MAX_EVENT_TEXT)
question = target.question(content, bot_mention=bot_mention)
sender = (
target.sender
if target.kind is ConversationKind.DIRECT
else _required_text(observed_sender, name="observed sender", limit=120)
)
effective_sender_confidence = (
1.0
if target.kind is ConversationKind.DIRECT
else max(0.0, min(1.0, float(sender_confidence)))
)
effective_body_confidence = max(0.0, min(1.0, float(body_confidence)))
seed = (
f"{target.key}\n{observed_at}\n{ordinal}\n{visual_signature}\n"
f"{sender}\n{content}"
)
return {
"version": 1,
"event_id": f"shadow-{hashlib.sha256(seed.encode()).hexdigest()[:24]}",
"observed_at": observed_at,
"sender": sender,
"text": content,
"question": question,
"confidence": min(
effective_sender_confidence,
effective_body_confidence,
),
"sender_confidence": effective_sender_confidence,
"body_confidence": effective_body_confidence,
"side": "incoming",
"mention_bot": bool(question),
"group_fingerprint": target.title_fingerprint,
"conversation_key": target.key,
"conversation_kind": target.kind.value,
"source": (
"rapidocr-private-shadow"
if target.kind is ConversationKind.DIRECT
else "rapidocr-group-shadow"
),
"shadow_only": True,
"dispatch_allowed": False,
}
@@ -8009,6 +8009,20 @@ class EdgeApplication:
started = time.monotonic()
event_id = str(event.get("event_id", ""))
group_id = str(event.get("group_fingerprint", ""))
if event.get("shadow_only") or event.get("dispatch_allowed") is False:
self.telemetry.elapsed(
"edge.event.accepted",
started,
status="shadow_ignored",
event_id=event_id,
group_id=group_id,
route="none",
execution_path="none",
)
return {
"status": "ignored",
"reason": "shadow_only",
}
question = event_question(event)
decision = route_question(question)
route = decision.route.value
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-official-extensions"
version = "1.2.8b1+1019"
version = "2.0.0b1+1021"
description = "Reviewed local command adapters and broker implementation for JWeBot"
requires-python = ">=3.9"
dependencies = [
"jwebot-sdk==1.2.8b1+1019",
"jwebot-sdk==2.0.0b1+1021",
]
[tool.setuptools.packages.find]
@@ -90,4 +90,4 @@ __all__ = [
"render_feature_list",
]
__version__ = "1.2.8b1+1019"
__version__ = "2.0.0b1+1021"
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for coin."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'coin'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '抛一枚硬币'
HELP_ENTRIES = ('/翻硬币',)
COMMANDS = ('/翻硬币',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for coin-loan."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'coin-loan'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '贷款'
HELP_ENTRIES = ('/贷款;/还款',)
COMMANDS = ('/贷款', '/借款', '/loan', '/borrow', '/还款', '/repay')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for coin-ranking."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'coin-ranking'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '富榜'
HELP_ENTRIES = ('/大富翁榜',)
COMMANDS = ('/摩拉排行', '/摩拉排行榜', '/金币排行', '/金币排行榜', '/大富翁榜', '/richlist')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for coin-taffy."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'coin-taffy'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = 'Taffy摩拉'
HELP_ENTRIES = ('/Taffy摩拉(兼容 /Taffy金币)',)
COMMANDS = ('/Taffy摩拉', '/Taffy金币', '/taffycoins')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for coin-transfer."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'coin-transfer'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '摩拉转账'
HELP_ENTRIES = ('/转账 对方 金额;/transfer',)
COMMANDS = ('/转账', '/transfer')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for context-summary."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'context-summary'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = '上下文总结'
HELP_ENTRIES = ('/上下文 [100|200|300];/context [100|200|300]',)
COMMANDS = ('/上下文', '/context')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for cs-major-autochess."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'cs-major-autochess'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '自走棋'
HELP_ENTRIES = ('/自走棋 开始|报名|选',)
COMMANDS = ('/自走棋', '/cs自走棋', '/autochess', '/选', '/刷新', '/锁定', '/战术', '/升级教练', '/上阵', '/下阵', '/出售', '/阵容', '/赛程', '/结束回合')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for daily-fortune."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'daily-fortune'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '生成当天稳定一致的运势'
HELP_ENTRIES = ('/今日运势',)
COMMANDS = ('/今日运势',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for debug-telemetry."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'debug-telemetry'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = '埋点 p50/p95'
HELP_ENTRIES = ('/debug',)
COMMANDS = ('/debug',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for dice."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'dice'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '骰子和多人骰子挑战'
HELP_ENTRIES = ('/丢骰子 [NdM]', '/丢骰子挑战 [5d6|5d20|状态|结算|战绩|结束]')
COMMANDS = ('/丢骰子', '/骰子', '/丢骰子挑战', '/骰子挑战')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for draw-lot."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'draw-lot'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '抽取一条本地签文'
HELP_ENTRIES = ('/抽签',)
COMMANDS = ('/抽签',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for game-history."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'game-history'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '游戏记录'
HELP_ENTRIES = ('/游戏记录 /个人记录 /gamehistory',)
COMMANDS = ('/游戏记录', '/个人记录', '/gamehistory')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for guess-number."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'guess-number'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '群内持久化猜数字游戏'
HELP_ENTRIES = ('/猜数字 开始 [上限];/猜 数字;/猜数字 [状态|结束]',)
COMMANDS = ('/猜数字', '/猜')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for history-search."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'history-search'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '搜索本地群聊文字记录'
HELP_ENTRIES = ('/查记录 关键词',)
COMMANDS = ('/查记录', '/历史搜索')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for jwebot-version."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'jwebot-version'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = 'JWeBot 版本'
HELP_ENTRIES = ('/version /版本',)
COMMANDS = ('/版本', '/version')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for person-directory."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'person-directory'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = '人物索引'
HELP_ENTRIES = ('/人物列表 [页码] /people;/人物 [名称或别名] /person',)
COMMANDS = ('/人物列表', '/别名列表', '/people', '/人物', '/个人属性', '/person')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for person-memory."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'person-memory'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = '管理个人和同群人物记忆'
HELP_ENTRIES = ('/记住 内容;/我的记忆;/忘记 关键词或全部;/人物记忆 [显示名]',)
COMMANDS = ('/记住', '/我的记忆', '/忘记', '/人物记忆', '/记忆帮助')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for primogem-economy."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'primogem-economy'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '原石系统'
HELP_ENTRIES = ('/原石祈愿 /原石榜;/扫码加权 人;/Taffy发话 [定时HH:MM] 内容',)
COMMANDS = ('/原石祈愿', '/祈愿', '/wish', '/原石榜', '/primogem榜', '/扫码加权', '/扫码概率', '/Taffy发话', '/taffysay')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for random-number."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'random-number'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '在指定整数范围内取随机数'
HELP_ENTRIES = ('/随机数 最小值 最大值',)
COMMANDS = ('/随机数',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for repeat-ranking."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'repeat-ranking'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '查看北京时间今日复读排行'
HELP_ENTRIES = ('/复读榜',)
COMMANDS = ('/复读榜', '/复读')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for rock-paper-scissors."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'rock-paper-scissors'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '多人石头剪刀布游戏'
HELP_ENTRIES = ('/石头剪刀布 [开始|加入|出 选择|状态|结算|结束]',)
COMMANDS = ('/石头剪刀布',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for scan-ranking."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'scan-ranking'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '查看北京时间今日扫码排行'
HELP_ENTRIES = ('/扫码排行',)
COMMANDS = ('/扫码排行', '/扫码榜', '/今日扫码')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for server-status."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'server-status'
@@ -8,38 +8,11 @@ AUTHOR = 'official'
DESCRIPTION = '服务器状态'
HELP_ENTRIES = ('/状态;/status',)
COMMANDS = ('/状态', '/status')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for single-player-games."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'single-player-games'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '摩拉游戏'
HELP_ENTRIES = ('/摩拉/原石 /抽奖 /彩票 /21点 /游戏帮助',)
COMMANDS = ('/摩拉', '/金币', '/wallet', '/原石', '/抽奖', '/draw', '/彩票', '/买彩票', '/lottery', '/21点', '/二十一点', '/blackjack', '/游戏帮助', '/games')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for steam-presence."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'steam-presence'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = 'Steam 状态与时长'
HELP_ENTRIES = ('/steam;/steam时长 游戏[、玩家]',)
COMMANDS = ('/steam',)
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
@@ -1,6 +1,6 @@
"""Generated reviewed adapter for trivia-quiz."""
from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
from jwebot_sdk import ServiceCommandAdapter, SingleGroupContext
PROFILE = 'trivia-quiz'
@@ -8,38 +8,11 @@ AUTHOR = 'jwebot'
DESCRIPTION = '冷门知识问答'
HELP_ENTRIES = ('/回答 A;/answer A',)
COMMANDS = ('/回答', '/answer')
def _handler(context: SingleGroupContext, command: str):
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
PROFILE,
operation="execute",
payload={
"command": command,
"arguments": arguments,
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts and all(
isinstance(item, str) and item.strip() for item in texts
):
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("local service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
return handle
ADAPTER = ServiceCommandAdapter(
PROFILE,
metadata={"local_extension": PROFILE, "author": AUTHOR},
)
def plugin(context: SingleGroupContext) -> None:
for command in COMMANDS:
context.commands.register(command, _handler(context, command))
ADAPTER.register(context, COMMANDS)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "jwebot-sdk"
version = "1.2.8b1+1019"
version = "2.0.0b1+1021"
description = "Typed, capability-limited extension API for JWeBot plugins"
requires-python = ">=3.9"
dependencies = []
@@ -8,6 +8,7 @@ from .context import (
PluginLogger,
PluginStorage,
Scheduler,
ServiceCommandAdapter,
SingleGroupContext,
)
from .contracts import (
@@ -35,7 +36,8 @@ __all__ = [
"PluginStorage",
"ReplyPlan",
"Scheduler",
"ServiceCommandAdapter",
"SingleGroupContext",
]
__version__ = "1.2.8b1+1019"
__version__ = "2.0.0b1+1021"
+66 -2
View File
@@ -2,10 +2,10 @@
from __future__ import annotations
from collections.abc import Callable, Mapping
from collections.abc import Callable, Iterable, Mapping
from typing import Protocol
from .contracts import Event, ExtensionResult, Fact
from .contracts import Event, ExtensionResult, Fact, ReplyPlan
CommandHandler = Callable[[Event, str], ExtensionResult]
@@ -68,3 +68,67 @@ class SingleGroupContext(Protocol):
facts: FactWriter
scheduler: Scheduler
logger: PluginLogger
class ServiceCommandAdapter:
"""Register commands that delegate only to declared kernel service profiles."""
def __init__(
self,
profile: str,
*,
operation: str = "execute",
metadata: Mapping[str, str] | None = None,
) -> None:
self.profile = self._bounded_text(profile, "profile")
self.operation = self._bounded_text(operation, "operation")
self.metadata = {
str(key): str(value)
for key, value in (metadata or {}).items()
}
@staticmethod
def _bounded_text(value: object, name: str) -> str:
text = str(value or "").strip()
if not text or len(text) > 80:
raise ValueError(f"{name} is invalid")
return text
def _handler(self, context: SingleGroupContext, command: str) -> CommandHandler:
command_name = self._bounded_text(command, "command")
def handle(event: Event, arguments: str) -> ExtensionResult:
response = context.services.call(
self.profile,
operation=self.operation,
payload={
"command": command_name,
"arguments": str(arguments),
"event": event.to_mapping(),
},
)
texts = response.get("texts")
if isinstance(texts, list) and texts:
if not all(isinstance(item, str) and item.strip() for item in texts):
raise ValueError("service returned invalid text parts")
return ExtensionResult(
reply=ReplyPlan.multi_text(texts),
metadata=self.metadata,
)
text = response.get("text")
if not isinstance(text, str) or not text.strip():
raise ValueError("service returned invalid text")
return ExtensionResult(
reply=ReplyPlan.text(text),
metadata=self.metadata,
)
return handle
def register(
self,
context: SingleGroupContext,
commands: Iterable[str],
) -> None:
for command in commands:
context.commands.register(command, self._handler(context, command))