@llblab/pi-kit 0.7.0 → 0.8.0

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-state-flow/AGENTS.md +21 -21
  4. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +3 -122
  5. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +11 -0
  6. package/node_modules/@llblab/pi-state-flow/README.md +41 -35
  7. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +36 -16
  8. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +4 -4
  9. package/node_modules/@llblab/pi-state-flow/index.ts +23 -1
  10. package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +3 -0
  11. package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +191 -29
  12. package/node_modules/@llblab/pi-state-flow/lib/config.ts +6 -1
  13. package/node_modules/@llblab/pi-state-flow/lib/context.ts +42 -7
  14. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +38 -8
  15. package/node_modules/@llblab/pi-state-flow/lib/episode.ts +1 -13
  16. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +290 -134
  17. package/node_modules/@llblab/pi-state-flow/lib/git.ts +32 -16
  18. package/node_modules/@llblab/pi-state-flow/lib/logging.ts +41 -0
  19. package/node_modules/@llblab/pi-state-flow/lib/maintenance.ts +12 -6
  20. package/node_modules/@llblab/pi-state-flow/lib/migration.ts +16 -0
  21. package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +3 -0
  22. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +167 -31
  23. package/node_modules/@llblab/pi-state-flow/lib/skills.ts +15 -6
  24. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +40 -34
  25. package/node_modules/@llblab/pi-state-flow/lib/state.ts +6 -0
  26. package/node_modules/@llblab/pi-state-flow/lib/status.ts +4 -9
  27. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +25 -5
  28. package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +17 -147
  29. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +49 -27
  30. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  31. package/node_modules/@llblab/pi-telegram/AGENTS.md +2 -2
  32. package/node_modules/@llblab/pi-telegram/BACKLOG.md +3 -2
  33. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +6 -1
  34. package/node_modules/@llblab/pi-telegram/README.md +1 -1
  35. package/node_modules/@llblab/pi-telegram/docs/architecture.md +8 -6
  36. package/node_modules/@llblab/pi-telegram/docs/public-api.md +4 -4
  37. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +18 -0
  38. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +32 -19
  39. package/node_modules/@llblab/pi-telegram/lib/bus.ts +5 -0
  40. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +189 -15
  41. package/node_modules/@llblab/pi-telegram/lib/commands.ts +3 -0
  42. package/node_modules/@llblab/pi-telegram/lib/config.ts +67 -4
  43. package/node_modules/@llblab/pi-telegram/lib/extension.ts +65 -6
  44. package/node_modules/@llblab/pi-telegram/lib/locks.ts +6 -1
  45. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +49 -3
  46. package/node_modules/@llblab/pi-telegram/lib/preview.ts +17 -0
  47. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +1 -0
  48. package/node_modules/@llblab/pi-telegram/lib/queue.ts +66 -8
  49. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +4 -1
  50. package/node_modules/@llblab/pi-telegram/lib/replies.ts +19 -0
  51. package/node_modules/@llblab/pi-telegram/lib/routing.ts +39 -0
  52. package/node_modules/@llblab/pi-telegram/lib/setup.ts +44 -4
  53. package/node_modules/@llblab/pi-telegram/lib/status.ts +41 -4
  54. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +74 -18
  55. package/node_modules/@llblab/pi-telegram/lib/turns.ts +7 -0
  56. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  57. package/package.json +3 -3
  58. package/node_modules/@llblab/pi-state-flow/lib/validation.ts +0 -27
  59. /package/node_modules/@llblab/pi-telegram/lib/{logs.ts → logging.ts} +0 -0
@@ -200,6 +200,10 @@ export interface TelegramSentMessage {
200
200
  message_id: number;
201
201
  }
202
202
 
203
+ export interface TelegramSentGuestMessage {
204
+ inline_message_id?: string;
205
+ }
206
+
203
207
  export interface TelegramReplyParameters {
204
208
  message_id: number;
205
209
  allow_sending_without_reply?: boolean;
@@ -427,6 +431,11 @@ export interface TelegramAnswerGuestQueryOptions {
427
431
  result?: TelegramGuestCachedMediaResult;
428
432
  }
429
433
 
434
+ export interface TelegramEditGuestInlineMessageContent {
435
+ text?: string;
436
+ richMessage?: TelegramInputRichMessage;
437
+ }
438
+
430
439
  export interface TelegramAnswerCallbackQueryOptions {
431
440
  recordRuntimeEvent?: (
432
441
  kind: "api",
@@ -810,6 +819,21 @@ export interface TelegramBridgeApiRuntime {
810
819
  text?: string,
811
820
  options?: TelegramAnswerGuestQueryOptions,
812
821
  ) => Promise<void>;
822
+ /**
823
+ * Temporary Guest Mode ACK experiment: answers the guest query and returns
824
+ * the sent inline message id so the final answer can edit that early reply.
825
+ * Requires direct transport ownership; Telegram does not document editing
826
+ * guest answers, so this exists only to falsify that behavior live.
827
+ */
828
+ answerGuestQueryForInlineMessage: (
829
+ guestQueryId: string,
830
+ text?: string,
831
+ options?: TelegramAnswerGuestQueryOptions,
832
+ ) => Promise<string | undefined>;
833
+ editGuestInlineMessage: (
834
+ inlineMessageId: string,
835
+ content: TelegramEditGuestInlineMessageContent,
836
+ ) => Promise<void>;
813
837
  deleteMessage: (chatId: number, messageId: number) => Promise<void>;
814
838
  prepareTempDir: () => Promise<number>;
815
839
  }
@@ -1700,6 +1724,31 @@ export function createTelegramAssistantDraftSender(deps: {
1700
1724
  };
1701
1725
  }
1702
1726
 
1727
+ export function buildTelegramAnswerGuestQueryBody(
1728
+ guestQueryId: string,
1729
+ text?: string,
1730
+ options?: TelegramAnswerGuestQueryOptions,
1731
+ ): Record<string, unknown> {
1732
+ const body: Record<string, unknown> = { guest_query_id: guestQueryId };
1733
+ if (options?.result) {
1734
+ body.result = options.result;
1735
+ } else if (text !== undefined || options?.richMessage) {
1736
+ const inputContent: Record<string, unknown> = options?.richMessage
1737
+ ? { rich_message: options.richMessage }
1738
+ : { message_text: text };
1739
+ if (!options?.richMessage && options?.parseMode) {
1740
+ inputContent.parse_mode = options.parseMode;
1741
+ }
1742
+ body.result = {
1743
+ type: "article",
1744
+ id: "1",
1745
+ title: "Response",
1746
+ input_message_content: inputContent,
1747
+ };
1748
+ }
1749
+ return body;
1750
+ }
1751
+
1703
1752
  export function createDefaultTelegramBridgeApiRuntime(deps: {
1704
1753
  getBotToken: () => string | undefined;
1705
1754
  recordRuntimeEvent: TelegramBridgeApiRuntimeDeps["recordRuntimeEvent"];
@@ -2021,25 +2070,32 @@ export function createTelegramBridgeApiRuntime(
2021
2070
  guestQueryId: string,
2022
2071
  text: string | undefined,
2023
2072
  options: TelegramAnswerGuestQueryOptions | undefined,
2073
+ ) =>
2074
+ callRecorded<void>(
2075
+ "answerGuestQuery",
2076
+ buildTelegramAnswerGuestQueryBody(guestQueryId, text, options),
2077
+ ),
2078
+ answerGuestQueryForInlineMessage: async (
2079
+ guestQueryId: string,
2080
+ text: string | undefined,
2081
+ options: TelegramAnswerGuestQueryOptions | undefined,
2024
2082
  ) => {
2025
- const body: Record<string, unknown> = { guest_query_id: guestQueryId };
2026
- if (options?.result) {
2027
- body.result = options.result;
2028
- } else if (text !== undefined || options?.richMessage) {
2029
- const inputContent: Record<string, unknown> = options?.richMessage
2030
- ? { rich_message: options.richMessage }
2031
- : { message_text: text };
2032
- if (!options?.richMessage && options?.parseMode) {
2033
- inputContent.parse_mode = options.parseMode;
2034
- }
2035
- body.result = {
2036
- type: "article",
2037
- id: "1",
2038
- title: "Response",
2039
- input_message_content: inputContent,
2040
- };
2041
- }
2042
- return callRecorded<void>("answerGuestQuery", body);
2083
+ const sent = await callRecorded<TelegramSentGuestMessage | undefined>(
2084
+ "answerGuestQuery",
2085
+ buildTelegramAnswerGuestQueryBody(guestQueryId, text, options),
2086
+ );
2087
+ return sent?.inline_message_id;
2088
+ },
2089
+ editGuestInlineMessage: async (
2090
+ inlineMessageId: string,
2091
+ content: TelegramEditGuestInlineMessageContent,
2092
+ ) => {
2093
+ await callRecorded("editMessageText", {
2094
+ inline_message_id: inlineMessageId,
2095
+ ...(content.richMessage
2096
+ ? { rich_message: content.richMessage }
2097
+ : { text: content.text }),
2098
+ });
2043
2099
  },
2044
2100
  prepareTempDir: () =>
2045
2101
  prepareTelegramTempDir(deps.tempDir, deps.tempFileMaxAgeMs),
@@ -41,6 +41,9 @@ import {
41
41
 
42
42
  export const TELEGRAM_PREFIX = "[telegram]";
43
43
 
44
+ export const TELEGRAM_GUEST_TURN_NOTE =
45
+ "[guest] delivery: answer quickly with one concise, self-contained reply";
46
+
44
47
  export interface TelegramTurnTarget {
45
48
  chatId: number;
46
49
  threadId?: number;
@@ -198,6 +201,7 @@ export function buildTelegramTurnPrompt(options: {
198
201
  historyTurns?: Pick<PendingTelegramTurn, "historyText">[];
199
202
  timeLine?: string | null;
200
203
  voiceContext?: Record<string, string>;
204
+ guestTurn?: boolean;
201
205
  }): string {
202
206
  let prompt = options.telegramPrefix;
203
207
  if ((options.historyTurns?.length ?? 0) > 0) {
@@ -229,6 +233,9 @@ export function buildTelegramTurnPrompt(options: {
229
233
  if (options.timeLine) {
230
234
  prompt = `${prompt}\n\n[time] ${options.timeLine}`;
231
235
  }
236
+ if (options.guestTurn) {
237
+ prompt = `${prompt}\n\n${TELEGRAM_GUEST_TURN_NOTE}`;
238
+ }
232
239
  return prompt;
233
240
  }
234
241
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.45.0",
3
+ "version": "0.45.1",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -44,8 +44,8 @@
44
44
  "@llblab/pi-clean-room": "0.1.1",
45
45
  "@llblab/pi-codex-usage": "0.9.4",
46
46
  "@llblab/pi-grow-loop": "0.7.5",
47
- "@llblab/pi-state-flow": "0.6.0",
48
- "@llblab/pi-telegram": "0.45.0",
47
+ "@llblab/pi-state-flow": "0.7.0",
48
+ "@llblab/pi-telegram": "0.45.1",
49
49
  "@llblab/skills": "1.15.0"
50
50
  },
51
51
  "bundledDependencies": [
@@ -1,27 +0,0 @@
1
- import { terminalRegenerationInstruction } from "./terminal.ts";
2
-
3
- export const MAX_VALIDATION_RETRIES = 3;
4
-
5
- export interface ValidationFeedback {
6
- attempt: number;
7
- error: string;
8
- instruction: string;
9
- }
10
-
11
- export type ValidationDecision =
12
- | { kind: "retry"; feedback: ValidationFeedback }
13
- | { kind: "exhausted"; error: string };
14
-
15
- /** Decide retry progression without mutating persistent runtime state. */
16
- export function nextValidation(previous: ValidationFeedback | undefined, error: string): ValidationDecision {
17
- const attempt = (previous?.attempt ?? 0) + 1;
18
- if (attempt > MAX_VALIDATION_RETRIES) return { kind: "exhausted", error };
19
- return {
20
- kind: "retry",
21
- feedback: {
22
- attempt,
23
- error,
24
- instruction: terminalRegenerationInstruction(error),
25
- },
26
- };
27
- }