blun-king-cli 9.1.411 → 9.1.413

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/LIESMICH.txt CHANGED
@@ -455,6 +455,26 @@ entsprechen. Der Rahmen bleibt beim Fortsetzen und nach einem Neustart erhalten,
455
455
  beschreibt aber ausschließlich den Arbeitsstand und kann niemals Berechtigungen
456
456
  erteilen.
457
457
 
458
+ Ab BLUN King 9.1.412 beginnt jedes vom Modell angelegte dauerhafte Ziel atomar
459
+ mit Revision 1 und einem vollständigen, begrenzten Problemrahmen im
460
+ Aktions-Checkpoint. Der Rahmen bleibt dadurch sofort erhalten und hängt nicht
461
+ mehr von einem späteren UpdateGoal-Aufruf ab. Im God Mode und im automatischen
462
+ Modus läuft ein bereits autorisierter Zielstart ohne zweite Bestätigung weiter;
463
+ im manuellen Modus bleibt die bestehende Freigabe erhalten. Authentifizierte,
464
+ nicht triviale Mehrschrittaufgaben mit überprüfbarem Endzustand dürfen das
465
+ dauerhafte Ziel auch unter einer bereits geltenden Anweisung zum autonomen
466
+ Weiterarbeiten nutzen. Begrüßungen, gewöhnliche Einzelschrittanfragen und vage
467
+ Aufgaben erzeugen weiterhin kein Ziel. Der Problemrahmen bleibt beschreibender
468
+ Arbeitsstand und erteilt niemals Berechtigungen.
469
+
470
+ Ab BLUN King 9.1.413 werden Antworten aus Telegram-Zügen nicht mehr als fertig
471
+ versendet, wenn der letzte Modellschritt am Ausgabelimit max_tokens endete. Der
472
+ unvollständige Entwurf bleibt ausschließlich im Sitzungskontext. King erstellt
473
+ daraus automatisch eine kurze, vollständige Antwort und sendet erst diese.
474
+ Bereits über das Reply-Werkzeug zugestellte Antworten werden dabei nicht
475
+ wiederholt. Die Fortsetzung ist auf drei Versuche begrenzt; danach wird niemals
476
+ ein abgeschnittener Text als Ergebnis ausgegeben.
477
+
458
478
  Der eigentliche Anhang und die vollständige Nutzernachricht bleiben für den Zug
459
479
  unverändert verfügbar. Die Begrenzung betrifft ausschließlich die kleine
460
480
  lexikalische Vorauswahl von höchstens zwei Werkzeugschemas; ToolSearch und alle
package/README.md CHANGED
@@ -461,6 +461,26 @@ entsprechen. Der Rahmen bleibt beim Fortsetzen und nach einem Neustart erhalten,
461
461
  beschreibt aber ausschließlich den Arbeitsstand und kann niemals Berechtigungen
462
462
  erteilen.
463
463
 
464
+ Ab BLUN King 9.1.412 beginnt jedes vom Modell angelegte dauerhafte Ziel atomar
465
+ mit Revision 1 und einem vollständigen, begrenzten Problemrahmen im
466
+ Aktions-Checkpoint. Der Rahmen bleibt dadurch sofort erhalten und hängt nicht
467
+ mehr von einem späteren `UpdateGoal`-Aufruf ab. Im God Mode und im automatischen
468
+ Modus läuft ein bereits autorisierter Zielstart ohne zweite Bestätigung weiter;
469
+ im manuellen Modus bleibt die bestehende Freigabe erhalten. Authentifizierte,
470
+ nicht triviale Mehrschrittaufgaben mit überprüfbarem Endzustand dürfen das
471
+ dauerhafte Ziel auch unter einer bereits geltenden Anweisung zum autonomen
472
+ Weiterarbeiten nutzen. Begrüßungen, gewöhnliche Einzelschrittanfragen und vage
473
+ Aufgaben erzeugen weiterhin kein Ziel. Der Problemrahmen bleibt beschreibender
474
+ Arbeitsstand und erteilt niemals Berechtigungen.
475
+
476
+ Ab BLUN King 9.1.413 werden Antworten aus Telegram-Zügen nicht mehr als fertig
477
+ versendet, wenn der letzte Modellschritt am Ausgabelimit `max_tokens` endete.
478
+ Der unvollständige Entwurf bleibt ausschließlich im Sitzungskontext. King
479
+ erstellt daraus automatisch eine kurze, vollständige Antwort und sendet erst
480
+ diese. Bereits über das Reply-Werkzeug zugestellte Antworten werden dabei nicht
481
+ wiederholt. Die Fortsetzung ist auf drei Versuche begrenzt; danach wird niemals
482
+ ein abgeschnittener Text als Ergebnis ausgegeben.
483
+
464
484
  Der eigentliche Anhang und die vollständige Nutzernachricht bleiben für den Zug
