nanoclaw init
Some checks failed
Sync upstream & merge-forward skill branches / sync-and-merge (push) Has been cancelled
Merge-forward skill branches / merge-forward (push) Has been cancelled
Bump version / bump-version (push) Has been cancelled
Update token count / update-tokens (push) Has been cancelled

This commit is contained in:
woozu-shin
2026-03-24 01:43:09 +09:00
parent a1b8c70b5c
commit 4dc270d2dd
10 changed files with 1541 additions and 30 deletions

View File

@@ -12,6 +12,98 @@ import {
RegisteredGroup,
} from '../types.js';
// Bot pool for agent teams: send-only Api instances (no polling)
const poolApis: Api[] = [];
// Maps "{groupFolder}:{senderName}" → pool Api index for stable assignment
const senderBotMap = new Map<string, number>();
let nextPoolIndex = 0;
/**
* Initialize send-only Api instances for the bot pool.
* Each pool bot can send messages but doesn't poll for updates.
*/
export async function initBotPool(tokens: string[]): Promise<void> {
for (const token of tokens) {
try {
const api = new Api(token);
const me = await api.getMe();
poolApis.push(api);
logger.info(
{ username: me.username, id: me.id, poolSize: poolApis.length },
'Pool bot initialized',
);
} catch (err) {
logger.error({ err }, 'Failed to initialize pool bot');
}
}
if (poolApis.length > 0) {
logger.info({ count: poolApis.length }, 'Telegram bot pool ready');
}
}
/**
* Send a message via a pool bot assigned to the given sender name.
* Assigns bots round-robin on first use; subsequent messages from the
* same sender in the same group always use the same bot.
* On first assignment, renames the bot to match the sender's role.
*/
export async function sendPoolMessage(
chatId: string,
text: string,
sender: string,
groupFolder: string,
): Promise<void> {
if (poolApis.length === 0) {
// No pool bots — fall back to main bot sendMessage path
return;
}
const key = `${groupFolder}:${sender}`;
let idx = senderBotMap.get(key);
if (idx === undefined) {
idx = nextPoolIndex % poolApis.length;
nextPoolIndex++;
senderBotMap.set(key, idx);
// Rename the bot to match the sender's role, then wait for Telegram to propagate
try {
await poolApis[idx].setMyName(sender);
await new Promise((r) => setTimeout(r, 2000));
logger.info(
{ sender, groupFolder, poolIndex: idx },
'Assigned and renamed pool bot',
);
} catch (err) {
logger.warn(
{ sender, err },
'Failed to rename pool bot (sending anyway)',
);
}
}
const api = poolApis[idx];
try {
const numericId = chatId.replace(/^tg:/, '');
const MAX_LENGTH = 4096;
if (text.length <= MAX_LENGTH) {
await sendTelegramMessage(api, numericId, text);
} else {
for (let i = 0; i < text.length; i += MAX_LENGTH) {
await sendTelegramMessage(
api,
numericId,
text.slice(i, i + MAX_LENGTH),
);
}
}
logger.info(
{ chatId, sender, poolIndex: idx, length: text.length },
'Pool message sent',
);
} catch (err) {
logger.error({ chatId, sender, err }, 'Failed to send pool message');
}
}
export interface TelegramChannelOpts {
onMessage: OnInboundMessage;
onChatMetadata: OnChatMetadata;