@llblab/pi-telegram 0.9.8 → 0.9.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.9: Guest Mode HTML Rendering
4
+
5
+ - `[Guest Mode]` Guest replies now render through the same `renderTelegramMessage` pipeline as direct messages: Markdown → HTML → `answerGuestQuery` with `parse_mode: "HTML"`. Bold, italic, code, links, lists, and tables render identically in guest and DM replies.
6
+ - `[Replies]` Added `createGuestMarkdownReplySender` in the replies domain — guest rendering stays encapsulated within `replies.ts` and `index.ts` no longer imports from `rendering.ts` directly.
7
+ - `[API]` Simplified `answerGuestQuery` title to a fixed `"Response"` string (the `InlineQueryResultArticle` title is hidden in guest mode and was previously generated by stripping HTML/Markdown from the message text).
8
+ - `[API]` Removed `replyMarkup` parameter from `answerGuestQuery` — inline keyboards are not supported in guest mode because `callback_query` from inline results carries `inline_message_id` instead of `chat_id`/`message_id`, which the existing callback routing cannot handle.
9
+
3
10
  ## 0.9.8: Guest Mode Context
4
11
 
5
12
  - `[Guest Mode]` Extended the [telegram] prefix with |from:user (sender) and |guest:GroupName (source chat for group guest messages) so the agent sees who sent the message and where from. Private guest chats omit the guest: suffix.
