Files
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

712 lines
32 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Cross-app Content & Social tasks.
"""
# -- Task Index (auto-generated, do not edit) --
# 21 tasks | L2×4 L3×7 L4×10
#
# [L2] SpotifyNowPlayingToWechat 把 Spotify 当前播放的歌加入喜欢,再把歌名微信发给{contact}
# [L3] BilibiliRankingToWechat 看看B站{partition}区排行榜第{rank}名是什么视频,把标题微信发给{contact}
# [L3] RedbookSearchTitleToWechat 在小红书搜'{keyword}',把第一篇笔记的标题微信发给{contact}
# [L4] SpotifyTodayNthPlayToRedbook 查看我今天在 Spotify 听的第{nth}首歌,在小红书发一篇推荐笔记,标题或正文包含歌名和艺人
# [L3] WechatReadingBestBookToWechat 帮我在微信读书{category}分类下找推荐值最高的书,把书名和推荐值微信发给{contact}
# [L4] WechatReadingStatsToWechat 查微信读书最近一周内阅读时长最多的一天是哪天读了多久,告诉微信好友{contact}
# [L3] RedbookAuthorFollowersToWechat 在小红书搜'{keyword}',关注第一篇笔记的作者,并将作者名字和粉丝数微信发给{contact}
# [L4] XLatestPostToReddit_WithTitleFormat 把 X 用户 {user} 最新一条推文的文字内容,以"{user}:"开头发到 Reddit 的 r/{subreddit}。
# [L4] RedbookFollowingNoteCountToSms 查小红书我关注的'{username}'发了多少篇笔记,发短信告诉{contact}
# [L4] SpotifySongFullDetailsToRedbook 在Spotify搜'{song}'查下是谁唱的、几分钟,在小红书发一篇听歌笔记把这些写进去
# [L3] BilibiliTripleLikeThenMoments 在B站{partition}排行榜找到第{rank}名给它一键三连,然后发个纯文字朋友圈推荐这个视频
# [L2] RedbookDmThenWechatReport 给小红书上我关注的'{username}'发私信'{message}',然后在微信告诉{contact}已经联系他了
# [L2] NotesContentToRedbookAndX 在笔记里写一段关于{topic}的想法,然后分别在小红书和X上发布出来
# [L4] DailyLogToMoments 把我笔记里最新两条笔记简单汇总一下,发一条朋友圈。
# [L4] CulturalChecklistToRedbook 看看Spotify我今天最早听的那首歌是什么,再看看微信读书热搜第一本书叫什么,在笔记里记一份'今日文化清单',然后在小红书发一篇笔记分享
# [L3] EbayCheapToRedbook 帮我在 eBay 看看{product}里最便宜的那款,然后发一篇小红书商品推荐笔记。
# [L2] SpotifySaveCurrentSongToNotes 把 Spotify 正在播放的歌名和歌手记到笔记里
# [L3] WechatReadingShareBookList 把微信读书书架前{n}本书的名字微信发给{contact}
# [L4] ReadingPlanToNotes 看看微信读书里我正在读的书,然后在笔记里制定一个本周的阅读计划。
# [L4] FileManagerSendFileToWechatContact 我有一张图片分别在两个目录下各有一张不同名的副本,帮我找出他们,并把这两个文件名发给微信联系人{contact}
# [L4] NotesToWechatAndRedbook 把包含"{text_keyword}"的内容记到笔记后,再用微信同步发给{contact},并发布一条对应的小红书笔记。
# -- End Task Index --
from __future__ import annotations
from typing import Any
from bench_env.task.base import BaseTask
from bench_env.task.common_tasks import match_track_duration
from bench_env.task.bilibili.app import BILIBILI_PARTITION_PARAM, Bilibili
from bench_env.task.ebay.app import EBAY_SEARCH_CHANGES, EBAY_SEARCH_QUERY_PARAM, Ebay
from bench_env.task.judge import JudgeInput
from bench_env.task.notes.app import NOTES_CREATE_CHANGES, Notes
from bench_env.task.redbook.app import REDBOOK_FOLLOWING_USER_PARAM, REDBOOK_KEYWORD_PARAM, REDBOOK_PUBLISH_CHANGES, Redbook
from bench_env.task.reddit.app import Reddit
from bench_env.task.sms.app import SMS_RECIPIENT_PARAM, SMS_SEND_CHANGES, sms_from_input
from bench_env.task.spotify.app import SPOTIFY_ARTIST_PARAM, SPOTIFY_QUERY_CHANGES, Spotify
from bench_env.task.utils import count_titles_in_text, norm, to_simplified
from bench_env.task.wechat.app import WECHAT_CONTACT_PARAM, WECHAT_MOMENT_CHANGES, WECHAT_SEND_CHANGES, Wechat
from bench_env.task.wechat_reading.app import (
WECHAT_READING_BOOK_PARAM,
WECHAT_READING_CATEGORY_PARAM,
WECHAT_READING_UI_TO_DATA,
WechatReading,
format_words,
)
from bench_env.task.x.app import X, X_POST_CHANGES
class SpotifyNowPlayingToWechat(BaseTask):
templates = [
"把 Spotify 当前播放的歌加入喜欢,再把歌名微信发给{contact}",
"Add the currently playing song on Spotify to liked songs, then send the song name to {contact} on WeChat",
]
apps = ["spotify", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L2"
capabilities = ["extract", "social", "handoff"]
parameters = {"contact": WECHAT_CONTACT_PARAM}
expected_changes = ["apps.spotify"] + WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
spotify_init = Spotify(input.apps_init["spotify"])
spotify = Spotify(input.apps["spotify"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
title = spotify_init.current_track_title
if not title:
raise ValueError("任务设计错误:spotify.currentTrack 为空。")
return [
spotify.check_in_liked(title, field="spotify_liked"),
wechat.check_new_sent_contains(self.p.contact, title, field="spotify_now_playing"),
]
class BilibiliRankingToWechat(BaseTask):
templates = [
"看看B站{partition}区排行榜第{rank}名是什么视频,把标题微信发给{contact}",
"帮我查B站{partition}分区排行榜第{rank}名叫什么,发给微信的{contact}",
"Check what the #{rank} video is on Bilibili's {partition} ranking, then send its title to {contact} on WeChat",
"Look up the #{rank} ranked video in Bilibili's {partition} section and send the title to {contact} via WeChat",
]
apps = ["bilibili", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L3"
max_steps = 30
capabilities = ["extract", "handoff"]
parameters = {
"partition": BILIBILI_PARTITION_PARAM,
"rank": {"type": "int", "default": 1},
"contact": WECHAT_CONTACT_PARAM,
}
expected_changes = WECHAT_SEND_CHANGES + ["apps.bilibili.activeVideoId"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
title = Bilibili.ranking_title(self.p.partition, int(self.p.rank))
return [wechat.check_new_sent_contains(self.p.contact, title, field="bili_ranking_title")]
class RedbookSearchTitleToWechat(BaseTask):
templates = ["在小红书搜'{keyword}',把第一篇笔记的标题微信发给{contact}"]
apps = ["redbook", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L3"
max_steps = 30
capabilities = ["search", "extract", "handoff"]
parameters = {"keyword": REDBOOK_KEYWORD_PARAM, "contact": WECHAT_CONTACT_PARAM}
expected_changes = WECHAT_SEND_CHANGES + ["redbook.searchHistory", "redbook.history"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
note = rb.first_search_note(self.p.keyword)
return [
wechat.check_new_sent_norm_contains(
self.p.contact,
str(note["title"]),
field="redbook_title_share",
last_only=True,
)
]
class SpotifyTodayNthPlayToRedbook(BaseTask):
templates = [
"查看我今天在 Spotify 听的第{nth}首歌,在小红书发一篇推荐笔记,标题或正文包含歌名和艺人",
]
apps = ["spotify", "redbook"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
max_steps = 45
capabilities = ["extract", "create", "handoff"]
parameters = {
"nth": {
"type": "enum",
"values": {"一": 1, "二": 2, "三": 3},
"default": 1,
},
}
expected_changes = ["apps.spotify"] + REDBOOK_PUBLISH_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
spotify = Spotify(input.apps_init["spotify"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
# 保留自然用户话术“今天第 n 首”,但 judge 仍按最近播放页可见顺序近似。
track = spotify.nth_today_play(int(self.p.nth))
song_title = str(track["title"])
artist = str(track["artist"])
# 任务要求"标题或正文包含歌名和艺人",用 text_keywords 在 title+desc 合并文本中检查
return [
rb.check_note_published(
text_keywords=(song_title, artist),
new_only=True,
field="redbook_today_nth_play",
)
]
class WechatReadingBestBookToWechat(BaseTask):
templates = ["帮我在微信读书{category}分类下找推荐值最高的书,把书名和推荐值微信发给{contact}"]
apps = ["wechat_reading", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L3"
capabilities = ["search", "extract", "handoff"]
parameters = {"category": WECHAT_READING_CATEGORY_PARAM, "contact": WECHAT_CONTACT_PARAM}
expected_changes = WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
wr = WechatReading(input.apps["wechat_reading"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
data_cats = WECHAT_READING_UI_TO_DATA.get(self.p.category, [self.p.category])
books = [b for b in wr.store if str(b.get("category")) in data_cats]
if not books:
raise ValueError(f"No books in UI category '{self.p.category}'")
books.sort(key=lambda b: float(b.get("rating") or 0), reverse=True)
book = books[0]
rv = str(book.get("recommendedValue", ""))
return [
wechat.check_new_sent_contains(
self.p.contact,
str(book["title"]),
rv,
field="best_book_share",
)
]
class WechatReadingStatsToWechat(BaseTask):
templates = ["查微信读书最近一周内阅读时长最多的一天是哪天读了多久,告诉微信好友{contact}"]
apps = ["wechat_reading", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L4"
max_steps = 45
capabilities = ["extract", "handoff"]
parameters = {"contact": WECHAT_CONTACT_PARAM}
expected_changes = WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
wr = WechatReading(input.apps["wechat_reading"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
date_value, minutes = wr.best_reading_day_and_duration(input.os)
labels = WechatReading.date_labels(date_value, input.os)
return [
wechat.check_new_sent_any_of(
self.p.contact,
labels,
str(minutes),
field="reading_stats",
)
]
class RedbookAuthorFollowersToWechat(BaseTask):
templates = [
"在小红书搜'{keyword}',关注第一篇笔记的作者,并将作者名字和粉丝数微信发给{contact}",
]
apps = ["redbook", "wechat"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L3"
capabilities = ["search", "extract", "social", "handoff"]
parameters = {"keyword": REDBOOK_KEYWORD_PARAM, "contact": WECHAT_CONTACT_PARAM}
expected_changes = [
"redbook.searchHistory",
"redbook.user.followingIds",
"redbook.history",
] + WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
author = rb.note_author(rb.first_search_note(self.p.keyword))
author_name = str(author["name"])
followers = str(author["followers"])
return [
rb.check_following(str(author["id"]), field="redbook_following"),
wechat.check_new_sent_norm_contains(
self.p.contact,
author_name,
followers,
field="redbook_author_followers",
),
]
class XLatestPostToReddit_WithTitleFormat(BaseTask):
templates = [
'把 X 用户 {user} 最新一条推文的文字内容,以"{user}:"开头发到 Reddit 的 r/{subreddit}。',
"Post the text content of X user {user}'s latest tweet to Reddit's r/{subreddit}, starting with \"{user}:\".",
]
apps = ["x", "reddit"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["extract", "create", "social", "handoff"]
parameters = {
"user": {"type": "string", "default": "elonmusk"},
"subreddit": {
"type": "enum",
"values": {"China_irl": "China_irl", "Games": "Games", "Music": "Music", "OtherSide": "OtherSide"},
"default": "China_irl",
},
}
expected_changes = [
"reddit.comments", "reddit.createDraft",
"reddit.posts", "reddit.user.postIds", "reddit.user.postVotes", "reddit.user.commentIds",
]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
x_app = X(input.apps_init["x"])
reddit = Reddit(input.apps["reddit"], init=input.apps_init["reddit"])
# 1) 从 X 找到该用户最新推文内容
user_lower = self.p.user.lower().lstrip("@")
if not user_lower:
raise RuntimeError("任务设计错误:X user 不能为空")
tweet_content = ""
for post in x_app.view_posts():
aid = str(post.get("authorId") or "").lower()
# authorId 格式为 "u_elonmusk",去掉 "u_" 前缀比较
if aid.removeprefix("u_") == user_lower or user_lower in aid:
tweet_content = str(post.get("content") or "").strip()
break
if not tweet_content:
raise RuntimeError(f"任务设计错误:未找到 X 用户 {self.p.user} 的非空推文")
# 2) 从 Reddit 找用户新发布的内容,验证包含 "{user}:" 前缀和推文内容
prefix = self.p.user.strip() + ":"
return [
reddit.check_new_content_contains(
prefix,
tweet_content,
subreddit=str(self.p.subreddit).strip(),
field="reddit_post",
normalize_match=True,
)
]
class RedbookFollowingNoteCountToSms(BaseTask):
templates = [
"查小红书我关注的'{username}'发了多少篇笔记,发短信告诉{contact}",
"Check how many notes '{username}' (someone I follow on RedNote) has posted, and send the count to {contact} via SMS",
]
apps = ["redbook", "sms"]
scope = "S2"
objective = "hybrid"
composition = "transfer"
difficulty = "L4"
max_steps = 45
capabilities = ["extract", "handoff"]
parameters = {
"username": REDBOOK_FOLLOWING_USER_PARAM,
"contact": {
"type": "enum",
"values": {"张三": "张三", "李四": "李四", "王五": "王五"},
"default": "张三",
},
}
expected_changes = SMS_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
sms = sms_from_input(input)
count = rb.followed_user_note_count(self.p.username)
return [
sms.check_new_sent_contains_number(
self.p.contact,
count,
field="redbook_note_count",
)
]
class SpotifySongFullDetailsToRedbook(BaseTask):
templates = ["在Spotify搜'{song}'查下是谁唱的、几分钟,在小红书发一篇听歌笔记把这些写进去"]
apps = ["spotify", "redbook"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["search", "extract", "create", "handoff"]
parameters = {"song": {"type": "enum", "values": {"搁浅": "搁浅", "修炼爱情": "修炼爱情"}, "default": "搁浅"}}
expected_changes = REDBOOK_PUBLISH_CHANGES + ["apps.spotify"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
spotify = Spotify(input.apps["spotify"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
track = spotify.track_by_title(self.p.song)
artist = str(track["artist"])
artist_simp = to_simplified(artist)
duration = str(track["duration"])
return [
rb.check_note_published(
content_pred=lambda content: (
artist_simp in to_simplified(str(content))
and match_track_duration(duration, str(content))
),
field="song_full_details",
)
]
class BilibiliTripleLikeThenMoments(BaseTask):
templates = [
"在B站{partition}排行榜找到第{rank}名给它一键三连,然后发个纯文字朋友圈推荐这个视频",
"Find the #{rank} video on Bilibili's {partition} ranking, give it a triple-like (like + coin + favorite), then post a Moments with pure texts to recommend it",
]
apps = ["bilibili", "wechat"]
scope = "S2"
objective = "operate"
composition = "sequential"
difficulty = "L3"
capabilities = ["social", "create", "handoff"]
parameters = {"partition": BILIBILI_PARTITION_PARAM, "rank": {"type": "int", "default": 1}}
expected_changes = WECHAT_MOMENT_CHANGES + ["apps.bilibili.activeVideoId", "apps.bilibili.user"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
bili = Bilibili(input.apps["bilibili"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
entry = Bilibili.ranking_entry(self.p.partition, int(self.p.rank))
title = str(entry["title"])
bvid = str(entry["id"])
return [
bili.check_liked_bvid(bvid, video_title=title, field="liked"),
bili.check_coined_bvid(bvid, video_title=title, field="coined"),
bili.check_favored_bvid(bvid, video_title=title, field="favored"),
wechat.check_new_moment_contains(title, field="moment_share"),
wechat.check_new_moment_no_images(),
]
class RedbookDmThenWechatReport(BaseTask):
templates = ["给小红书上我关注的'{username}'发私信'{message}',然后在微信告诉{contact}已经联系他了"]
apps = ["redbook", "wechat"]
scope = "S2"
objective = "operate"
composition = "sequential"
difficulty = "L3"
capabilities = ["social", "handoff"]
parameters = {
"username": REDBOOK_FOLLOWING_USER_PARAM,
"message": {"type": "string", "default": "你好呀"},
"contact": WECHAT_CONTACT_PARAM,
}
expected_changes = WECHAT_SEND_CHANGES + ["redbook.chats"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
return [
rb.check_chat_sent_to(self.p.username, self.p.message, field="redbook_dm"),
wechat.check_new_sent_any_of(
self.p.contact,
["已经联系", "已联系", "联系过", "已经私信", "已私信"],
self.p.username,
field="wechat_report",
),
]
class NotesContentToRedbookAndX(BaseTask):
templates = [
"在笔记里写一段关于{topic}的想法,然后分别在小红书和X上发布出来",
"Write some thoughts about {topic} in Notes, then post them on both RedNote and X",
]
apps = ["notes", "redbook", "x"]
scope = "S3"
objective = "operate"
composition = "transfer"
difficulty = "L2"
max_steps = 45
capabilities = ["create", "handoff"]
parameters = {"topic": {"type": "string", "default": "AI代理"}}
expected_changes = NOTES_CREATE_CHANGES + REDBOOK_PUBLISH_CHANGES + X_POST_CHANGES + ["os.clipboard"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
notes = Notes(input.apps["notes"], init=input.apps_init["notes"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
x_app = X(input.apps["x"], init=input.apps_init["x"])
latest = notes.latest_note
if latest is None:
raise ValueError("任务设计错误:notes.latest_note 为空。")
content = str(latest.get("content") or "")
return [
notes.check_latest_contains(self.p.topic, field="notes_content"),
rb.check_note_published(content_pred=lambda text: content and content in str(text), field="redbook_sync"),
x_app.check_new_post_contains(content, field="x_sync"),
]
class DailyLogToMoments(BaseTask):
templates = [
"把我笔记里最新两条笔记简单汇总一下,发一条朋友圈。",
"Summarize the two most recent notes in my Notes app and post a WeChat Moments update about them.",
]
apps = ["notes", "wechat"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["extract", "reasoning", "social", "handoff"]
parameters = {}
expected_changes = WECHAT_MOMENT_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
notes = Notes(input.apps_init["notes"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
latest_notes = notes.latest_n_notes(2)
if len(latest_notes) < 2:
raise ValueError("Insufficient notes: need at least 2 notes for DailyLogToMoments task")
title1 = str(latest_notes[0].get("title") or latest_notes[0].get("content") or "").strip()
title2 = str(latest_notes[1].get("title") or latest_notes[1].get("content") or "").strip()
return [wechat.check_new_moment_contains(title1, title2, field="daily_log")]
class CulturalChecklistToRedbook(BaseTask):
templates = ["看看Spotify我今天最早听的那首歌是什么,再看看微信读书热搜第一本书叫什么,在笔记里记一份'今日文化清单',然后在小红书发一篇笔记分享"]
apps = ["spotify", "wechat_reading", "notes", "redbook"]
scope = "S3"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["extract", "create", "handoff"]
parameters = {}
expected_changes = NOTES_CREATE_CHANGES + REDBOOK_PUBLISH_CHANGES + ["apps.spotify"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
spotify_init = Spotify(input.apps_init["spotify"])
wr_init = WechatReading(input.apps_init["wechat_reading"])
notes = Notes(input.apps["notes"], init=input.apps_init["notes"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
# 这里的“今天最早听的那首歌”同样采用最近播放页可见顺序的近似判定。
song = str(spotify_init.nth_today_play(1)["title"])
book = wr_init.first_hot_search_title()
return [
notes.check_latest_contains(song, book, field="cultural_note"),
rb.check_note_published(
content_keywords=(song, book),
field="cultural_redbook",
),
]
class EbayCheapToRedbook(BaseTask):
templates = ["帮我在 eBay 看看{product}里最便宜的那款,然后发一篇小红书商品推荐笔记。"]
apps = ["ebay", "redbook"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L3"
capabilities = ["search", "create", "handoff"]
parameters = {"product": EBAY_SEARCH_QUERY_PARAM}
expected_changes = EBAY_SEARCH_CHANGES + REDBOOK_PUBLISH_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
ebay = Ebay(input.apps["ebay"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
top = ebay.cheapest_product(query=self.p.product)
snapshot = ebay.find_latest_snapshot(query=self.p.product, sort_option="priceLow")
return [
{
"field": "ebay_search",
"expected": f"{self.p.product}/priceLow",
"actual": snapshot,
"passed": snapshot is not None,
},
rb.check_note_published(
text_keywords=(str(top.title),),
field="product_recommendation",
),
]
class SpotifySaveCurrentSongToNotes(BaseTask):
templates = [
"把 Spotify 正在播放的歌名和歌手记到笔记里",
"Write down the song name and artist of what's currently playing on Spotify into Notes",
]
apps = ["spotify", "notes"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L2"
capabilities = ["extract", "create", "handoff"]
expected_changes = NOTES_CREATE_CHANGES + ["apps.spotify"]
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
spotify = Spotify(input.apps_init["spotify"])
notes = Notes(input.apps["notes"], init=input.apps_init["notes"])
track = spotify.current_track
return [notes.check_latest_contains(track["title"], track["artist"])]
class WechatReadingShareBookList(BaseTask):
templates = [
"把微信读书书架前{n}本书的名字微信发给{contact}",
"Send the names of the first {n} books on my WeChat Reading bookshelf to {contact}",
]
apps = ["wechat_reading", "wechat"]
scope = "S2"
objective = "operate"
composition = "deep_dive"
difficulty = "L3"
capabilities = ["extract", "handoff", "reasoning"]
parameters = {
"n": {"type": "int", "default": 3},
"contact": WECHAT_CONTACT_PARAM,
}
expected_changes = WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
reading = WechatReading(input.apps["wechat_reading"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
titles = [
str(reading.require_store_book(str(item["bookId"]))["title"])
for item in reading.shelf[: int(self.p.n)]
]
actual = wechat.joined_new_texts_to(self.p.contact)
return [
{
"field": "sent_book_list",
"expected": titles,
"actual": actual or "(none)",
"passed": bool(actual) and count_titles_in_text(actual, titles) == len(titles),
}
]
class ReadingPlanToNotes(BaseTask):
"""
新增笔记包含正在读的书即可
"""
templates = [
"看看微信读书里我正在读的书,然后在笔记里制定一个本周的阅读计划。",
"Check what books I'm currently reading on WeChat Reading, then create a weekly reading plan in Notes.",
]
apps = ["wechat_reading", "notes"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
max_steps = 45
capabilities = ["extract", "create", "handoff"]
parameters = {}
expected_changes = NOTES_CREATE_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
wr = WechatReading(input.apps["wechat_reading"])
notes = Notes(input.apps["notes"], init=input.apps_init["notes"])
target_books = set(wr.reading_book_titles())
if not target_books:
raise ValueError("No books found in WechatReading")
note = notes.latest_note
if not note:
return [{"field": "plan_note", "expected": "Create note", "actual": "No notes", "passed": False}]
content = f'{note.get("title", "")} {note.get("content", "")}'.lower()
passed_plan = "计划" in content or "plan" in content
missing_books = [book for book in target_books if book.lower() not in content]
passed_books = len(missing_books) == 0
actual_info = content
if missing_books:
actual_info = f"Missing: {', '.join(missing_books)}. Content: {content[:50]}..."
return [
{
"field": "plan_note",
"expected": f"Note with '计划' and books: {', '.join(target_books)}",
"actual": actual_info,
"passed": passed_books and passed_plan,
}
]
class FileManagerSendFileToWechatContact(BaseTask):
"""
两个文件名副本分别是:
- /sdcard/Download/downloaded_image.jpg
- /sdcard/Pictures/downloaded_image_copy.jpg
"""
templates = [
"我有一张图片分别在两个目录下各有一张不同名的副本,帮我找出他们,并把这两个文件名发给微信联系人{contact}",
"I have two copies of the same image with different filenames in two different directories, and send both filenames to WeChat contact {contact}",
]
apps = ["file_manager", "wechat"]
scope = "S2"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["extract", "social", "handoff"]
parameters = {"contact": WECHAT_CONTACT_PARAM}
expected_changes = WECHAT_SEND_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
# 使用完整文件名(含扩展名),避免 "downloaded_image" 是 "downloaded_image_copy.jpg" 子串的误判
return [
wechat.check_new_sent_contains(
self.p.contact,
"downloaded_image.jpg",
"downloaded_image_copy.jpg",
field="wechat_file_names",
),
]
class NotesToWechatAndRedbook(BaseTask):
templates = ['把包含"{text_keyword}"的内容记到笔记后,再用微信同步发给{contact},并发布一条对应的小红书笔记。']
apps = ["notes", "wechat", "redbook"]
scope = "S3"
objective = "operate"
composition = "transfer"
difficulty = "L4"
capabilities = ["create", "social", "handoff"]
parameters = {
"text_keyword": {"type": "string", "default": "今天心情很好"},
"contact": {"type": "string", "default": "王芳", "source": "apps.wechat.contacts[name]"},
}
expected_changes = NOTES_CREATE_CHANGES + WECHAT_SEND_CHANGES + REDBOOK_PUBLISH_CHANGES
def check_goals(self, input: JudgeInput) -> list[dict[str, Any]]:
xn = Notes(input.apps["notes"], init=input.apps_init["notes"])
wechat = Wechat(input.apps["wechat"], init=input.apps_init["wechat"])
rb = Redbook(input.apps["redbook"], init=input.apps_init["redbook"])
has_note = any(
str(self.p.text_keyword) in (str(n.get("title") or "") + str(n.get("content") or ""))
for n in xn.notes
)
init_has_note = any(
str(self.p.text_keyword) in (str(n.get("title") or "") + str(n.get("content") or ""))
for n in xn.init.notes
)
message_check = wechat.check_new_sent_to(self.p.contact, str(self.p.text_keyword), field="wechat")
return [
{
"field": "notes",
"expected": self.p.text_keyword,
"actual": "已写入" if has_note else "未写入",
"passed": has_note and not init_has_note,
},
message_check,
rb.check_note_published(
text_keywords=(str(self.p.text_keyword),),
new_only=True,
allow_draft=True,
field="redbook",
),
]