blun-king-cli 9.1.75 → 9.1.77

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
@@ -9,7 +9,7 @@ Installation
9
9
  ------------
10
10
  Die geprüfte Version exakt global installieren:
11
11
 
12
- npm install -g blun-king-cli@9.1.69
12
+ npm install -g blun-king-cli@9.1.77
13
13
 
14
14
  Start
15
15
  -----
@@ -43,6 +43,11 @@ einen aktiven Zug ab, ohne den geschriebenen Entwurf zu löschen. Das gilt auch
43
43
  bei Autovervollständigung, Geistervorschlägen, Bash-Eingabe und einer offenen
44
44
  Mehrzeileneingabe.
45
45
 
46
+ Telegram-Nachrichten, die bei bereits aktivem Kernzug eintreffen, werden ohne
47
+ konkurrierenden Start zurückgewiesen und bleiben an der Spitze der
48
+ FIFO-Warteschlange. Für diesen normalen Wartestatus erscheint kein
49
+ `turn.agent_busy`-Fehler.
50
+
46
51
  Zuverlässiger King-Start
47
52
  -----------------------
48
53
  Der Windows-Hilfsprozess für private Pfade übernimmt TEMP und TMP aus der
@@ -67,6 +72,20 @@ parallel geprüft und eingelesen. Die Skills werden weiterhin in der
67
72
  ursprünglichen, festen Reihenfolge registriert; Priorität und Verhalten bei
68
73
  doppelten Namen bleiben unverändert.
69
74
 
75
+ Kontextentlastung bei langen Sitzungen
76
+ --------------------------------------
77
+ King bewahrt den vollständigen Verlauf weiterhin im Sitzungs-Wire auf. Erreicht
78
+ der aktive Verlauf 75 Prozent des Modellfensters, ersetzt die Modellprojektion
79
+ ältere große Werkzeugergebnisse durch einen kurzen Platzhalter. Die letzten 20
80
+ Nachrichten bleiben unverändert. Solange der Prefix-Cache warm ist, wird der
81
+ Schnitt höchstens nach jeweils 20 weiteren Nachrichten verschoben. Nach einer
82
+ Stunde ohne Modellantwort darf er sofort nachziehen.
83
+
84
+ Dabei werden keine gespeicherten Nachrichten geändert oder gelöscht. Fortsetzen,
85
+ Exportieren und die sichtbare Historie behalten die ursprünglichen
86
+ Werkzeugergebnisse. Das Telemetrieereignis `micro_compaction_finished` nennt den
87
+ Auslöser, den Schnitt und die geschätzte Tokenzahl vor und nach der Entlastung.
88
+
70
89
  Zug-Wächter
71
90
  -----------
72
91
  Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
@@ -175,6 +194,11 @@ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Seku
175
194
  genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
176
195
  GetMedia abrufen.
177
196
 
197
+ Ein angenommener Medienauftrag bleibt über Verdichtungen und schnelle
198
+ Folgeturns hinweg gespeichert. Solange er offen ist, bleibt `GetMedia`
199
+ verfügbar; King prüft den tatsächlichen Status, statt fälschlich zu behaupten,
200
+ die Medienerzeugung sei nicht verfügbar.
201
+
178
202
  Angehängte Bilder werden weiterhin mit ReadMediaFile gelesen. Bild-, Video- und
179
203
  Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
180
204
  nutzbar bleibt. GenerateVideo kann außerdem einen abgeschlossenen Bildauftrag
package/README.md CHANGED
@@ -62,6 +62,10 @@ blun tools enable context7
62
62
  Telegram-Nachrichten werden in Eingangsreihenfolge verarbeitet. Trifft eine
63
63
  Nachricht im Leerlauf ein, startet die Warteschlange selbstständig; während
64
64
  eines Werkzeuglaufs wird sie am nächsten geschützten Übergabepunkt eingefügt.
