Compare commits

...

8 Commits

Author SHA1 Message Date
Tim
d98c3644a6 fix: 添加GitHub action 2025-10-28 19:55:29 +08:00
Tim
dbb63a4039 feat(bot): add open source reply bot 2025-10-28 19:53:07 +08:00
Tim
8db928b9a8 Merge pull request #1119 from nagisa77/codex/update-lottery-time-from-23-to-15
Adjust coffee bot draw schedule
2025-10-28 18:58:05 +08:00
Tim
46f6ccb3a8 Adjust coffee draw schedule 2025-10-28 18:57:53 +08:00
Tim
87dcebf052 fix: tools 重写 2025-10-28 18:50:34 +08:00
Tim
0ad4f4feff fix: fix tools 2025-10-28 18:48:32 +08:00
Tim
a227ac77fb Merge pull request #1118 from nagisa77/codex/add-daily-weather-lookup-for-cities
fix: 透传token
2025-10-28 18:45:30 +08:00
Tim
7d8c9b68bd Merge pull request #1117 from nagisa77/codex/add-daily-weather-lookup-for-cities
Integrate weather MCP into Coffee Bot
2025-10-28 18:43:15 +08:00
5 changed files with 110 additions and 23 deletions

View File

@@ -2,7 +2,7 @@ name: Coffee Bot
on:
schedule:
- cron: "0 1 * * *"
- cron: "0 1 * * 1-5"
workflow_dispatch:
jobs:

View File

@@ -0,0 +1,30 @@
name: Open Source Reply Bot
on:
schedule:
- cron: "*/30 * * * *"
workflow_dispatch:
jobs:
run-open-source-reply-bot:
environment: Bots
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm install --no-save @openai/agents tsx typescript
- name: Run open source reply bot
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENISLE_TOKEN: ${{ secrets.OPENISLE_TOKEN_BOT_1 }}
APIFY_API_TOKEN: ${{ secrets.APIFY_API_TOKEN }}
run: npx tsx bots/instance/open_source_reply_bot.ts

View File

@@ -3,21 +3,6 @@ import { Agent, Runner, hostedMcpTool, withTrace } from "@openai/agents";
export type WorkflowInput = { input_as_text: string };
export abstract class BotFather {
protected readonly allowedMcpTools = [
// openisle MCP tools
"search", // 用于搜索帖子、内容等
"create_post", // 创建新帖子
"reply_to_post", // 回复帖子
"reply_to_comment", // 回复评论
"recent_posts", // 获取最新帖子
"get_post", // 获取特定帖子的详细信息
"list_unread_messages", // 列出未读消息或通知
"mark_notifications_read", // 标记通知为已读
// third-party MCP tools
"weather_mcp_server", // 天气 MCP 工具
];
protected readonly openisleToken = (process.env.OPENISLE_TOKEN ?? "").trim();
protected readonly weatherToken = (process.env.APIFY_API_TOKEN ?? "").trim();
@@ -27,11 +12,6 @@ export abstract class BotFather {
constructor(protected readonly name: string) {
console.log(`${this.name} starting...`);
console.log(
"🛠️ Configured Hosted MCP tools:",
this.allowedMcpTools.join(", ")
);
console.log(
this.openisleToken
? "🔑 OPENISLE_TOKEN detected in environment; it will be attached to MCP requests."
@@ -89,7 +69,16 @@ export abstract class BotFather {
return hostedMcpTool({
serverLabel: "openisle_mcp",
serverUrl: "https://www.open-isle.com/mcp",
allowedTools: this.allowedMcpTools,
allowedTools: [
"search", // 用于搜索帖子、内容等
"create_post", // 创建新帖子
"reply_to_post", // 回复帖子
"reply_to_comment", // 回复评论
"recent_posts", // 获取最新帖子
"get_post", // 获取特定帖子的详细信息
"list_unread_messages", // 列出未读消息或通知
"mark_notifications_read", // 标记通知为已读
],
requireApproval: "never",
...authConfig,
});
@@ -100,6 +89,9 @@ export abstract class BotFather {
serverLabel: "weather_mcp_server",
serverUrl: "https://jiri-spilka--weather-mcp-server.apify.actor/mcp",
requireApproval: "never",
allowedTools: [
"get_current_weather", // 天气 MCP 工具
],
headers: {
Authorization: `Bearer ${this.weatherToken || ""}`,
},

View File

@@ -22,7 +22,7 @@ class CoffeeBot extends BotFather {
const now = new Date(Date.now() + 8 * 60 * 60 * 1000);
const weekday = WEEKDAY_NAMES[now.getDay()];
const drawTime = new Date(now);
drawTime.setHours(23, 0, 0, 0);
drawTime.setHours(15, 0, 0, 0);
return `
请立即在 https://www.open-isle.com 使用 create_post 发表一篇帖子,遵循以下要求:

View File

@@ -0,0 +1,65 @@
import { readFileSync } from "node:fs";
import path from "node:path";
import { BotFather, WorkflowInput } from "../bot_father";
class OpenSourceReplyBot extends BotFather {
constructor() {
super("OpenSource Reply Bot");
}
protected override getAdditionalInstructions(): string[] {
const knowledgeBase = this.loadKnowledgeBase();
return [
"You are OpenSourceReplyBot, a professional helper who focuses on answering open-source development and code-related questions for the OpenIsle community.",
"Respond in Chinese using well-structured Markdown sections such as 标题、列表、代码块等,让回复清晰易读。",
"保持语气专业、耐心、详尽,绝不使用表情符号或颜文字,也不要卖萌。",
"优先解答与项目代码、贡献流程、架构设计或排错相关的问题;如果消息与此无关,请礼貌说明并跳过。",
"在需要时引用 README.md 与 CONTRIBUTING.md 中的要点,帮助用户快速定位文档位置。",
knowledgeBase,
].filter(Boolean);
}
protected override getCliQuery(): string {
return `
【AUTO】每30分钟自动巡检未读提及与评论严格遵守以下流程
1调用 list_unread_messages 获取待处理的“提及/评论”;
2按时间从新到旧逐条处理最多10条如需上下文请调用 get_post
3仅对与开源项目、代码实现或贡献流程直接相关的问题生成详尽的 Markdown 中文回复,
若与主题无关则礼貌说明并跳过;
4回复时引用 README 或 CONTRIBUTING 中的要点(如适用),并优先给出可执行的排查步骤或代码建议;
5回复评论使用 reply_to_comment回复帖子使用 reply_to_post
6若某通知最后一条已由本 bot 回复,则跳过避免重复;
7整理已处理通知 ID 调用 mark_notifications_read
8结束时输出包含处理条目概览URL或ID的总结。`.trim();
}
private loadKnowledgeBase(): string {
const docs = ["../../README.md", "../../CONTRIBUTING.md"];
const sections: string[] = [];
for (const relativePath of docs) {
try {
const absolutePath = path.resolve(__dirname, relativePath);
const content = readFileSync(absolutePath, "utf-8").trim();
if (content) {
sections.push(`以下是 ${path.basename(absolutePath)} 的内容:\n${content}`);
}
} catch (error) {
sections.push(`未能加载 ${relativePath},请检查文件路径或权限。`);
}
}
return sections.join("\n\n");
}
}
const openSourceReplyBot = new OpenSourceReplyBot();
export const runWorkflow = async (workflow: WorkflowInput) => {
return openSourceReplyBot.runWorkflow(workflow);
};
if (require.main === module) {
openSourceReplyBot.runCli();
}