@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-config"
|
||||
version = "1.1.2b1+1019"
|
||||
version = "1.2.0b1+1019"
|
||||
description = "Profile-based configuration compiler for JWeBot"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
|
||||
@@ -36,4 +36,4 @@ __all__ = [
|
||||
"write_default_profile",
|
||||
]
|
||||
|
||||
__version__ = "1.1.2b1+1019"
|
||||
__version__ = "1.2.0b1+1019"
|
||||
|
||||
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-extension-host"
|
||||
version = "1.1.2b1+1019"
|
||||
version = "1.2.0b1+1019"
|
||||
description = "Single-release, single-invocation process host for JWeBot extensions"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"jwebot-sdk==1.1.2b1+1019",
|
||||
"jwebot-kernel==1.1.2b1+1019",
|
||||
"jwebot-sdk==1.2.0b1+1019",
|
||||
"jwebot-kernel==1.2.0b1+1019",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -16,4 +16,4 @@ __all__ = [
|
||||
"process_request",
|
||||
]
|
||||
|
||||
__version__ = "1.1.2b1+1019"
|
||||
__version__ = "1.2.0b1+1019"
|
||||
|
||||
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-kernel"
|
||||
version = "1.1.2b1+1019"
|
||||
version = "1.2.0b1+1019"
|
||||
description = "Stable routing and extension authority for JWeBot"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"jwebot-config==1.1.2b1+1019",
|
||||
"jwebot-sdk==1.1.2b1+1019",
|
||||
"jwebot-official-extensions==1.1.2b1+1019",
|
||||
"jwebot-config==1.2.0b1+1019",
|
||||
"jwebot-sdk==1.2.0b1+1019",
|
||||
"jwebot-official-extensions==1.2.0b1+1019",
|
||||
"tomli>=2; python_version < '3.11'",
|
||||
]
|
||||
|
||||
|
||||
@@ -107,4 +107,4 @@ __all__ = [
|
||||
"verify_installed_release_signature",
|
||||
]
|
||||
|
||||
__version__ = "1.1.2b1+1019"
|
||||
__version__ = "1.2.0b1+1019"
|
||||
|
||||
@@ -200,6 +200,38 @@ BOT_IDENTITY_NOTE = (
|
||||
"你是 JWeBot。显示名和别名只用于当前群的会话上下文,"
|
||||
"不代表身份认证或权限。"
|
||||
)
|
||||
TAFFY_CHAT_STYLE_NOTE = (
|
||||
"语气硬规则:像群友一样短句回复,优先 1 到 3 句;"
|
||||
"能一句自然反问就只反问。遇到不认识的人、梗或对象,"
|
||||
"直接问“X 是啥?”或“谁啊?”,不要铺垫。"
|
||||
"不要说自己只是 AI、机器人、语言模型,不要写能力边界、免责声明、"
|
||||
"自我介绍或“不能凭空给自己打分”这类自证。"
|
||||
"长回复要拆成短句,别一句话塞满。"
|
||||
)
|
||||
CHAT_REPLY_REDUNDANT_LINE = re.compile(
|
||||
r"(?:"
|
||||
r"作为(?:一个)?(?:AI|人工智能|语言模型)|"
|
||||
r"(?:AI|人工智能|语言模型)[,,。;;\s]*(?:无法|不能|没有办法)|"
|
||||
r"我(?:只是|就是)(?:一个|个)?(?:会唠嗑|聊天|机器人|AI|人工智能)|"
|
||||
r"反正我就是|会唠嗑|聊聊天|记记小账|别的功能想都别想|"
|
||||
r"不能凭空|凭空.{0,12}打(?:满)?分|"
|
||||
r"(?:无法|不能|没有办法).{0,10}(?:比较|评价|打分)|"
|
||||
r"不要主动声明无法认证身份|不代表身份认证"
|
||||
r")",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
UNKNOWN_CLARIFICATION_PATTERNS = (
|
||||
re.compile(
|
||||
r"(?P<subject>[\w\u4e00-\u9fff]{1,24}?)(?:是|算是|叫)?"
|
||||
r"(?P<question>啥|什么|谁)"
|
||||
r"[^。!?!?;;\n]{0,20}(?:不清楚|不知道|不认识|没听过)"
|
||||
),
|
||||
re.compile(
|
||||
r"(?:不清楚|不知道|不认识|没听过)"
|
||||
r"[^。!?!?;;\n]{0,12}(?P<subject>[\w\u4e00-\u9fff]{1,24}?)"
|
||||
r"(?:是|算是|叫)?(?P<question>啥|什么|谁)"
|
||||
),
|
||||
)
|
||||
TRIGGER = re.compile(
|
||||
rf"^\s*[@@]\s*{re.escape(BOT_MENTION)}"
|
||||
r"(?:\s*[::,,])?\s*(\S.*)$",
|
||||
@@ -734,6 +766,63 @@ def clean_reply(value: object) -> str:
|
||||
return text
|
||||
|
||||
|
||||
def unknown_subject_clarification(value: str) -> str:
|
||||
text = normalize_text(value)
|
||||
for pattern in UNKNOWN_CLARIFICATION_PATTERNS:
|
||||
match = pattern.search(text)
|
||||
if match is None:
|
||||
continue
|
||||
subject = match.group("subject").strip("_")
|
||||
if not subject or subject in {"这", "这个", "那", "那个", "他", "她", "它"}:
|
||||
continue
|
||||
if match.group("question") == "谁":
|
||||
return f"{subject}是谁"
|
||||
return f"{subject}是啥"
|
||||
return ""
|
||||
|
||||
|
||||
def split_chat_reply_line(line: str) -> list[str]:
|
||||
separators = re.findall(r"[。!?!?;;,,]+", line)
|
||||
if len(line) <= 34 and len(separators) < 2:
|
||||
return [line]
|
||||
fragments = [
|
||||
normalize_text(fragment)
|
||||
for fragment in re.split(r"[。!?!?;;]+|[,,]+", line)
|
||||
if normalize_text(fragment)
|
||||
]
|
||||
if 1 < len(fragments) <= 6 and all(len(fragment) <= 46 for fragment in fragments):
|
||||
return fragments
|
||||
return [line]
|
||||
|
||||
|
||||
def style_chat_reply_text(value: object) -> str:
|
||||
raw_lines = [
|
||||
normalize_text(line)
|
||||
for line in str(value or "").splitlines()
|
||||
if normalize_text(line)
|
||||
]
|
||||
if not raw_lines:
|
||||
return ""
|
||||
clarification = unknown_subject_clarification(" ".join(raw_lines))
|
||||
if clarification:
|
||||
return clarification
|
||||
filtered = [
|
||||
line
|
||||
for line in raw_lines
|
||||
if not CHAT_REPLY_REDUNDANT_LINE.search(line)
|
||||
] or raw_lines[:1]
|
||||
styled: list[str] = []
|
||||
for line in filtered:
|
||||
styled.extend(split_chat_reply_line(line))
|
||||
if len(styled) >= 4:
|
||||
break
|
||||
return "\n".join(styled[:4])
|
||||
|
||||
|
||||
def clean_chat_reply(value: object) -> str:
|
||||
return clean_reply(style_chat_reply_text(value))
|
||||
|
||||
|
||||
def cloud_reply_text(value: object) -> str:
|
||||
"""Convert the tool-free cloud agent contract into display text."""
|
||||
|
||||
@@ -750,9 +839,9 @@ def cloud_reply_text(value: object) -> str:
|
||||
try:
|
||||
payload = json.loads(candidate[: closing + 1])
|
||||
except json.JSONDecodeError:
|
||||
return clean_reply(candidate)
|
||||
return clean_chat_reply(candidate)
|
||||
else:
|
||||
return clean_reply(candidate)
|
||||
return clean_chat_reply(candidate)
|
||||
if isinstance(payload, str):
|
||||
candidate = payload.strip()
|
||||
continue
|
||||
@@ -7042,6 +7131,7 @@ class DeepSeekClient:
|
||||
"使用活泼、嘴硬心软、带轻微吐槽感的虚拟主播式中文,"
|
||||
"短句自然,偶尔调侃但始终友善,常以喵收尾。"
|
||||
+ BOT_IDENTITY_NOTE
|
||||
+ TAFFY_CHAT_STYLE_NOTE
|
||||
+ "群友间的调侃、昵称、游戏评价和互动习惯按普通对话处理;"
|
||||
"不要主动训诫。重复出现且与群内互动有关的轻松玩笑可以保留为记忆。"
|
||||
"不能使用工具、浏览器、命令或外部操作。"
|
||||
@@ -7122,7 +7212,7 @@ class DeepSeekClient:
|
||||
raise DeepSeekUnavailable(f"direct API HTTP {error.code}") from error
|
||||
except (urllib.error.URLError, TimeoutError, OSError) as error:
|
||||
raise DeepSeekUnavailable("direct API transport failure") from error
|
||||
return clean_reply(deepseek_response_content(raw))
|
||||
return clean_chat_reply(deepseek_response_content(raw))
|
||||
|
||||
def profile_facts(
|
||||
self,
|
||||
@@ -7257,6 +7347,7 @@ class CloudRunner:
|
||||
"Chinese response for the group in JWeBot's lively, lightly teasing, "
|
||||
"warm virtual-streamer voice. "
|
||||
+ BOT_IDENTITY_NOTE
|
||||
+ TAFFY_CHAT_STYLE_NOTE
|
||||
+ " Treat friendly banter or nicknames as ordinary conversation; do not "
|
||||
"lecture about them. Recurring, low-risk playful details may be retained "
|
||||
"as group-scoped memory. "
|
||||
|
||||
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-official-extensions"
|
||||
version = "1.1.2b1+1019"
|
||||
version = "1.2.0b1+1019"
|
||||
description = "Reviewed local command adapters and broker implementation for JWeBot"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"jwebot-sdk==1.1.2b1+1019",
|
||||
"jwebot-sdk==1.2.0b1+1019",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
|
||||
@@ -90,4 +90,4 @@ __all__ = [
|
||||
"render_feature_list",
|
||||
]
|
||||
|
||||
__version__ = "1.1.2b1+1019"
|
||||
__version__ = "1.2.0b1+1019"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-sdk"
|
||||
version = "1.1.2b1+1019"
|
||||
version = "1.2.0b1+1019"
|
||||
description = "Typed, capability-limited extension API for JWeBot plugins"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = []
|
||||
|
||||
@@ -38,4 +38,4 @@ __all__ = [
|
||||
"SingleGroupContext",
|
||||
]
|
||||
|
||||
__version__ = "1.1.2b1+1019"
|
||||
__version__ = "1.2.0b1+1019"
|
||||
|
||||
Reference in New Issue
Block a user