65
+ Telegram-Nachrichten, die bei bereits aktivem Kernzug eintreffen, werden ohne
66
+ konkurrierenden Start zurückgewiesen und bleiben an der Spitze der
67
+ FIFO-Warteschlange. Für diesen normalen Wartestatus erscheint kein
68
+ `turn.agent_busy`-Fehler.
65
69
  `Strg+C` und `Esc` brechen einen aktiven Zug zuverlässig ab, ohne den bereits
66
70
  geschriebenen Entwurf zu löschen. Das gilt auch bei Autovervollständigung,
67
71
  Geistervorschlägen, Bash-Eingabe und einer noch offenen Mehrzeileneingabe.
@@ -90,6 +94,20 @@ parallel geprüft und eingelesen. Die Skills werden weiterhin in der
90
94
  ursprünglichen, festen Reihenfolge registriert; Priorität und Verhalten bei
91
95
  doppelten Namen bleiben unverändert.
92
96
 
97
+ ## Kontextentlastung bei langen Sitzungen
98
+
99
+ King bewahrt den vollständigen Verlauf weiterhin im Sitzungs-Wire auf. Erreicht
100
+ der aktive Verlauf 75 Prozent des Modellfensters, ersetzt die Modellprojektion
101
+ ältere große Werkzeugergebnisse durch einen kurzen Platzhalter. Die letzten 20
102
+ Nachrichten bleiben unverändert. Solange der Prefix-Cache warm ist, wird der
103
+ Schnitt höchstens nach jeweils 20 weiteren Nachrichten verschoben. Nach einer
104
+ Stunde ohne Modellantwort darf er sofort nachziehen.
105
+
106
+ Dabei werden keine gespeicherten Nachrichten geändert oder gelöscht. Fortsetzen,
107
+ Exportieren und die sichtbare Historie behalten die ursprünglichen
108
+ Werkzeugergebnisse. Das Telemetrieereignis `micro_compaction_finished` nennt den
109
+ Auslöser, den Schnitt und die geschätzte Tokenzahl vor und nach der Entlastung.
110
+
93
111
  ## Zug-Wächter
94
112
 
95
113
  Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
@@ -203,6 +221,11 @@ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Seku
203
221
  genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
204
222
  `GetMedia` abrufen.
205
223
 
224
+ Ein angenommener Medienauftrag bleibt über Verdichtungen und schnelle
225
+ Folgeturns hinweg gespeichert. Solange er offen ist, bleibt `GetMedia`
226
+ verfügbar; King prüft den tatsächlichen Status, statt fälschlich zu behaupten,
227
+ die Medienerzeugung sei nicht verfügbar.
228
+
206
229
  Angehängte Bilder werden weiterhin mit `ReadMediaFile` gelesen. Bild-, Video-
207
230
  und Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
