从 Telegram bot 迁移到 Hashee
Telegram bot 简单优雅但单页 API 长达数千行;本教程做完整对照映射,帮你 保留同样的功能模型迁过来。
一句话差异
| 维度 | Telegram | Hashee |
|---|---|---|
| 加密 | TLS only(服务端可读) | 端到端加密(盲管道) |
| 鉴权 | Bot Token (123456:ABC-DEF...) | Agent Token (hsk_...) |
| 接收 | Long polling / Webhook | WebSocket / Webhook |
| 命令 | /start, /help 内置 | 任意文本 + 业务侧解析 |
| 富 UI | Inline Keyboard / ReplyKeyboard | Artifact(subtype) |
| 回调 | callback_query | artifact_response(含 action) |
| 文件 | sendPhoto / sendDocument | agent.send({type:"image/file"}) |
| 群组 | Group / Supergroup / Channel | Group (统一抽象) |
| 限速 | 30 msg/sec/bot | 5 msg/sec/agent |
API 映射
接收文本
Telegram: bot.on("message", (msg) => { bot.sendMessage(msg.chat.id, `Echo: ${msg.text}`); });
Hashee: agent.addMessageHandler(async (msg) => { if (msg.payload?.type !== "text") return; await agent.send(msg.conversation_id, { type: "text", text: `Echo: ${msg.payload.text}` }); });Inline Keyboard → Artifact
Telegram: bot.sendMessage(chatId, "选择", { reply_markup: { inline_keyboard: [[ { text: "Yes", callback_data: "yes" }, { text: "No", callback_data: "no" }, ]], }, });
Hashee: agent.sendArtifact(convId, { artifact: { subtype: "info", title: "选择", payload: { body: "请选择", actions: [ { id: "yes", label: "Yes", action: "yes" }, { id: "no", label: "No", action: "no" }, ], }, }, });Callback Query → artifact_response
Telegram: bot.on("callback_query", (q) => { if (q.data === "yes") bot.sendMessage(q.message.chat.id, "你选了 Yes"); });
Hashee: agent.addEventHandler(async (event) => { if (event.type !== "artifact_response") return; const action = event.payload.action; if (action === "yes") { await agent.send(event.payload.conversation_id, { type: "text", text: "你选了 Yes" }); } });sendPhoto / sendDocument → uploadFile
Telegram: bot.sendPhoto(chatId, fileBuffer, { caption: "Q1 报告" });Hashee: agent.uploadFile(convId, { filename: "q1.png", mime: "image/png", data: fileBuffer, caption: "Q1 报告", send_as: "image", });Force reply / Reply keyboard
Telegram 的 ForceReply / ReplyKeyboardMarkup(让用户从一组按钮里选回答)→
Hashee 用 subtype: "form" artifact:
agent.sendArtifact(convId, { artifact: { artifact_id: ulid(), subtype: "form", title: "选择", payload: { fields: [{ id: "choice", type: "radio", label: "选一个", options: [{ id: "a", label: "A" }, { id: "b", label: "B" }], }], submit_label: "提交", }, },});// artifact_response.payload.payload.choice 是用户选的完整迁移示例
原 Telegram 版本(node-telegram-bot-api):
import TelegramBot from "node-telegram-bot-api";const bot = new TelegramBot(process.env.TELEGRAM_BOT_TOKEN!, { polling: true });
bot.onText(/\/poll (.+)/, (msg, m) => { const question = m![1]; bot.sendMessage(msg.chat.id, `投票:${question}`, { reply_markup: { inline_keyboard: [[ { text: "👍", callback_data: "up" }, { text: "👎", callback_data: "down" }, ]], }, });});
bot.on("callback_query", (q) => { bot.answerCallbackQuery(q.id); bot.sendMessage(q.message!.chat.id, `${q.from.first_name} 投了 ${q.data}`);});Hashee 版本:
import { HasheeAgent } from "@hasheeai/agent-sdk-ts";import { ulid } from "ulid";
const agent = await HasheeAgent.init({ agentId: process.env.HASHEE_AGENT_ID!, token: process.env.HASHEE_AGENT_TOKEN!, baseUrl: "https://api.hashee.ai", connectionMode: "websocket",});
const pollStore = new Map<string, string>(); // artifactId → question
agent.addMessageHandler(async (msg) => { if (msg.payload?.type !== "text") return; const m = msg.payload.text.match(/^\/poll\s+(.+)$/); if (!m) return; const question = m[1];
const artifactId = ulid(); pollStore.set(artifactId, question);
await agent.sendArtifact(msg.conversation_id, { artifact: { artifact_id: artifactId, subtype: "info", title: `投票:${question}`, payload: { body: question, actions: [ { id: "up", label: "👍", action: "vote_up" }, { id: "down", label: "👎", action: "vote_down" }, ], }, }, });});
agent.addEventHandler(async (event) => { if (event.type !== "artifact_response") return; const action = event.payload.action; if (action !== "vote_up" && action !== "vote_down") return; await agent.send(event.payload.conversation_id, { type: "text", text: `@<U:${event.sender_id}> 投了 ${action === "vote_up" ? "👍" : "👎"}`, mentions: [event.sender_id], });});
agent.addStatusHandler((s) => console.log(`[status] ${s}`));console.log("[migrated-tg-bot] up");部署对比
| Telegram | Hashee |
|---|---|
| Long polling(自托管) | WebSocket(自托管) |
| Webhook → 你的 server | Webhook → 你的 server |
| Single bot 多 chat | Single Agent 多 conversation(含群) |
| BotFather 创建 | Hashee app 内系统 Agent 创建 |
你可能会怀念的
- Inline mode(用户在任意聊天里
@yourbot query)→ Hashee V1 无对等 - Game platform → 可用 Artifact 实现(见 IM 小游戏)
- Payments API → V2 通过 Stripe Connect
- Chat actions 详细列表(typing / uploading_photo / 等)→ Hashee 仅
typing(),V2 评估
你会得到的(Telegram 没有)
- 端到端加密:Telegram 群组 + bot 通信走明文(仅 secret chat 端到端);Hashee 全部
- Agent 是一等公民:Telegram bot 不能加为联系人发文件给你;Hashee Agent 可以
- Tool Call with sensitivity:3 级权限
- 数据撤销审计:Grant Ledger append-only