Important
This project is still a work in progress. If you encounter any bugs, please let me know.
- Multi Sessions.
- Database Node:Sqlite / Mongodb / MySQL.
- AI Rich and Button message.
- Auto-Heal Files.
- Fast Website.
- No Encrypted Files.
AI INFO
'Model Used:'
Gemini 3.1 Lite-Flash > Daily conversation
Gemini 3.1 Lite > Daily conversation but more complex
Gemma-4-31b-it > For system Auto-heal / coding
Gemma-4-26b-a4b-it > For system Auto-heal / codingPlugin Error
β
Detect error line, Read stack trace
β
Auto-Heal using AI Gemma 4
β
Write file & Save
β
DoneAll MCP Helper
-- Session / chat history --
getSession(jid) get chat history array for a chat
resetSession(jid) clear chat history for a chat
getPinnedNotesReadOnly(jid) get notes pinned to a chat
-- Talking to the AI / agent loop --
runAgent(conn, m, text, opts) run a full AI turn, get a reply
runAgentConfirmed(conn, m, opts) resume an agent turn awaiting confirmation
callTool(name, args) call another registered tool by name
listTools() / countTools() list / count registered tools
-- Identity & permissions --
getUserIdentity(jid, db, conn) get sender's name/number/owner/timezone
checkGroupAdminOrOwner(groupJid) check if sender is group admin/owner
readGroupSettings(groupJid) read group settings from brain storage
readOwnerList() list registered bot owners
-- Persistent storage ("brain") --
loadBrain() / saveBrain(brain) read/write ai-brain.json
ensureBrainGroupSlot(brain, jid) ensure a group slot exists in brain
-- Web & media --
searchWebGrounded(query) grounded web search
captureWebsiteScreenshot(url) screenshot a webpage
fetchWebsiteHtmlFallback(url) fetch raw HTML of a page
peekFetchBuffer(url, headers) peek a file buffer from a URL
peekFetchVideoBuffer(url, maxBytes, headers) peek a video buffer from a URL
detectPlatform(url) detect platform (YouTube/TikTok/etc)
peekAnalyzeWithVision(mediaItems, platform, url, context) analyze media with vision model
buildMediaPart(m) extract image/video/audio from a message
fetchSocialMulti(url) download helper for social media
downloadUserImageAsUrl(m) upload user's image, get back a URL
-- File & data tools --
readFileToolCore(file_path, offset) core logic behind "read file" tool
buildSimpleDiff(oldStr, newStr) build a text diff between two strings
parseDbKeyPath(key_path) parse a dotted key path for db access
-- Plugin execution (advanced/internal) --
resolvePlugin(command) find which plugin matches a command
resolveCustomPrefixPlugin(rawInput) same, for custom-prefix commands
execPluginCommand(command, argsStr, opts) run an existing bot plugin/command
execEval(code, opts) evaluate raw JS code (owner-only, dangerous)
classifyPluginRisk(name, plugin) classify a plugin's risk level
accessLabel(level) / riskBadge(level) risk-level label/badge helpers
pluginRequirements(plugin) get a plugin's access requirements
getDangerousDocReason(m) check if a message/doc looks risky
-- Error handling & internals (rarely needed in tools) --
handleError(conn, m, err, pluginName) central error handler/reporter
isTransientApiError(err) check if an API error is transient
getApiKeys() / getNextKey() / rotateKey() / resetRateLimit(jid) API key pool mgmt
normalizeApiKeys(input) format/clean a raw API key list
getPersonality() get bot's configured personality/system prompt
MODELS map of available AI models
setCurrentContext(...) / hasPending() / confirmPending() / cancelPending()
internal turn/state mgmt (used by mcp.js itself)
/*
ctx() -> Returns the current chat state (always fresh, since it's a function
call, not a stored variable). Common fields:
- currentJid : the id of the chat/user sending the message
- conn : the active WhatsApp connection (for manual sendMessage)
- isOwner : true if the sender is the bot owner
getMcp() -> Async function to access helpers from mcp.js. Must be called
INSIDE execute(), never at the top of the file -- importing
mcp.js directly at the top would cause a circular import
deadlock, since mcp.js is the one loading this file in the
first place.
*/
import { ctx, getMcp } from '../context.js'
export default [
{
name: 'check_weather',
description: 'Check the weather for a specific city. Use it when a user asks for the weather, e.g., "What\'s the weather like in Jakarta?"',
parameters: {
city: { type: 'string', description: 'City name, e.g. "Jakarta"', required: true }
},
execute: async ({ city }) => {
const { currentJid } = ctx()
if (!currentJid) return 'Chat context not available'
// const { runAgent } = await getMcp() // only if you need a helper from mcp.js
return `Weather in ${city}: sunny, 30Β°C`
}
}
]SEND MESSAGE
//---Basic---
conn.reply(m.chat, 'Hello world!', m)
conn.sendFile(m.chat, media, filename, caption, m)
// media > buffer / fs path
// voice note > { ptt: true }
// document > { document: true }
conn.sendContact(m.chat, [
['6281234567890', 'HirooSy'],
['6289876543210', 'Hiro']
], m)
conn.react(m.chat, 'π', m.key)//---location interactive ---
conn.sendLocUrl(m.chat, 'https://example.com/thumb.jpg', 'Title', 'Address', 'Text', 'Footer', 'https://github.com/hiroosy', m)
//--- Url Preview ---
conn.sendUrlPreview(
m.chat,
'https://example.com/thumb.jpg',
'https://example.com Hello World!',
'Url Preview Title',
'Url Description',
'IMAGE', // true for highQuality, or ['IMAGE', true]
m
)
//--- Carousel ---
conn.sendButton(m.chat, {
text: 'Interactive with Carousel!',
footer: 'HirooSy',
cards: [
{
image: { url: './path/to/image.jpg' },
caption: 'Image 1',
footer: 'Image 1',
nativeFlow: [{ text: 'Source', url: 'https://example.com', useWebview: true }]
},
{
image: { url: 'https://example.com/image.png' },
caption: 'Image 2',
footer: 'Image 2',
ltoText: 'New Coupon!',
ltoCode: 'HiroBot',
ltoUrl: 'https://example.com',
nativeFlow: [{ text: 'Source', url: 'https://example.com' }]
}
]
}, m)
//--- Interactive buttons ---
conn.sendButton(m.chat, {
image: { url: './path/to/image.jpg' },
caption: 'Interactive!',
footer: 'My Bot',
optionText: 'Select Options',
optionTitle: 'Select Options',
ltoText: 'HirooSy',
ltoCode: 'Hiro bot',
ltoUrl: 'https://example.com',
nativeFlow: [
{ text: 'ππ» Greeting', id: '#Greeting' },
{ text: 'π Call', call: '628123456789' },
{ text: 'π Copy', copy: 'Hiro bot' },
{ text: 'π Source', url: 'https://example.com', useWebview: true },
{
text: 'π Select',
sections: [
{ title: 'β¨ Section 1', rows: [{ header: '', title: 'π·οΈ Coupon', description: '', id: '#CouponCode' }] },
{ title: 'β¨ Section 2', highlight_label: 'π₯ Popular', rows: [{ header: '', title: 'π Secret Ingredient', description: '', id: '#SecretIngredient' }] }
],
}
]
}, m)
//--- Ai Rich ---
await conn.aiRich()
.setTitle('Ai Rich Message')
.addText('[HyperLink](https://example.com)\nCitation [](https://example.com)'\n[x^2+y^2=r^2|100|100](https://example.com/latex.png))
.addImage('https://example.com/image.png')
.addCode('javascript', `console.log('Hello World')`)
.addTable([
['Name', 'HirooSy'],
['Bio', 'Im developer'],
['Age', '67']
])
.addSource([['https://example.com/favicon.ico', 'https://example.com', 'Source']])
.addTip('Tip Text')
.addSuggest(['Continue', 'Cancel'])
.send(m.chat, { quoted: m })
//--- Sticker Pack ---
// Media = buffer / path
conn.sendStickerPack(m.chat, {
cover: { url: media },
stickers: [
{ data: { url: media } },
{ data: { url: media } },
],
name: 'My Sticker Pack',
publisher: 'Publisher stickerpack',
description: 'Description pack'
})MORE INFO
.
βββ lib
β βββ ai // Ai system
β βββ config.js // Set your bot's preference here
β βββ connection.js // connection manager
β βββ database.js // database manager
β βββ handler.js // event handler
β βββ helper.js // lib helper
β βββ import.js // plugin importer
β βββ main.js // Tunnel, all interval
β βββ scraper // Scrapers
β βββ server.js // Website endpoint
β βββ simple.js // Functions conn
β βββ start.js // Start script
β βββ store.js // Store connection
β βββ tools // Tools
β βββ views // HTML folder
βββ data // Sessions, database, TMP, Tunnel data, All .json
βββ plugins // commands here
βββ .env // Set your tokens here
βββ package.json
βββ README.mdlet handler = async (m, { conn }) => {
// Your code here
};
handler.command = Array / String
handler.help = Array / String
handler.rowner = Boolean
handler.owner = Boolean
handler.mods = Boolean
handler.group = Boolean
handler.private = Boolean
handler.botAdmin = Boolean
handler.premium = Boolean
handler.admin = Boolean
handler.limit = Boolean / Numberic
handler.level = Numberic
handler.customPrefix = String
handler.ai = Array
handler.dym = Array / String
export default handlerlet handler = (m) => m;
handler.before = async (m, { conn }) => {
//your code here
};
export default handler;πͺ§ Export style :
export default {
run: async (m, { conn }) => {
// your code here
},
command: Array / String,
tags: Array / String,
help: Array / String,
rowner: Boolean,
owner: Boolean,
mods: Boolean,
group: Boolean,
private: Boolean,
botAdmin: Boolean,
premium: Boolean,
admin: Boolean,
limit: Boolean / Numberic,
level: Numberic,
customPrefix: String,
ai: Array,
dym: Array / String,
}export default {
async before(m, { conn }) {
// your code here
},
};Warning
REQUIRE NODEJS V22+
$ git clone https://github.com/HirooSy/HIROBOT.git
$ npm install
$ cp .env.example .env
$ nano .env
$ npm start