208
231
  nutzbar bleibt. `GenerateVideo` kann außerdem einen abgeschlossenen Bildauftrag
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ const MICRO_COMPACTION_PRESSURE_RATIO = 0.75;
4
+ const MICRO_COMPACTION_MIN_ADVANCE_MESSAGES = 20;
5
+
6
+ function selectMicroCompactionCutoff(options = {}) {
7
+ const historyLength = nonNegativeInteger(options.historyLength);
8
+ const currentCutoff = nonNegativeInteger(options.currentCutoff);
9
+ const keepRecentMessages = nonNegativeInteger(options.keepRecentMessages);
10
+ const nextCutoff = Math.max(0, historyLength - keepRecentMessages);
11
+ if (nextCutoff <= currentCutoff) return null;
12
+
13
+ const maxContextTokens = positiveFinite(options.maxContextTokens);
14
+ const contextTokens = nonNegativeFinite(options.contextTokens);
15
+ const contextUsageRatio = maxContextTokens === null
16
+ ? 1
17
+ : contextTokens / maxContextTokens;
18
+ const minContextUsageRatio = nonNegativeFinite(options.minContextUsageRatio);
19
+ if (contextUsageRatio < minContextUsageRatio) return null;
20
+
21
+ const now = finiteOr(options.now, Date.now());
22
+ const lastAssistantAt = finiteOrNull(options.lastAssistantAt);
23
+ const cacheAgeMs = lastAssistantAt === null ? null : Math.max(0, now - lastAssistantAt);
24
+ const cacheMissedThresholdMs = nonNegativeFinite(options.cacheMissedThresholdMs);
25
+ const cacheMissed = cacheAgeMs !== null && cacheAgeMs >= cacheMissedThresholdMs;
26
+ const underContextPressure = maxContextTokens !== null
27
+ && contextUsageRatio >= MICRO_COMPACTION_PRESSURE_RATIO;
28
+ if (!cacheMissed && !underContextPressure) return null;
29
+
30
+ if (
31
+ !cacheMissed
32
+ && currentCutoff > 0
33
+ && nextCutoff - currentCutoff < MICRO_COMPACTION_MIN_ADVANCE_MESSAGES
34
+ ) {
35
+ return null;
36
+ }
37
+
38
+ return {
39
+ cacheAgeMs,
40
+ contextUsageRatio,
41
+ cutoff: nextCutoff,
42
+ trigger: cacheMissed ? 'cache_miss' : 'context_pressure',
43
+ };
44
+ }
45
+
46
+ function finiteOr(value, fallback) {
47
+ const number = Number(value);
48
+ return Number.isFinite(number) ? number : fallback;
49
+ }
50
+
51
+ function finiteOrNull(value) {
52
+ if (value === null || value === undefined) return null;
53
+ const number = Number(value);
54
+ return Number.isFinite(number) ? number : null;
55
+ }
56
+
57
+ function nonNegativeFinite(value) {
58
+ const number = Number(value);
59
+ return Number.isFinite(number) && number >= 0 ? number : 0;
60
+ }
61
+
62
+ function nonNegativeInteger(value) {
63
+ return Math.floor(nonNegativeFinite(value));
64
+ }
65
+
66
+ function positiveFinite(value) {
67
+ const number = Number(value);
68
+ return Number.isFinite(number) && number > 0 ? number : null;
69
+ }
70
+
71
+ module.exports = {
72
+ MICRO_COMPACTION_MIN_ADVANCE_MESSAGES,
73
+ MICRO_COMPACTION_PRESSURE_RATIO,
74
+ selectMicroCompactionCutoff,
75
+ };
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ const TERMINAL_STATUSES = new Set([
4
+ 'blocked',
5
+ 'cancelled',
6
+ 'canceled',
7
+ 'complete',
8
+ 'completed',
9
+ 'expired',
10
+ 'failed',
11
+ 'succeeded',
12
+ ]);
13
+
14
+ function validMediaId(value) {
15
+ return typeof value === 'string' && value.length > 0 && value.length <= 200
16
+ && /^[A-Za-z0-9_-]+$/.test(value);
17
+ }
18
+
19
+ function terminalStatus(value) {
20
+ return typeof value === 'string' && TERMINAL_STATUSES.has(value.trim().toLowerCase());
21
+ }
22
+
23
+ function createPendingMediaTracker() {
24
+ const pending = new Set();
25
+
26
+ return {
27
+ observeSubmission(job) {
28
+ if (!validMediaId(job?.id)) return;
29
+ if (terminalStatus(job?.status)) pending.delete(job.id);
30
+ else pending.add(job.id);
31
+ },
32
+ observeLookup(result) {
33
+ if (!validMediaId(result?.id)) return;
34
+ if (result.kind !== 'status' || terminalStatus(result.status)) pending.delete(result.id);
35
+ else pending.add(result.id);
36
+ },
37
+ ids() {
38
+ return [...pending];
39
+ },
40
+ };
41
+ }
42
+
43
+ module.exports = { createPendingMediaTracker };
package/blun.mjs CHANGED
@@ -75889,8 +75889,9 @@ var init_full = __esmMin((() => {
75889
75889
  }));
75890
75890
  //#endregion
75891
75891
  //#region ../../packages/agent-core/src/agent/compaction/micro.ts
