talon-agent 4.3.3 → 4.4.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 (105) hide show
  1. package/package.json +1 -1
  2. package/src/app.ts +1 -1
  3. package/src/backend/claude-sdk/state.ts +1 -1
  4. package/src/backend/codex/init.ts +1 -1
  5. package/src/backend/codex/state.ts +1 -1
  6. package/src/backend/openai-agents/init.ts +1 -1
  7. package/src/backend/openai-agents/state.ts +1 -1
  8. package/src/backend/remote-server/factory.ts +1 -1
  9. package/src/backend/remote-server/mcp.ts +1 -1
  10. package/src/backend/remote-server/server-bindings.ts +1 -1
  11. package/src/backend/remote-server/state.ts +1 -1
  12. package/src/backend/shared/system-prompt.ts +1 -1
  13. package/src/bootstrap.ts +2 -2
  14. package/src/cli/chat.ts +1 -1
  15. package/src/cli/config.ts +2 -2
  16. package/src/cli/index.ts +8 -0
  17. package/src/cli/memory.ts +166 -0
  18. package/src/cli/setup.ts +1 -1
  19. package/src/core/agent-runtime/backend-registry.ts +1 -1
  20. package/src/core/agent-runtime/model-ref.ts +2 -2
  21. package/src/{util/config.ts → core/config/index.ts} +8 -8
  22. package/src/core/engine/backend-controller/legacy.ts +1 -1
  23. package/src/core/engine/backend-controller/pool.ts +1 -1
  24. package/src/core/engine/backend-controller/rebind.ts +1 -1
  25. package/src/core/engine/backend-controller/state.ts +1 -1
  26. package/src/core/engine/gateway-actions/plugins.ts +1 -1
  27. package/src/core/engine/model-audit.ts +1 -1
  28. package/src/core/frontend-runtime/capabilities.ts +1 -1
  29. package/src/core/models/active-model.ts +1 -1
  30. package/src/core/plugin/builtins.ts +2 -2
  31. package/src/core/plugin/manage.ts +1 -1
  32. package/src/frontend/discord/admin.ts +1 -1
  33. package/src/frontend/discord/callbacks/components/index.ts +1 -1
  34. package/src/frontend/discord/callbacks/components/settings.ts +1 -1
  35. package/src/frontend/discord/callbacks/components/types.ts +1 -1
  36. package/src/frontend/discord/callbacks/modals.ts +1 -1
  37. package/src/frontend/discord/commands/admin.ts +1 -1
  38. package/src/frontend/discord/commands/definitions.ts +1 -1
  39. package/src/frontend/discord/commands/info.ts +1 -1
  40. package/src/frontend/discord/commands/router.ts +1 -1
  41. package/src/frontend/discord/commands/session.ts +1 -1
  42. package/src/frontend/discord/commands/settings.ts +1 -1
  43. package/src/frontend/discord/handlers/delivery.ts +1 -1
  44. package/src/frontend/discord/handlers/messages.ts +1 -1
  45. package/src/frontend/discord/handlers/queue.ts +1 -1
  46. package/src/frontend/discord/handlers/state.ts +1 -1
  47. package/src/frontend/discord/index.ts +1 -1
  48. package/src/frontend/discord/middleware.ts +1 -1
  49. package/src/frontend/discord/runtime.ts +1 -1
  50. package/src/frontend/native/extensions.ts +4 -1
  51. package/src/frontend/native/index.ts +1 -1
  52. package/src/frontend/native/runtime.ts +1 -1
  53. package/src/frontend/native/settings.ts +1 -1
  54. package/src/frontend/shared/model-commands.ts +1 -1
  55. package/src/frontend/shared/plan-usage-report.ts +1 -1
  56. package/src/frontend/shared/reasoning-levels.ts +1 -1
  57. package/src/frontend/shared/session-status.ts +1 -1
  58. package/src/frontend/teams/index.ts +1 -1
  59. package/src/frontend/teams/runtime.ts +1 -1
  60. package/src/frontend/telegram/actions/chat-info.ts +1 -1
  61. package/src/frontend/telegram/actions/coerce.ts +15 -0
  62. package/src/frontend/telegram/actions/index.ts +1 -1
  63. package/src/frontend/telegram/actions/media.ts +1 -1
  64. package/src/frontend/telegram/actions/messaging.ts +3 -4
  65. package/src/frontend/telegram/actions/moderation/chat.ts +1 -1
  66. package/src/frontend/telegram/actions/moderation/index.ts +1 -1
  67. package/src/frontend/telegram/actions/moderation/topics.ts +1 -1
  68. package/src/frontend/telegram/actions/rich-messages.ts +51 -0
  69. package/src/frontend/telegram/actions/{shared.ts → send.ts} +9 -59
  70. package/src/frontend/telegram/admin/sessions.ts +1 -1
  71. package/src/frontend/telegram/admin.ts +1 -1
  72. package/src/frontend/telegram/callbacks/auth.ts +1 -1
  73. package/src/frontend/telegram/callbacks/effort.ts +1 -1
  74. package/src/frontend/telegram/callbacks/index.ts +3 -3
  75. package/src/frontend/telegram/callbacks/metrics.ts +1 -1
  76. package/src/frontend/telegram/callbacks/model/backend.ts +1 -1
  77. package/src/frontend/telegram/callbacks/model/control.ts +1 -1
  78. package/src/frontend/telegram/callbacks/model/select.ts +1 -1
  79. package/src/frontend/telegram/callbacks/model/types.ts +1 -1
  80. package/src/frontend/telegram/callbacks/model/views.ts +1 -1
  81. package/src/frontend/telegram/callbacks/model.ts +1 -1
  82. package/src/frontend/telegram/callbacks/pulse.ts +1 -1
  83. package/src/frontend/telegram/callbacks/{shared.ts → query.ts} +3 -2
  84. package/src/frontend/telegram/callbacks/settings.ts +1 -1
  85. package/src/frontend/telegram/callbacks/whatsapp.ts +1 -1
  86. package/src/frontend/telegram/commands/admin.ts +1 -1
  87. package/src/frontend/telegram/commands/index.ts +1 -1
  88. package/src/frontend/telegram/commands/state.ts +1 -1
  89. package/src/frontend/telegram/handlers/context.ts +1 -1
  90. package/src/frontend/telegram/handlers/delivery.ts +2 -2
  91. package/src/frontend/telegram/handlers/messages.ts +1 -1
  92. package/src/frontend/telegram/handlers/queue.ts +1 -1
  93. package/src/frontend/telegram/handlers/state.ts +1 -1
  94. package/src/frontend/telegram/index.ts +1 -1
  95. package/src/frontend/telegram/middleware.ts +1 -1
  96. package/src/frontend/telegram/model-menu.ts +1 -1
  97. package/src/frontend/terminal/command-registry.ts +1 -1
  98. package/src/frontend/terminal/index.ts +1 -1
  99. package/src/frontend/whatsapp/index.ts +1 -1
  100. package/src/frontend/whatsapp/runtime.ts +1 -1
  101. package/src/storage/memory.ts +505 -0
  102. package/src/storage/repositories/memory-repo.ts +308 -0
  103. package/src/storage/sql/memory.sql +95 -0
  104. package/src/storage/sql/schema.sql +81 -0
  105. package/src/storage/sql/statements.generated.ts +146 -0
@@ -9,7 +9,7 @@ import {
9
9
  type Interaction,
10
10
  MessageFlags,
11
11
  } from "discord.js";
12
- import type { TalonConfig } from "../../../util/config.js";
12
+ import type { TalonConfig } from "../../../core/config/index.js";
13
13
  import type { Gateway } from "../../../core/engine/gateway.js";
14
14
  import { logError } from "../../../util/log.js";
15
15
  import {
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { type ChatInputCommandInteraction, MessageFlags } from "discord.js";
9
- import type { TalonConfig } from "../../../util/config.js";
9
+ import type { TalonConfig } from "../../../core/config/index.js";
10
10
  import type { Gateway } from "../../../core/engine/gateway.js";
11
11
  import {
12
12
  formatModelLabel,
@@ -10,7 +10,7 @@ import {
10
10
  StringSelectMenuBuilder,
11
11
  MessageFlags,
12
12
  } from "discord.js";
13
- import type { TalonConfig } from "../../../util/config.js";
13
+ import type { TalonConfig } from "../../../core/config/index.js";
14
14
  import type { Gateway } from "../../../core/engine/gateway.js";
15
15
  import {
16
16
  getChatSettings,
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { TextBasedChannel } from "discord.js";
8
- import type { TalonConfig } from "../../../util/config.js";
8
+ import type { TalonConfig } from "../../../core/config/index.js";
9
9
  import { execute } from "../../../core/engine/dispatcher.js";
10
10
  import { toolInputToRecord } from "../../../core/agent-runtime/events.js";
11
11
  import { appendDailyLogResponse } from "../../../storage/daily-log.js";
@@ -6,7 +6,7 @@
6
6
 
7
7
  import type { Client, Message } from "discord.js";
8
8
  import { ChannelType } from "discord.js";
9
- import type { TalonConfig } from "../../../util/config.js";
9
+ import type { TalonConfig } from "../../../core/config/index.js";
10
10
  import { setMessageFilePath } from "../../../storage/history.js";
11
11
  import { addMedia } from "../../../storage/media-index.js";
12
12
  import { deriveNumericChatId } from "../../../util/chat-id.js";
@@ -25,7 +25,7 @@ import {
25
25
  MAX_QUEUED_PER_CHAT,
26
26
  type QueuedMessage,
27
27
  } from "./state.js";
28
- import type { TalonConfig } from "../../../util/config.js";
28
+ import type { TalonConfig } from "../../../core/config/index.js";
29
29
 
30
30
  export function enqueueMessage(
31
31
  config: TalonConfig,
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { TextBasedChannel } from "discord.js";
9
- import type { TalonConfig } from "../../../util/config.js";
9
+ import type { TalonConfig } from "../../../core/config/index.js";
10
10
  import {
11
11
  createDmUserTracker,
12
12
  createNoticeCooldown,
@@ -18,7 +18,7 @@
18
18
  * outbound, connection, and the handlers/commands/callbacks trees.
19
19
  */
20
20
 
21
- import type { TalonConfig } from "../../util/config.js";
21
+ import type { TalonConfig } from "../../core/config/index.js";
22
22
  import type { ContextManager } from "../../core/types.js";
23
23
  import type { Gateway } from "../../core/engine/gateway.js";
24
24
  import { log } from "../../util/log.js";
@@ -16,7 +16,7 @@
16
16
 
17
17
  import type { Client, Message } from "discord.js";
18
18
  import { ChannelType } from "discord.js";
19
- import type { TalonConfig } from "../../util/config.js";
19
+ import type { TalonConfig } from "../../core/config/index.js";
20
20
  import { pushMessage } from "../../storage/history.js";
21
21
  import { registerChat } from "../../core/background/pulse.js";
22
22
  import { deriveNumericChatId } from "../../util/chat-id.js";
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { Client, GatewayIntentBits, Partials } from "discord.js";
12
- import type { TalonConfig } from "../../util/config.js";
12
+ import type { TalonConfig } from "../../core/config/index.js";
13
13
  import type { Gateway } from "../../core/engine/gateway.js";
14
14
 
15
15
  /** `config.discord`, narrowed once — the factory refuses to build without it. */
@@ -23,7 +23,10 @@ import { getPluginPromptAdditions } from "../../core/plugin/index.js";
23
23
  import { listPluginItems, setPluginEnabled } from "../../core/plugin/manage.js";
24
24
  import { notifyPromptInputsChanged } from "../../core/prompt/invalidation.js";
25
25
  import { listSkills, setSkillEnabled } from "../../storage/skills.js";
26
- import { rebuildSystemPrompt, type TalonConfig } from "../../util/config.js";
26
+ import {
27
+ rebuildSystemPrompt,
28
+ type TalonConfig,
29
+ } from "../../core/config/index.js";
27
30
  import { log } from "../../util/log.js";
28
31
  import type { PluginItem, SkillItem, ToggleResult } from "./protocol.js";
29
32
  import { persistConfigPatch } from "./settings.js";
@@ -14,7 +14,7 @@
14
14
  * delegate to — chat-wire, context, emit, turn, models, history, ….
15
15
  */
16
16
 
17
- import type { TalonConfig } from "../../util/config.js";
17
+ import type { TalonConfig } from "../../core/config/index.js";
18
18
  import type { ContextManager } from "../../core/types.js";
19
19
  import type { Gateway } from "../../core/engine/gateway.js";
20
20
  import { log, logError } from "../../util/log.js";
@@ -8,7 +8,7 @@
8
8
  * message-id minter and the broadcast sink; the modules own the behaviour.
9
9
  */
10
10
 
11
- import type { TalonConfig } from "../../util/config.js";
11
+ import type { TalonConfig } from "../../core/config/index.js";
12
12
  import type { Gateway } from "../../core/engine/gateway.js";
13
13
  import { getMeshService, type MeshService } from "../../core/mesh/index.js";
14
14
  import { NativeChats } from "./chats.js";
@@ -14,7 +14,7 @@
14
14
  import { existsSync, readFileSync, mkdirSync } from "node:fs";
15
15
  import writeFileAtomic from "write-file-atomic";
16
16
  import { dirname } from "node:path";
17
- import type { TalonConfig } from "../../util/config.js";
17
+ import type { TalonConfig } from "../../core/config/index.js";
18
18
  import { files as pathFiles } from "../../util/paths.js";
19
19
  import { setTimezone } from "../../util/time.js";
20
20
  import { resolveModel } from "../../core/models/catalog.js";
@@ -10,7 +10,7 @@
10
10
  * about a socket, a bot API, or a keyboard.
11
11
  */
12
12
 
13
- import type { TalonConfig } from "../../util/config.js";
13
+ import type { TalonConfig } from "../../core/config/index.js";
14
14
  import type { Backend } from "../../core/agent-runtime/capabilities.js";
15
15
  import type { ReasoningEffortLevel } from "../../core/types.js";
16
16
  import {
@@ -9,7 +9,7 @@
9
9
  * never silence.
10
10
  */
11
11
 
12
- import type { TalonConfig } from "../../util/config.js";
12
+ import type { TalonConfig } from "../../core/config/index.js";
13
13
  import type { PlanUsage } from "../../core/agent-runtime/capabilities.js";
14
14
  import {
15
15
  listAvailableBackends,
@@ -4,7 +4,7 @@ import type {
4
4
  } from "../../core/types.js";
5
5
  import type { Backend } from "../../core/agent-runtime/capabilities.js";
6
6
  import { resolveActiveModelForChat } from "../../core/models/active-model.js";
7
- import type { TalonConfig } from "../../util/config.js";
7
+ import type { TalonConfig } from "../../core/config/index.js";
8
8
  import {
9
9
  normalizeReasoningLevels,
10
10
  supportsReasoningLevel,
@@ -9,7 +9,7 @@
9
9
  * markup.
10
10
  */
11
11
 
12
- import type { TalonConfig } from "../../util/config.js";
12
+ import type { TalonConfig } from "../../core/config/index.js";
13
13
  import type { Backend } from "../../core/agent-runtime/capabilities.js";
14
14
  import {
15
15
  resetSession,
@@ -12,7 +12,7 @@
12
12
  * chat-discovery, poll, commands, turn, outbound.
13
13
  */
14
14
 
15
- import type { TalonConfig } from "../../util/config.js";
15
+ import type { TalonConfig } from "../../core/config/index.js";
16
16
  import type { ContextManager } from "../../core/types.js";
17
17
  import type { Gateway } from "../../core/engine/gateway.js";
18
18
  import { log } from "../../util/log.js";
@@ -7,7 +7,7 @@
7
7
  * poll, commands, turn, outbound) takes as its first parameter.
8
8
  */
9
9
 
10
- import type { TalonConfig } from "../../util/config.js";
10
+ import type { TalonConfig } from "../../core/config/index.js";
11
11
  import type { Gateway } from "../../core/engine/gateway.js";
12
12
  import type { GraphClient } from "./graph.js";
13
13
 
@@ -22,7 +22,7 @@ import {
22
22
  getOnlineCount as userbotOnlineCount,
23
23
  } from "../userbot.js";
24
24
  import { savePackToLibrary } from "../sticker-library.js";
25
- import { toPositiveId } from "./shared.js";
25
+ import { toPositiveId } from "./coerce.js";
26
26
  import type { TelegramActionHandlers } from "./types.js";
27
27
 
28
28
  export const chatInfoHandlers: TelegramActionHandlers = {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Id coercion for the Telegram action handlers.
3
+ */
4
+
5
+ /**
6
+ * Telegram/GramJS APIs expect numeric IDs. `snowflakeOrIdSchema` normalizes IDs
7
+ * to digit-strings (so 17-19 digit Discord snowflakes survive validation), so a
8
+ * Telegram message/reply/offset ID can arrive here as a string. Coerce it back
9
+ * to a positive integer: Telegram IDs are well within 2^53, so this is lossless.
10
+ * Returns undefined for missing / non-positive / non-integer values.
11
+ */
12
+ export function toPositiveId(v: unknown): number | undefined {
13
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
14
+ return Number.isInteger(n) && n > 0 ? n : undefined;
15
+ }
@@ -25,7 +25,7 @@ import { chatInfoHandlers } from "./chat-info.js";
25
25
  import { moderationHandlers } from "./moderation/index.js";
26
26
  import type { TelegramActionContext, TelegramActionHandlers } from "./types.js";
27
27
 
28
- export { sendText } from "./shared.js";
28
+ export { sendText } from "./send.js";
29
29
 
30
30
  // Null-prototype so a request `action` of "toString" / "constructor" / etc.
31
31
  // can't resolve an inherited Object.prototype method via `handlers[action]`.
@@ -9,7 +9,7 @@ import { expandFsPath } from "../../../util/fs-path.js";
9
9
  import { markdownToTelegramHtml } from "../formatting.js";
10
10
  import { withRetry } from "../../../core/engine/gateway.js";
11
11
  import { resolveStickerByEmoji } from "../sticker-library.js";
12
- import { replyParams, sendOpts } from "./shared.js";
12
+ import { replyParams, sendOpts } from "./send.js";
13
13
  import type { TelegramActionHandlers } from "./types.js";
14
14
 
15
15
  type MediaSource = {
@@ -15,13 +15,12 @@ import {
15
15
  MAX_OVERDUE_MS,
16
16
  type ScheduledMessage,
17
17
  } from "../../../storage/scheduled.js";
18
+ import { sendOpts, sendText } from "./send.js";
18
19
  import {
19
20
  noteRichMessageFailure,
20
21
  richMessagesAvailable,
21
- sendOpts,
22
- sendText,
23
- toPositiveId,
24
- } from "./shared.js";
22
+ } from "./rich-messages.js";
23
+ import { toPositiveId } from "./coerce.js";
25
24
  import { resolveThreadId } from "../topics.js";
26
25
  import { TELEGRAM_MAX_TEXT, type TelegramActionHandlers } from "./types.js";
27
26
 
@@ -3,7 +3,7 @@
3
3
  * leave_chat.
4
4
  */
5
5
 
6
- import { toPositiveId } from "../shared.js";
6
+ import { toPositiveId } from "../coerce.js";
7
7
  import { resolveMediaInput } from "../media.js";
8
8
  import { toChatPermissions } from "./permissions.js";
9
9
  import type { ModerationOps } from "./types.js";
@@ -14,7 +14,7 @@
14
14
  * - `topics` — create / edit / close / reopen / delete_topic
15
15
  */
16
16
 
17
- import { toPositiveId } from "../shared.js";
17
+ import { toPositiveId } from "../coerce.js";
18
18
  import type { TelegramActionHandlers } from "../types.js";
19
19
  import { memberOps } from "./members.js";
20
20
  import { chatOps } from "./chat.js";
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { Bot } from "grammy";
6
- import { toPositiveId } from "../shared.js";
6
+ import { toPositiveId } from "../coerce.js";
7
7
  import type { ModerationOp, ModerationOps } from "./types.js";
8
8
 
9
9
  /** An op on an existing topic: validates `thread_id`, then runs `call`. */
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Rich Messages capability probe — whether native Rich Markdown delivery is
3
+ * worth attempting on this Bot API server, latched off on the first
4
+ * "method not found".
5
+ */
6
+
7
+ import { logWarn } from "../../../util/log.js";
8
+
9
+ /**
10
+ * Rich Messages arrived in Bot API 10.2. A self-hosted Bot API server (or a
11
+ * deployment pinned to an older release) rejects `sendRichMessage` outright,
12
+ * and retrying it per message would cost a doomed round-trip plus a warning
13
+ * line on every single send. Probe once and latch, mirroring the
14
+ * `draftsSupported` capability probe in `handlers/delivery.ts`.
15
+ */
16
+ let richMessagesSupported = true;
17
+
18
+ /** Telegram's shape for "this build doesn't have that method". */
19
+ const METHOD_UNAVAILABLE_RE =
20
+ /method not found|not supported|unknown method|unsupported method/i;
21
+
22
+ /** True while native Rich Markdown delivery is still worth attempting. */
23
+ export function richMessagesAvailable(): boolean {
24
+ return richMessagesSupported;
25
+ }
26
+
27
+ /**
28
+ * Log a failed Rich Message call and latch the capability off when the failure
29
+ * says the method itself is missing. Payload-level rejections (a markdown
30
+ * string Telegram won't parse) stay one-off — the next message may be fine.
31
+ */
32
+ export function noteRichMessageFailure(err: unknown, context: string): void {
33
+ const msg = err instanceof Error ? err.message : String(err);
34
+ if (METHOD_UNAVAILABLE_RE.test(msg)) {
35
+ richMessagesSupported = false;
36
+ logWarn(
37
+ "bot",
38
+ `Rich Messages unavailable on this Bot API server — using legacy HTML from now on (${context}): ${msg}`,
39
+ );
40
+ return;
41
+ }
42
+ logWarn(
43
+ "bot",
44
+ `Rich Markdown failed; falling back to HTML (${context}): ${msg}`,
45
+ );
46
+ }
47
+
48
+ /** Test seam: re-arm the capability probe between cases. */
49
+ export function resetRichMessageSupport(): void {
50
+ richMessagesSupported = true;
51
+ }
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Shared helpers for Telegram action handlers: reply-parameter extraction and
3
- * native Rich Markdown delivery with legacy fallbacks.
2
+ * Outbound Telegram sends: reply-parameter extraction, delivery modifiers,
3
+ * and text delivery with native Rich Markdown and legacy HTML / plain-text
4
+ * fallbacks.
4
5
  */
5
6
 
6
7
  import type { Bot } from "grammy";
@@ -8,6 +9,11 @@ import { markdownToTelegramHtml } from "../formatting.js";
8
9
  import { logWarn } from "../../../util/log.js";
9
10
  import { ambientThreadId, resolveThreadId } from "../topics.js";
10
11
  import { TELEGRAM_MAX_TEXT } from "./types.js";
12
+ import { toPositiveId } from "./coerce.js";
13
+ import {
14
+ noteRichMessageFailure,
15
+ richMessagesAvailable,
16
+ } from "./rich-messages.js";
11
17
 
12
18
  export function replyParams(
13
19
  body: Record<string, unknown>,
@@ -62,62 +68,6 @@ export function sendOpts(
62
68
  };
63
69
  }
64
70
 
65
- /**
66
- * Telegram/GramJS APIs expect numeric IDs. `snowflakeOrIdSchema` normalizes IDs
67
- * to digit-strings (so 17-19 digit Discord snowflakes survive validation), so a
68
- * Telegram message/reply/offset ID can arrive here as a string. Coerce it back
69
- * to a positive integer: Telegram IDs are well within 2^53, so this is lossless.
70
- * Returns undefined for missing / non-positive / non-integer values.
71
- */
72
- export function toPositiveId(v: unknown): number | undefined {
73
- const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
74
- return Number.isInteger(n) && n > 0 ? n : undefined;
75
- }
76
-
77
- /**
78
- * Rich Messages arrived in Bot API 10.2. A self-hosted Bot API server (or a
79
- * deployment pinned to an older release) rejects `sendRichMessage` outright,
80
- * and retrying it per message would cost a doomed round-trip plus a warning
81
- * line on every single send. Probe once and latch, mirroring the
82
- * `draftsSupported` capability probe in `handlers/delivery.ts`.
83
- */
84
- let richMessagesSupported = true;
85
-
86
- /** Telegram's shape for "this build doesn't have that method". */
87
- const METHOD_UNAVAILABLE_RE =
88
- /method not found|not supported|unknown method|unsupported method/i;
89
-
90
- /** True while native Rich Markdown delivery is still worth attempting. */
91
- export function richMessagesAvailable(): boolean {
92
- return richMessagesSupported;
93
- }
94
-
95
- /**
96
- * Log a failed Rich Message call and latch the capability off when the failure
97
- * says the method itself is missing. Payload-level rejections (a markdown
98
- * string Telegram won't parse) stay one-off — the next message may be fine.
99
- */
100
- export function noteRichMessageFailure(err: unknown, context: string): void {
101
- const msg = err instanceof Error ? err.message : String(err);
102
- if (METHOD_UNAVAILABLE_RE.test(msg)) {
103
- richMessagesSupported = false;
104
- logWarn(
105
- "bot",
106
- `Rich Messages unavailable on this Bot API server — using legacy HTML from now on (${context}): ${msg}`,
107
- );
108
- return;
109
- }
110
- logWarn(
111
- "bot",
112
- `Rich Markdown failed; falling back to HTML (${context}): ${msg}`,
113
- );
114
- }
115
-
116
- /** Test seam: re-arm the capability probe between cases. */
117
- export function resetRichMessageSupport(): void {
118
- richMessagesSupported = true;
119
- }
120
-
121
71
  export async function sendText(
122
72
  bot: Bot,
123
73
  chatId: number,
@@ -141,7 +91,7 @@ export async function sendText(
141
91
  message_thread_id: ambientThreadId(chatId),
142
92
  };
143
93
 
144
- if (richMessagesSupported) {
94
+ if (richMessagesAvailable()) {
145
95
  try {
146
96
  const sent = await bot.api.sendRichMessage(
147
97
  chatId,
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { Bot, Context } from "grammy";
6
- import type { TalonConfig } from "../../../util/config.js";
6
+ import type { TalonConfig } from "../../../core/config/index.js";
7
7
  import { escapeHtml } from "../formatting.js";
8
8
  import { resetSession, getAllSessions } from "../../../storage/sessions.js";
9
9
  import { clearHistory } from "../../../storage/history.js";
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import type { Bot, Context } from "grammy";
12
- import type { TalonConfig } from "../../util/config.js";
12
+ import type { TalonConfig } from "../../core/config/index.js";
13
13
  import { replyActiveChats, broadcast, killSession } from "./admin/sessions.js";
14
14
  import {
15
15
  replyStats,
@@ -12,7 +12,7 @@ import { activeLoginFlow } from "../../../core/auth/login-flow.js";
12
12
  import { currentAuthPanel, driveLogin, isAuthProvider } from "../auth-panel.js";
13
13
  import { loginBinariesFrom } from "../commands/auth.js";
14
14
  import { isAuthorizedAdmin } from "../commands/state.js";
15
- import { answerCallbackQuerySafe, type CallbackDeps } from "./shared.js";
15
+ import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
16
16
 
17
17
  export async function handleAuthCallback(
18
18
  ctx: Context,
@@ -16,7 +16,7 @@ import {
16
16
  getActiveReasoningLevels,
17
17
  supportsReasoningLevel,
18
18
  } from "../../shared/reasoning-levels.js";
19
- import { answerCallbackQuerySafe, type CallbackDeps } from "./shared.js";
19
+ import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
20
20
 
21
21
  export async function handleEffortCallback(
22
22
  ctx: Context,
@@ -18,10 +18,10 @@
18
18
  */
19
19
 
20
20
  import type { Bot } from "grammy";
21
- import type { TalonConfig } from "../../../util/config.js";
21
+ import type { TalonConfig } from "../../../core/config/index.js";
22
22
  import type { Backend } from "../../../core/agent-runtime/capabilities.js";
23
23
  import { handleCallbackQuery } from "../handlers/index.js";
24
- import type { CallbackDeps } from "./shared.js";
24
+ import type { CallbackDeps } from "./query.js";
25
25
  import { handleSettingsCallback } from "./settings.js";
26
26
  import { handlePulseCallback } from "./pulse.js";
27
27
  import { handleEffortCallback } from "./effort.js";
@@ -30,7 +30,7 @@ import { handleModelCallback } from "./model.js";
30
30
  import { handleAuthCallback } from "./auth.js";
31
31
  import { handleWhatsAppCallback } from "./whatsapp.js";
32
32
 
33
- export { answerCallbackQuerySafe } from "./shared.js";
33
+ export { answerCallbackQuerySafe } from "./query.js";
34
34
 
35
35
  export function registerCallbacks(
36
36
  bot: Bot,
@@ -14,7 +14,7 @@ import {
14
14
  type MetricsView,
15
15
  } from "../helpers/index.js";
16
16
  import { isAuthorizedAdmin } from "../commands/state.js";
17
- import { answerCallbackQuerySafe, editOrIgnoreSame } from "./shared.js";
17
+ import { answerCallbackQuerySafe, editOrIgnoreSame } from "./query.js";
18
18
 
19
19
  export async function handleMetricsCallback(
20
20
  ctx: Context,
@@ -19,7 +19,7 @@ import { resolveActiveModelForChat } from "../../../../core/models/active-model.
19
19
  import { logWarn } from "../../../../util/log.js";
20
20
  import type { ModelCallback } from "../../model-callbacks.js";
21
21
  import { resolveBackendForChat } from "../../model-menu.js";
22
- import { answerCallbackQuerySafe, type CallbackDeps } from "../shared.js";
22
+ import { answerCallbackQuerySafe, type CallbackDeps } from "../query.js";
23
23
  import type { ModelOutcome } from "./types.js";
24
24
 
25
25
  /**
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { Context } from "grammy";
7
- import { answerCallbackQuerySafe } from "../shared.js";
7
+ import { answerCallbackQuerySafe } from "../query.js";
8
8
  import type { ModelOutcome } from "./types.js";
9
9
 
10
10
  // Acknowledge fast (within Telegram's 30s window) so the user
@@ -15,7 +15,7 @@ import { getBackendIdForChat } from "../../../../core/engine/backend-controller/
15
15
  import { resolveActiveModelForChat } from "../../../../core/models/active-model.js";
16
16
  import type { ModelCallback } from "../../model-callbacks.js";
17
17
  import { resolveBackendForChat, toggleChatFreeOnly } from "../../model-menu.js";
18
- import { answerCallbackQuerySafe, type CallbackDeps } from "../shared.js";
18
+ import { answerCallbackQuerySafe, type CallbackDeps } from "../query.js";
19
19
  import type { ModelOutcome } from "./types.js";
20
20
 
21
21
  export async function handleSelect(
@@ -10,7 +10,7 @@
10
10
 
11
11
  import type { Context } from "grammy";
12
12
  import type { ModelCallback } from "../../model-callbacks.js";
13
- import type { CallbackDeps } from "../shared.js";
13
+ import type { CallbackDeps } from "../query.js";
14
14
 
15
15
  export type ModelView =
16
16
  | { kind: "menu" }
@@ -17,7 +17,7 @@ import {
17
17
  buildModelBrowseViewForChat,
18
18
  buildBackendMenuViewForChat,
19
19
  } from "../../model-menu.js";
20
- import { editOrIgnoreSame, type CallbackDeps } from "../shared.js";
20
+ import { editOrIgnoreSame, type CallbackDeps } from "../query.js";
21
21
  import type { ModelView } from "./types.js";
22
22
 
23
23
  export async function renderModelView(
@@ -17,7 +17,7 @@
17
17
 
18
18
  import type { Context } from "grammy";
19
19
  import { parseModelCallback } from "../model-callbacks.js";
20
- import { answerCallbackQuerySafe, type CallbackDeps } from "./shared.js";
20
+ import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
21
21
  import { handleDone, handleNoop } from "./model/control.js";
22
22
  import { handleSelect, handleReset, handleToggleFree } from "./model/select.js";
23
23
  import {
@@ -9,7 +9,7 @@ import {
9
9
  enablePulse,
10
10
  isPulseEnabled,
11
11
  } from "../../../core/background/pulse.js";
12
- import { answerCallbackQuerySafe } from "./shared.js";
12
+ import { answerCallbackQuerySafe } from "./query.js";
13
13
 
14
14
  export async function handlePulseCallback(
15
15
  ctx: Context,
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Shared callback helpers + the dependency bundle passed to each handler.
2
+ * Callback-query plumbing shared by the Telegram callback handlers: the
3
+ * dependency bundle, edit-or-ignore-same, and the safe query ack.
3
4
  */
4
5
 
5
6
  import type { Context } from "grammy";
6
- import type { TalonConfig } from "../../../util/config.js";
7
+ import type { TalonConfig } from "../../../core/config/index.js";
7
8
  import type { Backend } from "../../../core/agent-runtime/capabilities.js";
8
9
  import { logWarn } from "../../../util/log.js";
9
10
  import type { SettingsButton } from "../helpers/index.js";
@@ -28,7 +28,7 @@ import {
28
28
  getActiveReasoningLevels,
29
29
  supportsReasoningLevel,
30
30
  } from "../../shared/reasoning-levels.js";
31
- import { answerCallbackQuerySafe, type CallbackDeps } from "./shared.js";
31
+ import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
32
32
 
33
33
  export async function handleSettingsCallback(
34
34
  ctx: Context,
@@ -11,7 +11,7 @@ import {
11
11
  whatsAppPanel,
12
12
  } from "../commands/whatsapp-pairing.js";
13
13
  import { isAuthorizedAdmin } from "../commands/state.js";
14
- import { answerCallbackQuerySafe } from "./shared.js";
14
+ import { answerCallbackQuerySafe } from "./query.js";
15
15
 
16
16
  export async function handleWhatsAppCallback(
17
17
  ctx: Context,