talon-agent 3.15.1 → 3.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -70,7 +70,9 @@ export async function handleAdminCommand(
|
|
|
70
70
|
const model = formatModelLabel(
|
|
71
71
|
getChatSettings(s.chatId).model ?? config.model,
|
|
72
72
|
);
|
|
73
|
-
|
|
73
|
+
// `model` is a catalog id (OpenRouter/Kilo ids are free-form), so
|
|
74
|
+
// it gets the same escaping the title already had.
|
|
75
|
+
return `<b>${escapeHtml(title)}</b> <code>${s.chatId}</code>\n ${s.info.turns} turns | ${age} | ${escapeHtml(model)}`;
|
|
74
76
|
});
|
|
75
77
|
await ctx.reply(
|
|
76
78
|
`<b>Active chats (${sessions.length})</b>\n\n` + lines.join("\n\n"),
|
|
@@ -132,11 +132,17 @@ export function registerInfoCommands(bot: Bot): void {
|
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
134
|
const lines = plugins.map((p) => {
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
// Every field here is author-supplied manifest text, not just the
|
|
136
|
+
// name. A description like "R&D tools" or "<beta>" would otherwise
|
|
137
|
+
// reach Telegram as markup and 400 the whole listing, so `/plugins`
|
|
138
|
+
// would look dead rather than show one odd line.
|
|
139
|
+
const ver = p.plugin.version ? ` v${escapeHtml(p.plugin.version)}` : "";
|
|
140
|
+
const desc = p.plugin.description
|
|
141
|
+
? ` — ${escapeHtml(p.plugin.description)}`
|
|
142
|
+
: "";
|
|
137
143
|
const mcp = p.plugin.mcpServerPath ? " [MCP]" : "";
|
|
138
144
|
const fe = p.plugin.frontends?.length
|
|
139
|
-
? ` (${p.plugin.frontends.join(", ")})`
|
|
145
|
+
? ` (${escapeHtml(p.plugin.frontends.join(", "))})`
|
|
140
146
|
: "";
|
|
141
147
|
return `• <b>${escapeHtml(p.plugin.name)}</b>${ver}${mcp}${fe}${desc}`;
|
|
142
148
|
});
|
|
@@ -122,10 +122,16 @@ async function flushQueue(chatId: string): Promise<void> {
|
|
|
122
122
|
// Clear hourglass reactions on queued messages now that we're processing
|
|
123
123
|
for (const msgId of queuedReactionMsgIds) {
|
|
124
124
|
bot.api.setMessageReaction(numericChatId, msgId, []).catch((err) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
126
|
+
// The id is recorded optimistically — the hourglass `setMessageReaction`
|
|
127
|
+
// above is fire-and-forget, so we queue the clear before knowing the set
|
|
128
|
+
// landed. When it didn't, clearing a reaction that was never there comes
|
|
129
|
+
// back as REACTION_EMPTY. The end state we wanted (no reaction) already
|
|
130
|
+
// holds, so that is a no-op, not a failure. Keeping the optimistic push
|
|
131
|
+
// matters: gating it on the set resolving would race the flush and strand
|
|
132
|
+
// a ⏳ on the message. Anything else is still worth surfacing.
|
|
133
|
+
if (detail.includes("REACTION_EMPTY")) return;
|
|
134
|
+
logWarn("bot", `Failed to clear reaction on msg ${msgId}: ${detail}`);
|
|
129
135
|
});
|
|
130
136
|
}
|
|
131
137
|
|