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 +20 -0
- package/README.md +20 -0
- package/bin/telegram-truncated-reply-policy.cjs +37 -0
- package/blun.mjs +98 -32
- package/package.json +1 -1
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
|
|
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`
|
|
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
|
-
|
|
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.
|
|
260287
|
-
*
|
|
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
|
|
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
|
|
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
|
|
262750
|
-
|
|
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.
|