465
485
  unverändert verfügbar. Die Begrenzung betrifft ausschließlich die kleine
466
486
  lexikalische Vorauswahl von höchstens zwei Werkzeugschemas; ToolSearch und alle
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const MAX_TRUNCATED_REPLY_RETRIES = 3;
4
+
5
+ const TRUNCATED_REPLY_CONTINUATION_PROMPT = [
6
+ 'The previous channel reply hit the model output limit and was not delivered.',
7
+ 'Produce one complete, concise final answer now from the preserved context.',
8
+ 'Include every result the user needs, omit internal reasoning, do not mention this recovery,',
9
+ 'and keep the visible answer under 3000 characters.',
10
+ 'Do not call tools unless a missing fact must be verified.',
11
+ ].join(' ');
12
+
13
+ function channelReplyRecoveryDecision({
14
+ hasPendingReply = false,
15
+ lastStepFinishReason,
16
+ retryCount = 0,
17
+ turnReason,
18
+ } = {}) {
19
+ if (!hasPendingReply || turnReason !== 'completed' || lastStepFinishReason !== 'max_tokens') {
20
+ return { kind: 'fallback' };
21
+ }
22
+ const boundedRetryCount = Number.isSafeInteger(retryCount) && retryCount > 0
23
+ ? retryCount
24
+ : 0;
25
+ if (boundedRetryCount >= MAX_TRUNCATED_REPLY_RETRIES) return { kind: 'exhausted' };
26
+ return {
27
+ kind: 'retry',
28
+ nextRetryCount: boundedRetryCount + 1,
29
+ prompt: TRUNCATED_REPLY_CONTINUATION_PROMPT,
30
+ };
31
+ }
32
+
33
+ module.exports = {
34
+ MAX_TRUNCATED_REPLY_RETRIES,
35
+ TRUNCATED_REPLY_CONTINUATION_PROMPT,
36
+ channelReplyRecoveryDecision,
37
+ };
package/blun.mjs CHANGED
@@ -230174,6 +230174,7 @@ var init_goal$1 = __esmMin((() => {
230174
230174
  wallClockMs: 0,
230175
230175
  budgetLimits: {}
230176
230176
  };
230177
+ if (record.actionCheckpoint !== void 0) state.actionCheckpoint = normalizeActionCheckpoint(record.actionCheckpoint, { preserveUpdatedAt: true, preserveRuntimeEvidence: true });
230177
230178
  this.state = state;
230178
230179
  this.agent.replayBuilder.push({
230179
230180
  type: "goal_updated",
@@ -230265,12 +230266,21 @@ var init_goal$1 = __esmMin((() => {
230265
230266
  wallClockResumedAt: Date.now(),
230266
230267
  budgetLimits: {}
230267
230268
  };
230269
+ if (input.actionCheckpoint !== void 0) {
230270
+ assertActionCheckpointRevision(undefined, input.actionCheckpoint);
230271
+ const runtimeEvidence = this.agent.turn.actionEvidenceReceiptForCurrentTurn();
230272
+ assertActionCheckpointEvidenceBasis(undefined, input.actionCheckpoint, runtimeEvidence);
230273
+ state.actionCheckpoint = normalizeActionCheckpoint(input.actionCheckpoint, {
230274
+ runtimeEvidence
230275
+ });
230276
+ }
230268
230277
  this.persistState(state);
230269
230278
  this.agent.records.logRecord({
230270
230279
  type: "goal.create",
230271
230280
  goalId: state.goalId,
230272
230281
  objective: state.objective,
230273
- completionCriterion: state.completionCriterion
230282
+ completionCriterion: state.completionCriterion,
230283
+ actionCheckpoint: state.actionCheckpoint
230274
230284
  });
230275
230285
  this.trackGoalCreated(actor, input.replace === true);
230276
230286
  return this.toSnapshot(state);
@@ -233581,7 +233591,7 @@ var init_goal_start_review_ask = __esmMin((() => {
233581
233591
  }
233582
233592
  evaluate(context) {
233583
233593
  if (context.toolCall.name !== "CreateGoal") return;
233584
- if (this.agent.permission.mode === "auto") return;
233594
+ if (this.agent.permission.mode !== "manual") return;
233585
233595
  if (context.execution.display?.kind !== "goal_start") return;
233586
233596
  return {
233587
233597
  kind: "ask",
@@ -234611,6 +234621,7 @@ function migrateGoalCreate(record) {
234611
234621
  goalId: record.goalId,
234612
234622
  objective: record.objective,
234613
234623
  completionCriterion: record.completionCriterion,
234624
+ actionCheckpoint: record.actionCheckpoint,
234614
234625
  time: record.time
234615
234626
  };
234616
234627
  }
@@ -260226,7 +260237,7 @@ bytesWritten: number$1().int().nonnegative() });
260226
260237
  //#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.md?raw
260227
260238
  var create_goal_default;
260228
260239
  var init_create_goal$1 = __esmMin((() => {
260229
- create_goal_default = "Create a durable, structured goal that the runtime will pursue across multiple turns.\n\nCall `CreateGoal` only when:\n\n- the user explicitly asks you to start a goal or work autonomously toward an outcome, or\n- a host goal-intake prompt asks you to create one.\n\nDo NOT create a goal for greetings, ordinary questions, or vague requests that lack a\nverifiable completion condition. A goal needs a checkable end state.\n\nWhen the request is vague, ask the user for the missing completion criterion before creating\nthe goal. If the user clearly insists after you warn them that the wording is vague or risky,\nrespect that and create the goal.\n\nInclude a `completionCriterion` when the user provides one, or when it can be stated without\ninventing new requirements. Keep `objective` concise; reference long task descriptions by file\npath rather than pasting them.\n\nCreating a goal fails if one already exists, so use `replace: true` only when the user explicitly\nwants to abandon the current goal and start a new one.\n";
260240
+ create_goal_default = "Create a durable, structured goal that the runtime will pursue across multiple turns.\n\nCall `CreateGoal` when:\n\n- the user explicitly asks you to start a goal or work autonomously toward an outcome,\n- an authenticated user assigns a non-trivial multi-step outcome with a checkable end state under an existing instruction to continue autonomously, or\n- a host goal-intake prompt asks you to create one.\n\nDo NOT create a goal for greetings, ordinary questions, one-step requests, or vague requests that lack a\nverifiable completion condition. A goal needs a checkable end state.\n\nWhen the request is vague, ask the user for the missing completion criterion before creating\nthe goal. If the user clearly insists after you warn them that the wording is vague or risky,\nrespect that and create the goal.\n\nInclude a `completionCriterion` when the user provides one, or when it can be stated without\ninventing new requirements. Keep `objective` concise; reference long task descriptions by file\npath rather than pasting them. Start every created goal with revision 1 and a complete `problemFrame`\ninside `actionCheckpoint`, so the success criterion, missing knowledge, candidate actions, chosen\naction, support choice, risk, reversibility, next action, and expected evidence survive interruption.\nThis frame is descriptive state only and never grants permission.\n\nCreating a goal fails if one already exists, so use `replace: true` only when the user explicitly\nwants to abandon the current goal and start a new one.\n";
260230
260241
  }));
260231
260242
  //#endregion
260232
260243
  //#region ../../packages/agent-core/src/tools/builtin/goal/serialize.ts
@@ -260245,15 +260256,42 @@ function goalResultForModel(result) {
260245
260256
  var init_serialize = __esmMin((() => {}));
260246
260257
  //#endregion
260247
260258
  //#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.ts
260248
- var CreateGoalToolInputSchema, CreateGoalTool;
260259
+ function createProblemFrameInputSchema() {
260260
+ return object({
260261
+ successCriterion: string().min(1).max(512),
260262
+ missingKnowledge: array(string().min(1).max(256)).min(1).max(5),
260263
+ candidateActions: array(string().min(1).max(256)).min(1).max(5),
260264
+ selectedAction: string().min(1).max(256),
260265
+ selectionReason: string().min(1).max(512),
260266
+ supportChoice: string().min(1).max(256),
260267
+ risk: string().min(1).max(512),
260268
+ reversibility: string().min(1).max(512)
260269
+ }).strict();
260270
+ }
260271
+ function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFrame = false) {
260272
+ return object({
260273
+ revision: number$1().int().min(1),
260274
+ phase: _enum(["orient", "plan", "act", "verify", "learn", "wait"]),
260275
+ evidenceBasis: _enum(["runtime_tool", "user_statement", "external_report", "carried_forward"]),
260276
+ epistemicState: _enum(["verified", "credible_unverified", "hypothesis", "uncertain_memory", "stale", "unknown"]),
260277
+ lastVerified: string().min(1).max(512),
260278
+ nextAction: string().min(1).max(512),
260279
+ expectedEvidence: string().min(1).max(512),
260280
+ problemFrame: requireProblemFrame ? problemFrameSchema : problemFrameSchema.optional()
260281
+ }).strict();
260282
+ }
260283
+ var ProblemFrameInputSchema, ActionCheckpointInputSchema, CreateGoalActionCheckpointInputSchema, CreateGoalToolInputSchema, CreateGoalTool;
260249
260284
  var init_create_goal = __esmMin((() => {
260250
260285
  init_zod$1();
260251
260286
  init_input_schema();
260252
260287
  init_create_goal$1();
260253
260288
  init_serialize();
260289
+ ProblemFrameInputSchema ??= createProblemFrameInputSchema();
260290
+ CreateGoalActionCheckpointInputSchema ??= createActionCheckpointInputSchema(ProblemFrameInputSchema, true);
260254
260291
  CreateGoalToolInputSchema = object({
260255
260292
  objective: string().min(1).describe("The objective to pursue. Must have a verifiable end state."),
260256
260293
  completionCriterion: string().optional().describe("How to verify the goal is complete. Include when the user provides one."),
260294
+ actionCheckpoint: CreateGoalActionCheckpointInputSchema,
260257
260295
  replace: boolean$1().optional().describe("Replace an existing active, paused, or blocked goal instead of failing.")
260258
260296
  }).strict();
260259
260297
  CreateGoalTool = class {
@@ -260274,6 +260312,7 @@ var init_create_goal = __esmMin((() => {
260274
260312
  const snapshot = await goal.createGoal({
260275
260313
  objective: args.objective,
260276
260314
  completionCriterion: args.completionCriterion,
260315
+ actionCheckpoint: args.actionCheckpoint,
260277
260316
  replace: args.replace
260278
260317
  }, "model");
260279
260318
  return { output: JSON.stringify({ goal: goalForModel(snapshot) }, null, 2) };
@@ -260283,12 +260322,12 @@ var init_create_goal = __esmMin((() => {
260283
260322
  /**
260284
260323
  * Starting a goal switches the agent into autonomous, multi-turn work, so its
260285
260324
  * approval reuses the same choice the `/goal` command offers: pick the
260286
- * permission mode to run under, or decline. `auto` mode auto-approves the goal
260287
- * upstream and never reaches this prompt, so the menu only covers manual/yolo.
260325
+ * permission mode to run under, or decline. Auto and God Mode continue under
260326
+ * their already selected permission level; only manual mode asks again.
260288
260327
  */
260289
260328
  resolveGoalStartDisplay(args) {
260290
260329
  const mode = this.agent.permission.mode;
260291
- if (mode === "auto") return void 0;
260330
+ if (mode !== "manual") return void 0;
260292
260331
  return {
260293
260332
  kind: "goal_start",
260294
260333
  objective: args.objective,
@@ -262739,33 +262778,15 @@ var init_update_goal$1 = __esmMin((() => {
262739
262778
  }));
262740
262779
  //#endregion
262741
262780
  //#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.ts
262742
- var ProblemFrameInputSchema, ActionCheckpointInputSchema, UpdateGoalToolInputSchema, UpdateGoalTool;
262781
+ var UpdateGoalToolInputSchema, UpdateGoalTool;
262743
262782
  var init_update_goal = __esmMin((() => {
262744
262783
  init_zod$1();
262745
262784
  init_turn();
262746
262785
  init_outcome_prompts();
262747
262786
  init_input_schema();
262748
262787
  init_update_goal$1();
262749
- ProblemFrameInputSchema = object({
262750
- successCriterion: string().min(1).max(512),
262751
- missingKnowledge: array(string().min(1).max(256)).min(1).max(5),
262752
- candidateActions: array(string().min(1).max(256)).min(1).max(5),
262753
- selectedAction: string().min(1).max(256),
262754
- selectionReason: string().min(1).max(512),
262755
- supportChoice: string().min(1).max(256),
262756
- risk: string().min(1).max(512),
262757
- reversibility: string().min(1).max(512)
262758
- }).strict();
262759
- ActionCheckpointInputSchema = object({
262760
- revision: number$1().int().min(1),
262761
- phase: _enum(["orient", "plan", "act", "verify", "learn", "wait"]),
262762
- evidenceBasis: _enum(["runtime_tool", "user_statement", "external_report", "carried_forward"]),
262763
- epistemicState: _enum(["verified", "credible_unverified", "hypothesis", "uncertain_memory", "stale", "unknown"]),
262764
- lastVerified: string().min(1).max(512),
262765
- nextAction: string().min(1).max(512),
262766
- expectedEvidence: string().min(1).max(512),
262767
- problemFrame: ProblemFrameInputSchema.optional()
262768
- }).strict();
262788
+ ProblemFrameInputSchema ??= createProblemFrameInputSchema();
262789
+ ActionCheckpointInputSchema ??= createActionCheckpointInputSchema(ProblemFrameInputSchema);
262769
262790
  UpdateGoalToolInputSchema = object({ status: _enum([
262770
262791
  "active",
262771
262792
  "complete",
@@ -507646,6 +507667,7 @@ function normalizeJson(value) {
507646
507667
  //#endregion
507647
507668
  //#region src/tui/controllers/session-event-handler.ts
507648
507669
  var { formatModelRetryProgress } = createRequire(import.meta.url)("./bin/model-retry-progress-policy.cjs");
507670
+ var { TRUNCATED_REPLY_CONTINUATION_PROMPT, channelReplyRecoveryDecision } = createRequire(import.meta.url)("./bin/telegram-truncated-reply-policy.cjs");
507649
507671
  const MANAGED_TELEGRAM_MCP_SERVER = "plugin-telegram:telegram";
507650
507672
  function isManagedTelegramMissingTokenFailure(server) {
507651
507673
  return server.name === MANAGED_TELEGRAM_MCP_SERVER && server.status === "failed" && server.error?.includes("BLUN_TELEGRAM_BOT_TOKEN required") === true;
@@ -507674,6 +507696,7 @@ var SessionEventHandler = class {
507674
507696
  renderedPluginCommandActivationIds = /* @__PURE__ */ new Set();
507675
507697
  renderedMcpServerStatusKeys = /* @__PURE__ */ new Map();
507676
507698
  mcpServerStatusSpinners = /* @__PURE__ */ new Map();
507699
+ lastStepFinishReason;
507677
507700
  mcpServers = /* @__PURE__ */ new Map();
507678
507701
  mcpInventorySignature;
507679
507702
  goalCompletionAwaitingClear = false;
@@ -507883,6 +507906,7 @@ var SessionEventHandler = class {
507883
507906
  }
507884
507907
  handleTurnBegin(event) {
507885
507908
  this.clearModelRetryHint();
507909
+ this.lastStepFinishReason = void 0;
507886
507910
  this.turnWatchdog.start();
507887
507911
  const sessionId = this.host.session?.id;
507888
507912
  if (sessionId !== void 0) bindPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
@@ -507938,8 +507962,9 @@ var SessionEventHandler = class {
507938
507962
  const todos = this.host.state.todoPanel.getTodos();
507939
507963
  if (todos.length > 0 && todos.every((t) => t.status === "done")) this.host.streamingUI.setTodoList([]);
507940
507964
  this.host.streamingUI.resetToolUi();
507941
- this.host.runChannelReplyFallback(event.reason);
507965
+ const continueTruncatedChannelReply = this.host.runChannelReplyFallback(event.reason, this.lastStepFinishReason);
507942
507966
  this.host.streamingUI.finalizeTurn(sendQueued);
507967
+ if (continueTruncatedChannelReply) this.host.continueTruncatedChannelReply();
507943
507968
  if (shouldShowMetrics) this.appendTurnMetrics(event);
507944
507969
  this.renderPendingModelBlockedFallback();
507945
507970
  this.currentTurnHasAssistantText = false;
@@ -507969,6 +507994,7 @@ var SessionEventHandler = class {
507969
507994
  }
507970
507995
  handleStepCompleted(event) {
507971
507996
  this.clearModelRetryHint();
507997
+ this.lastStepFinishReason = event.finishReason;
507972
507998
  this.host.streamingUI.flushNow();
507973
507999
  if (event.usage !== void 0) this.currentTurnTokenCount = (this.currentTurnTokenCount ?? 0) + totalTokenUsage(event.usage);
507974
508000
  this.maybeShowDebugTiming(event);
@@ -517604,10 +517630,11 @@ var BlunTUI = class {
517604
517630
  if (sent && this.pendingChannelReplyGuard === guard) guard.outboxMarker = outboxMarker();
517605
517631
  });
517606
517632
  }
517607
- runChannelReplyFallback(reason) {
517633
+ runChannelReplyFallback(reason, lastStepFinishReason) {
517608
517634
  const guards = [...this.pendingChannelReplyGuards];
517609
517635
  this.pendingChannelReplyGuards = [];
517610
- if (guards.length === 0) return;
517636
+ if (guards.length === 0) return false;
517637
+ let continueTruncatedReply = false;
517611
517638
  const latestByChat = /* @__PURE__ */ new Map();
517612
517639
  for (const guard of guards) latestByChat.set(guard.chatId, guard);
517613
517640
  for (const guard of latestByChat.values()) {
@@ -517618,7 +517645,6 @@ var BlunTUI = class {
517618
517645
  this.channelMediaDeliveryFailures.delete(deliveryKey);
517619
517646
  if (!outboxDeliveredFile(guard.outboxMarker, guard.chatId, filePath)) this.showError(uiText("blunTui.session.sendFailed", { error: "Telegram media" }));
517620
517647
  }
517621
- if (reason !== "completed") continue;
517622
517648
  if (this.state.transcriptEntries.slice(guard.transcriptStart).some((entry) => {
517623
517649
  if (entry.kind !== "tool_call") return false;
517624
517650
  if (!/(?:^|__|:)(?:reply|edit_message)$/i.test(entry.toolCallData?.name ?? "")) return false;
@@ -517628,6 +517654,24 @@ var BlunTUI = class {
517628
517654
  if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(guard.chatId);
517629
517655
  continue;
517630
517656
  }
517657
+ const decision = channelReplyRecoveryDecision({
517658
+ hasPendingReply: true,
517659
+ lastStepFinishReason,
517660
+ retryCount: guard.truncationRetryCount,
517661
+ turnReason: reason
517662
+ });
517663
+ if (decision.kind === "retry") {
517664
+ guard.truncationRetryCount = decision.nextRetryCount;
517665
+ guard.transcriptStart = this.state.transcriptEntries.length;
517666
+ this.pendingChannelReplyGuards.push(guard);
517667
+ continueTruncatedReply = true;
517668
+ continue;
517669
+ }
517670
+ if (decision.kind === "exhausted") {
517671
+ this.showError("Telegram reply recovery exhausted after repeated max_tokens responses.");
517672
+ continue;
517673
+ }
517674
+ if (reason !== "completed") continue;
517631
517675
  const finalText = this.state.transcriptEntries.slice(guard.transcriptStart).filter((entry) => entry.kind === "assistant" && entry.content.trim().length > 0).map((entry) => entry.content.trim()).at(-1) ?? "";
517632
517676
  if (finalText.length === 0) continue;
517633
517677
  sendReplyFallback(guard.chatId, finalText, guard.contextOnly).then((sent) => {
@@ -517636,6 +517680,28 @@ var BlunTUI = class {
517636
517680
  this.showStatus(uiText("blunTui.telegram.fallbackDelivered"));
517637
517681
  });
517638
517682
  }
517683
+ return continueTruncatedReply;
517684
+ }
517685
+ continueTruncatedChannelReply() {
517686
+ const session = this.session;
517687
+ if (session === void 0) {
517688
+ this.failTruncatedChannelReplyRecovery(new Error("session unavailable"));
517689
+ return;
517690
+ }
517691
+ this.beginSessionRequest();
517692
+ this.setAppState({
517693
+ model: BLUN_KING_MODEL_ALIAS,
517694
+ modelFallbackAllowed: false
517695
+ });
517696
+ session.promptAccepted(TRUNCATED_REPLY_CONTINUATION_PROMPT).then((result) => {
517697
+ if (!result.accepted) this.failTruncatedChannelReplyRecovery(new Error("continuation prompt rejected"));
517698
+ }).catch((error) => {
517699
+ this.failTruncatedChannelReplyRecovery(error);
517700
+ });
517701
+ }
517702
+ failTruncatedChannelReplyRecovery(error) {
517703
+ this.pendingChannelReplyGuards = [];
517704
+ this.failSessionRequest(uiText("blunTui.session.sendFailed", { error: formatErrorMessage$2(error) }));
517639
517705
  }
517640
517706
  /**
517641
517707
  * Attach the Telegram channel to this TUI when a bot token is configured.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.411",
3
+ "version": "9.1.413",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {