feat: full service exposure with grammy bot + claudegram patterns
- Rewrote bot/index.js using grammy (@grammyjs/auto-retry + runner) - Added deduplication.js (adapted from claudegram) - Added request-queue.js (per-chat sequential processing) - Added message-sender.js (chunking + Markdown fallback) - Wired all JS-shim services: tools, skills, agents, config, RTK - Added function calling support to ZAIProvider.chat() - Added dynamic command routing (tools, skills, agents, model, stats) - Added per-agent delegation commands (/agent_coder, /agent_architect, etc.) - Added dedup + queue patterns from claudegram's battle-tested codebase - Updated zcode.js to pass agents to initBot() - Updated README feature comparison table to reflect real capabilities
This commit is contained in:
48
src/bot/message-sender.js
Normal file
48
src/bot/message-sender.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Adapted from claudegram's message-sender.ts — send with retry, chunking, fallback
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
const MAX_MSG_LENGTH = 4000;
|
||||
|
||||
export function splitMessage(text) {
|
||||
if (text.length <= MAX_MSG_LENGTH) return [text];
|
||||
const chunks = [];
|
||||
let remaining = text;
|
||||
while (remaining.length > 0) {
|
||||
chunks.push(remaining.slice(0, MAX_MSG_LENGTH));
|
||||
remaining = remaining.slice(MAX_MSG_LENGTH);
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
export function escapeMarkdown(text) {
|
||||
if (!text) return '';
|
||||
return text
|
||||
.replace(/_/g, '\\_')
|
||||
.replace(/\*/g, '\\*')
|
||||
.replace(/\[/g, '\\[')
|
||||
.replace(/`/g, '\\`');
|
||||
}
|
||||
|
||||
export async function sendFormatted(ctx, text) {
|
||||
if (!text) return;
|
||||
|
||||
try {
|
||||
// Try Markdown first
|
||||
const chunks = splitMessage(text);
|
||||
for (const chunk of chunks) {
|
||||
await ctx.reply(chunk, { parse_mode: 'Markdown' });
|
||||
}
|
||||
} catch {
|
||||
// Fallback to plain text
|
||||
logger.warn('Markdown send failed, falling back to plain text');
|
||||
const chunks = splitMessage(text);
|
||||
for (const chunk of chunks) {
|
||||
await ctx.reply(chunk, { parse_mode: undefined });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendLongMessage(ctx, text) {
|
||||
if (!text) return;
|
||||
return sendFormatted(ctx, text);
|
||||
}
|
||||
Reference in New Issue
Block a user