package/index.ts CHANGED
@@ -157,6 +157,11 @@ export default function (pi: Pi.ExtensionAPI) {
157
157
 
158
158
  // --- Message Delivery & Preview ---
159
159
 
160
+ const sendGuestReply = Replies.createGuestMarkdownReplySender({
161
+ renderTelegramMessage: Replies.renderTelegramMessage,
162
+ answerGuestQuery,
163
+ });
164
+
160
165
  const promptDispatchRuntime =
161
166
  Runtime.createTelegramPromptDispatchRuntime<Pi.ExtensionContext>({
162
167
  lifecycle,
@@ -497,6 +502,7 @@ export default function (pi: Pi.ExtensionAPI) {
497
502
  sendTextReply,
498
503
  sendQueuedAttachments: queuedAttachmentSender,
499
504
  answerGuestQuery,
505
+ sendGuestReply,
500
506
  planOutboundReply: outboundReplyPlanner,
501
507
  sendOutboundReplyArtifacts: outboundReplyArtifactSender,
502
508
  isCurrentOwner: lockOwnershipGuard.ownsContext,
package/lib/api.ts CHANGED
@@ -256,7 +256,11 @@ export interface TelegramApiClient {
256
256
  callbackQueryId: string,
257
257
  text?: string,
258
258
  ) => Promise<void>;
259
- answerGuestQuery?: (guestQueryId: string, text?: string) => Promise<void>;
259
+ answerGuestQuery?: (
260
+ guestQueryId: string,
261
+ text?: string,
262
+ options?: { parseMode?: string },
263
+ ) => Promise<void>;
260
264
  }
261
265
 
262
266
  export interface TelegramBridgeApiRuntimeDeps {
@@ -314,7 +318,11 @@ export interface TelegramBridgeApiRuntime {
314
318
  callbackQueryId: string,
315
319
  text?: string,
316
320
  ) => Promise<void>;
317
- answerGuestQuery: (guestQueryId: string, text?: string) => Promise<void>;
321
+ answerGuestQuery: (
322
+ guestQueryId: string,
323
+ text?: string,
324
+ options?: { parseMode?: string },
325
+ ) => Promise<void>;
318
326
  prepareTempDir: () => Promise<number>;
319
327
  }
320
328
 
@@ -785,14 +793,24 @@ export function createTelegramBridgeApiRuntime(
785
793
  answerCallbackQuery: (callbackQueryId, text) => {
786
794
  return deps.client.answerCallbackQuery(callbackQueryId, text);
787
795
  },
788
- answerGuestQuery: (guestQueryId, text) => {
796
+ answerGuestQuery: (
797
+ guestQueryId: string,
798
+ text: string | undefined,
799
+ options: { parseMode?: string } | undefined,
800
+ ) => {
789
801
  const body: Record<string, unknown> = { guest_query_id: guestQueryId };
790
802
  if (text !== undefined) {
803
+ const inputContent: Record<string, unknown> = {
804
+ message_text: text,
805
+ };
806
+ if (options?.parseMode) {
807
+ inputContent.parse_mode = options.parseMode;
808
+ }
791
809
  body.result = {
792
810
  type: "article",
793
811
  id: "1",
794
- title: text.length > 64 ? text.slice(0, 61) + "..." : text,
795
- input_message_content: { message_text: text },
812
+ title: "Response",
813
+ input_message_content: inputContent,
796
814
  };
797
815
  }
798
816
  return callRecorded<void>("answerGuestQuery", body);
package/lib/queue.ts CHANGED
@@ -788,7 +788,8 @@ export interface TelegramAgentEndRuntimeDeps<
788
788
  text: string,
789
789
  ) => Promise<unknown>;
790
790
  sendQueuedAttachments: (turn: TTurn) => Promise<void>;
791
- answerGuestQuery?: (guestQueryId: string, text?: string) => Promise<void>;
791
+ answerGuestQuery?: (guestQueryId: string, text?: string, options?: { parseMode?: string }) => Promise<void>;
792
+ sendGuestReply?: (guestQueryId: string, markdown: string) => Promise<void>;
792
793
  planOutboundReply?: (
793
794
  markdown: string,
794
795
  ) => TelegramAgentEndOutboundReplyPlan<TReplyMarkup>;
@@ -837,6 +838,7 @@ export interface TelegramAgentEndHookRuntimeDeps<
837
838
  sendTextReply: TelegramAgentEndRuntimeDeps<TTurn>["sendTextReply"];
838
839
  sendQueuedAttachments: (turn: TTurn) => Promise<void>;
839
840
  answerGuestQuery?: TelegramAgentEndRuntimeDeps<TTurn>["answerGuestQuery"];
841
+ sendGuestReply?: TelegramAgentEndRuntimeDeps<TTurn>["sendGuestReply"];
840
842
  planOutboundReply?: TelegramAgentEndRuntimeDeps<
841
843
  TTurn,
842
844
  TReplyMarkup
@@ -958,6 +960,7 @@ export function createTelegramAgentEndHook<
958
960
  sendTextReply: deps.sendTextReply,
959
961
  sendQueuedAttachments: deps.sendQueuedAttachments,
960
962
  answerGuestQuery: deps.answerGuestQuery,
963
+ sendGuestReply: deps.sendGuestReply,
961
964
  planOutboundReply: deps.planOutboundReply,
962
965
  sendOutboundReplyArtifacts: deps.sendOutboundReplyArtifacts,
963
966
  getDefaultChatId: deps.getDefaultChatId,
@@ -1027,7 +1030,11 @@ export async function handleTelegramAgentEndRuntime<
1027
1030
  return;
1028
1031
  }
1029
1032
  if (finalText) {
1030
- await deps.answerGuestQuery?.(turn.guestQueryId, finalText);
1033
+ if (deps.sendGuestReply) {
1034
+ await deps.sendGuestReply(turn.guestQueryId, finalText);
1035
+ } else {
1036
+ await deps.answerGuestQuery?.(turn.guestQueryId, finalText);
1037
+ }
1031
1038
  }
1032
1039
  if (endPlan.shouldDispatchNext) deps.dispatchNextQueuedTelegramTurn();
1033
1040
  return;
package/lib/replies.ts CHANGED
@@ -11,6 +11,12 @@ import {
11
11
  type TelegramRenderMode,
12
12
  } from "./rendering.ts";
13
13
 
14
+ export {
15
+ renderTelegramMessage,
16
+ type TelegramRenderedChunk,
17
+ type TelegramRenderMode,
18
+ };
19
+
14
20
  // --- Reply Dedup ---
15
21
 
16
22
  /** Non-persistent reply deduplication for a single agent turn.
@@ -420,3 +426,26 @@ export function dedupSendMarkdownReply<TReplyMarkup = unknown>(
420
426
  return inner(chatId, effectiveReplyTo, markdown, options);
421
427
  };
422
428
  }
429
+
430
+ /**
431
+ * Guest reply sender: renders Markdown → HTML, sends via answerGuestQuery.
432
+ * Keeps guest rendering inside the replies domain so the orchestration layer
433
+ * (index.ts) does not import from rendering.ts directly.
434
+ */
435
+ export function createGuestMarkdownReplySender(deps: {
436
+ renderTelegramMessage: (
437
+ text: string,
438
+ options?: { mode?: TelegramRenderMode },
439
+ ) => TelegramRenderedChunk[];
440
+ answerGuestQuery: (
441
+ guestQueryId: string,
442
+ text?: string,
443
+ options?: { parseMode?: string },
444
+ ) => Promise<void>;
445
+ }) {
446
+ return async (guestQueryId: string, markdown: string) => {
447
+ const chunks = deps.renderTelegramMessage(markdown, { mode: "markdown" });
448
+ const html = chunks.length > 0 ? chunks[0].text : markdown;
449
+ await deps.answerGuestQuery(guestQueryId, html, { parseMode: "HTML" });
450
+ };
451
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.9.8",
3
+ "version": "0.9.9",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"