75892
- var DEFAULT_CONFIG, MicroCompaction;
75892
+ var selectMicroCompactionCutoff, DEFAULT_CONFIG, MicroCompaction;
75893
75893
  var init_micro = __esmMin((() => {
75894
+ ({ selectMicroCompactionCutoff } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
75894
75895
  init_tokens();
75895
75896
  DEFAULT_CONFIG = {
75896
75897
  keepRecentMessages: 20,
@@ -75920,9 +75921,67 @@ var init_micro = __esmMin((() => {
75920
75921
  });
75921
75922
  this.cutoff = cutoff;
75922
75923
  }
75923
- detect() {}
75924
+ detect() {
75925
+ const config = this.config;
75926
+ const { history, lastAssistantAt } = this.agent.context;
75927
+ const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
75928
+ const contextTokens = this.agent.context.tokenCountWithPending;
75929
+ const selection = selectMicroCompactionCutoff({
75930
+ historyLength: history.length,
75931
+ currentCutoff: this.cutoff,
75932
+ keepRecentMessages: config.keepRecentMessages,
75933
+ contextTokens,
75934
+ maxContextTokens,
75935
+ lastAssistantAt,
75936
+ now: Date.now(),
75937
+ cacheMissedThresholdMs: config.cacheMissedThresholdMs,
75938
+ minContextUsageRatio: config.minContextUsageRatio
75939
+ });
75940
+ if (selection === null) return;
75941
+ const previousCutoff = this.cutoff;
75942
+ const effect = this.measureEffect(history, selection.cutoff);
75943
+ const previousEffect = this.measureEffect(history, previousCutoff);
75944
+ if (effect.truncatedToolResultCount <= previousEffect.truncatedToolResultCount) return;
75945
+ this.apply(selection.cutoff);
75946
+ const rawContextTokens = estimateTokensForMessages(history);
75947
+ const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter;
75948
+ const tokensAfter = rawContextTokens - effect.truncatedToolResultTokensBefore + effect.truncatedToolResultTokensAfter;
75949
+ this.agent.telemetry.track("micro_compaction_finished", {
75950
+ trigger: selection.trigger,
75951
+ keep_recent_messages: config.keepRecentMessages,
75952
+ min_content_tokens: config.minContentTokens,
75953
+ cache_missed_threshold_ms: config.cacheMissedThresholdMs,
75954
+ truncated_marker: config.truncatedMarker,
75955
+ min_context_usage_ratio: config.minContextUsageRatio,
75956
+ context_usage_ratio: selection.contextUsageRatio,
75957
+ truncated_tool_result_count: effect.truncatedToolResultCount,
75958
+ truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
75959
+ truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
75960
+ tokens_before: tokensBefore,
75961
+ tokens_after: tokensAfter,
75962
+ previous_cutoff: previousCutoff,
75963
+ cutoff: selection.cutoff,
75964
+ message_count: history.length,
75965
+ cache_age_ms: selection.cacheAgeMs,
75966
+ thinking_effort: this.agent.config.thinkingEffort
75967
+ });
75968
+ }
75924
75969
  compact(messages) {
75925
- return messages;
75970
+ const config = this.config;
75971
+ const result = [];
75972
+ let i = 0;
75973
+ for (const msg of messages) {
75974
+ if (i < this.cutoff && msg.role === "tool" && msg.toolCallId !== void 0 && estimateTokensForContentParts(msg.content) >= config.minContentTokens) result.push({
75975
+ ...msg,
75976
+ content: [{
75977
+ type: "text",
75978
+ text: config.truncatedMarker
75979
+ }]
75980
+ });
75981
+ else result.push(msg);
75982
+ i++;
75983
+ }
75984
+ return result;
75926
75985
  }
75927
75986
  measureEffect(messages, cutoff) {
75928
75987
  let markerTokenCount;
@@ -259942,9 +260001,14 @@ function blunToolsForOrigin(tools, origin) {
259942
260001
  if (origin.kind !== "system_trigger" && origin.kind !== "injection") return tools;
259943
260002
  return tools.filter((tool) => !BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name));
259944
260003
  }
259945
- function blunFastConversationTools(tools, input) {
259946
- if (!BLUN_TELEGRAM_CHANNEL_RE.test(blunExtractText(input))) return [];
259947
- return tools.filter((tool) => BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name));
260004
+ function blunPendingMediaSystemPrompt(systemPrompt, pendingMediaJobIds) {
260005
+ if (pendingMediaJobIds.length === 0) return systemPrompt;
260006
+ return `${systemPrompt}\n\n## Pending BLUN media\n\nThe following media jobs were already accepted and are still pending: ${pendingMediaJobIds.join(", ")}. Call GetMedia exactly once for each listed id before replying. If a job is still processing, report that status truthfully and wait for a later turn; do not claim that media tools are unavailable.`;
260007
+ }
260008
+ function blunFastConversationTools(tools, input, pendingMediaJobIds = []) {
260009
+ const telegramTurn = BLUN_TELEGRAM_CHANNEL_RE.test(blunExtractText(input));
260010
+ const mediaPending = pendingMediaJobIds.length > 0;
260011
+ return tools.filter((tool) => telegramTurn && BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name) || mediaPending && tool.name === "GetMedia");
259948
260012
  }
259949
260013
  /**
259950
260014
  * Keep frequently used native tools resident and expose every other tool by
@@ -260281,11 +260345,15 @@ var init_turn = __esmMin((() => {
260281
260345
  input,
260282
260346
  origin
260283
260347
  });
260284
- const blocked = this.activeTurn !== null;
260285
- const buffered = !blocked && this.agent.fullCompaction.isCompacting;
260348
+ if (this.activeTurn !== null) return {
260349
+ accepted: false,
260350
+ buffered: false,
260351
+ turnId: null
260352
+ };
260353
+ const buffered = this.agent.fullCompaction.isCompacting;
260286
260354
  const turnId = this.launch(input, origin);
260287
260355
  return {
260288
- accepted: !blocked,
260356
+ accepted: true,
260289
260357
  buffered,
260290
260358
  turnId
260291
260359
  };
@@ -260773,7 +260841,9 @@ var init_turn = __esmMin((() => {
260773
260841
  const turnHasAttachment = blunTurnHasAttachment(input);
260774
260842
  const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind);
260775
260843
  const fastConversation = turnThinkingEffort === "off" || turnThinkingEffort === "low";
260776
- const turnLLM = this.agent.llmForTurn(turnThinkingEffort, fastConversation ? this.agent.fastConversationSystemPrompt : void 0);
260844
+ const pendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
260845
+ const turnSystemPrompt = pendingMediaJobIds.length > 0 ? blunPendingMediaSystemPrompt(fastConversation ? this.agent.fastConversationSystemPrompt : this.agent.effectiveSystemPrompt, pendingMediaJobIds) : fastConversation ? this.agent.fastConversationSystemPrompt : void 0;
260846
+ const turnLLM = this.agent.llmForTurn(turnThinkingEffort, turnSystemPrompt);
260777
260847
  let previousStepToolOutcome = "initial";
260778
260848
  let currentStepHadTool = false;
260779
260849
  let currentStepHadFailure = false;
@@ -260785,7 +260855,7 @@ var init_turn = __esmMin((() => {
260785
260855
  try {
260786
260856
  const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
260787
260857
  const toolSelection = fastConversation ? {
260788
- tools: [...blunFastConversationTools(eligibleTools, input)],
260858
+ tools: [...blunFastConversationTools(eligibleTools, input, pendingMediaJobIds)],
260789
260859
  deferredToolCount: 0
260790
260860
  } : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames) : {
260791
260861
  tools: [],
@@ -260849,8 +260919,9 @@ var init_turn = __esmMin((() => {
260849
260919
  if (steerEfforts.some((effort) => effort === void 0)) return;
260850
260920
  const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
260851
260921
  const steerThinkingEffort = "low";
260852
- const steerLLM = this.agent.llmForTurn(steerThinkingEffort, this.agent.fastConversationSystemPrompt);
260853
- const steerTools = [...blunFastConversationTools(eligibleTools, steerInput)];
260922
+ const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
260923
+ const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
260924
+ const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds)];
260854
260925
  const steerHistory = () => blunFastConversationHistory(this.agent.context.history);
260855
260926
  const buildSteerMessages = () => this.agent.context.project(steerHistory(), { dropOrphanResults: true });
260856
260927
  const buildSteerMessagesStrict = () => this.agent.context.project(steerHistory(), {
@@ -311242,8 +311313,9 @@ async function assertSuccess(response, operation) {
311242
311313
  } catch {}
311243
311314
  throw new Error(`${operation} failed: HTTP ${String(response.status)}${detail ? `: ${detail}` : ""}`);
311244
311315
  }
311245
- var BlunMediaService;
311316
+ var createPendingMediaTracker, BlunMediaService;
311246
311317
  var init_blun_media = __esmMin((() => {
311318
+ ({ createPendingMediaTracker } = createRequire(import.meta.url)("./bin/pending-media-policy.cjs"));
311247
311319
  BlunMediaService = class {
311248
311320
  tokenProvider;
311249
311321
  apiKey;
@@ -311251,6 +311323,7 @@ var init_blun_media = __esmMin((() => {
311251
311323
  defaultHeaders;
311252
311324
  customHeaders;
311253
311325
  fetchImpl;
311326
+ pendingMedia = createPendingMediaTracker();
311254
311327
  constructor(options) {
311255
311328
  this.tokenProvider = options.tokenProvider;
311256
311329
  this.apiKey = options.apiKey;
@@ -311303,28 +311376,28 @@ var init_blun_media = __esmMin((() => {
311303
311376
  }
311304
311377
  async getMedia(id, options) {
311305
311378
  const response = await this.request(`/media/${encodeURIComponent(id)}`, { method: "GET" }, options);
311306
- if (response.status === 409) return parseBlockedStatus(response, id);
311307
- if (response.status === 410) return {
311379
+ if (response.status === 409) return this.trackMediaLookup(parseBlockedStatus(response, id));
311380
+ if (response.status === 410) return this.trackMediaLookup({
311308
311381
  kind: "status",
311309
311382
  id,
311310
311383
  status: "expired"
311311
- };
311384
+ });
311312
311385
  await assertSuccess(response, "Media lookup");
311313
311386
  const mimeType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
311314
- if (mimeType === "application/json" || mimeType.endsWith("+json")) return parseStatus(await response.json(), id);
311315
- if (mimeType === "text/plain") return {
311387
+ if (mimeType === "application/json" || mimeType.endsWith("+json")) return this.trackMediaLookup(parseStatus(await response.json(), id));
311388
+ if (mimeType === "text/plain") return this.trackMediaLookup({
311316
311389
  kind: "text",
311317
311390
  id,
311318
311391
  mimeType,
311319
311392
  text: await response.text()
311320
- };
311393
+ });
311321
311394
  if (!mimeType.startsWith("image/") && !mimeType.startsWith("audio/") && !mimeType.startsWith("video/")) throw new Error(`Media lookup returned unsupported content type ${mimeType || "(missing)"}`);
311322
- return {
311395
+ return this.trackMediaLookup({
311323
311396
  kind: "file",
311324
311397
  id,
311325
311398
  mimeType,
311326
311399
  data: new Uint8Array(await response.arrayBuffer())
311327
- };
311400
+ });
311328
311401
  }
311329
311402
  async submit(path, body, options) {
311330
311403
  const response = await this.request(path, {
@@ -311333,7 +311406,16 @@ var init_blun_media = __esmMin((() => {
311333
311406
  }, options);
311334
311407
  if (response.status === 409) throw await blockedSubmissionError(response);
311335
311408
  await assertSuccess(response, "Media request");
311336
- return parseJob(await response.json());
311409
+ const job = parseJob(await response.json());
311410
+ this.pendingMedia.observeSubmission(job);
311411
+ return job;
311412
+ }
311413
+ trackMediaLookup(result) {
311414
+ this.pendingMedia.observeLookup(result);
311415
+ return result;
311416
+ }
311417
+ pendingMediaJobIds() {
311418
+ return this.pendingMedia.ids();
311337
311419
  }
311338
311420
  async request(path, init, options) {
311339
311421
  const firstToken = await this.resolveToken(false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.75",
3
+ "version": "9.1.77",
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": {