blun-king-cli 9.1.74 → 9.1.76
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 +10 -0
- package/README.md +9 -0
- package/bin/pending-media-policy.cjs +43 -0
- package/blun.mjs +51 -22
- package/package.json +1 -1
package/LIESMICH.txt
CHANGED
|
@@ -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
|
|
@@ -175,6 +180,11 @@ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Seku
|
|
|
175
180
|
genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
|
|
176
181
|
GetMedia abrufen.
|
|
177
182
|
|
|
183
|
+
Ein angenommener Medienauftrag bleibt über Verdichtungen und schnelle
|
|
184
|
+
Folgeturns hinweg gespeichert. Solange er offen ist, bleibt `GetMedia`
|
|
185
|
+
verfügbar; King prüft den tatsächlichen Status, statt fälschlich zu behaupten,
|
|
186
|
+
die Medienerzeugung sei nicht verfügbar.
|
|
187
|
+
|
|
178
188
|
Angehängte Bilder werden weiterhin mit ReadMediaFile gelesen. Bild-, Video- und
|
|
179
189
|
Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
|
|
180
190
|
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.
|
|
@@ -203,6 +207,11 @@ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Seku
|
|
|
203
207
|
genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
|
|
204
208
|
`GetMedia` abrufen.
|
|
205
209
|
|
|
210
|
+
Ein angenommener Medienauftrag bleibt über Verdichtungen und schnelle
|
|
211
|
+
Folgeturns hinweg gespeichert. Solange er offen ist, bleibt `GetMedia`
|
|
212
|
+
verfügbar; King prüft den tatsächlichen Status, statt fälschlich zu behaupten,
|
|
213
|
+
die Medienerzeugung sei nicht verfügbar.
|
|
214
|
+
|
|
206
215
|
Angehängte Bilder werden weiterhin mit `ReadMediaFile` gelesen. Bild-, Video-
|
|
207
216
|
und Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
|
|
208
217
|
nutzbar bleibt. `GenerateVideo` kann außerdem einen abgeschlossenen Bildauftrag
|
|
@@ -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
|
@@ -259910,17 +259910,23 @@ function blunMessageTextChars(message) {
|
|
|
259910
259910
|
function blunFastConversationHistory(history) {
|
|
259911
259911
|
const selected = [];
|
|
259912
259912
|
let textChars = 0;
|
|
259913
|
+
let expectsAssistant = false;
|
|
259913
259914
|
for (let index = history.length - 1; index >= 0; index -= 1) {
|
|
259914
259915
|
const message = history[index];
|
|
259915
259916
|
if (message === void 0) continue;
|
|
259916
259917
|
if (message.role === "user" && message.origin?.kind !== "user") continue;
|
|
259917
|
-
if (message.role === "assistant" && message.toolCalls.length > 0) continue;
|
|
259918
259918
|
if (message.role !== "user" && message.role !== "assistant") continue;
|
|
259919
|
+
if (message.role === "user" && selected.length > 0 && expectsAssistant) break;
|
|
259920
|
+
if (message.role === "assistant") {
|
|
259921
|
+
if (!expectsAssistant) continue;
|
|
259922
|
+
if (message.toolCalls.length > 0) break;
|
|
259923
|
+
}
|
|
259919
259924
|
const messageTextChars = blunMessageTextChars(message);
|
|
259920
259925
|
if (messageTextChars === 0) continue;
|
|
259921
|
-
if (textChars + messageTextChars > 12e3)
|
|
259926
|
+
if (textChars + messageTextChars > 12e3) break;
|
|
259922
259927
|
selected.push(message);
|
|
259923
259928
|
textChars += messageTextChars;
|
|
259929
|
+
expectsAssistant = message.role === "user";
|
|
259924
259930
|
if (selected.length >= 6) break;
|
|
259925
259931
|
}
|
|
259926
259932
|
return selected.toReversed();
|
|
@@ -259936,9 +259942,14 @@ function blunToolsForOrigin(tools, origin) {
|
|
|
259936
259942
|
if (origin.kind !== "system_trigger" && origin.kind !== "injection") return tools;
|
|
259937
259943
|
return tools.filter((tool) => !BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name));
|
|
259938
259944
|
}
|
|
259939
|
-
function
|
|
259940
|
-
if (
|
|
259941
|
-
return
|
|
259945
|
+
function blunPendingMediaSystemPrompt(systemPrompt, pendingMediaJobIds) {
|
|
259946
|
+
if (pendingMediaJobIds.length === 0) return systemPrompt;
|
|
259947
|
+
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.`;
|
|
259948
|
+
}
|
|
259949
|
+
function blunFastConversationTools(tools, input, pendingMediaJobIds = []) {
|
|
259950
|
+
const telegramTurn = BLUN_TELEGRAM_CHANNEL_RE.test(blunExtractText(input));
|
|
259951
|
+
const mediaPending = pendingMediaJobIds.length > 0;
|
|
259952
|
+
return tools.filter((tool) => telegramTurn && BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name) || mediaPending && tool.name === "GetMedia");
|
|
259942
259953
|
}
|
|
259943
259954
|
/**
|
|
259944
259955
|
* Keep frequently used native tools resident and expose every other tool by
|
|
@@ -260275,11 +260286,15 @@ var init_turn = __esmMin((() => {
|
|
|
260275
260286
|
input,
|
|
260276
260287
|
origin
|
|
260277
260288
|
});
|
|
260278
|
-
|
|
260279
|
-
|
|
260289
|
+
if (this.activeTurn !== null) return {
|
|
260290
|
+
accepted: false,
|
|
260291
|
+
buffered: false,
|
|
260292
|
+
turnId: null
|
|
260293
|
+
};
|
|
260294
|
+
const buffered = this.agent.fullCompaction.isCompacting;
|
|
260280
260295
|
const turnId = this.launch(input, origin);
|
|
260281
260296
|
return {
|
|
260282
|
-
accepted:
|
|
260297
|
+
accepted: true,
|
|
260283
260298
|
buffered,
|
|
260284
260299
|
turnId
|
|
260285
260300
|
};
|
|
@@ -260767,7 +260782,9 @@ var init_turn = __esmMin((() => {
|
|
|
260767
260782
|
const turnHasAttachment = blunTurnHasAttachment(input);
|
|
260768
260783
|
const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind);
|
|
260769
260784
|
const fastConversation = turnThinkingEffort === "off" || turnThinkingEffort === "low";
|
|
260770
|
-
const
|
|
260785
|
+
const pendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
|
|
260786
|
+
const turnSystemPrompt = pendingMediaJobIds.length > 0 ? blunPendingMediaSystemPrompt(fastConversation ? this.agent.fastConversationSystemPrompt : this.agent.effectiveSystemPrompt, pendingMediaJobIds) : fastConversation ? this.agent.fastConversationSystemPrompt : void 0;
|
|
260787
|
+
const turnLLM = this.agent.llmForTurn(turnThinkingEffort, turnSystemPrompt);
|
|
260771
260788
|
let previousStepToolOutcome = "initial";
|
|
260772
260789
|
let currentStepHadTool = false;
|
|
260773
260790
|
let currentStepHadFailure = false;
|
|
@@ -260779,7 +260796,7 @@ var init_turn = __esmMin((() => {
|
|
|
260779
260796
|
try {
|
|
260780
260797
|
const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
|
|
260781
260798
|
const toolSelection = fastConversation ? {
|
|
260782
|
-
tools: [...blunFastConversationTools(eligibleTools, input)],
|
|
260799
|
+
tools: [...blunFastConversationTools(eligibleTools, input, pendingMediaJobIds)],
|
|
260783
260800
|
deferredToolCount: 0
|
|
260784
260801
|
} : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames) : {
|
|
260785
260802
|
tools: [],
|
|
@@ -260843,8 +260860,9 @@ var init_turn = __esmMin((() => {
|
|
|
260843
260860
|
if (steerEfforts.some((effort) => effort === void 0)) return;
|
|
260844
260861
|
const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
|
|
260845
260862
|
const steerThinkingEffort = "low";
|
|
260846
|
-
const
|
|
260847
|
-
const
|
|
260863
|
+
const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
|
|
260864
|
+
const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
|
|
260865
|
+
const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds)];
|
|
260848
260866
|
const steerHistory = () => blunFastConversationHistory(this.agent.context.history);
|
|
260849
260867
|
const buildSteerMessages = () => this.agent.context.project(steerHistory(), { dropOrphanResults: true });
|
|
260850
260868
|
const buildSteerMessagesStrict = () => this.agent.context.project(steerHistory(), {
|
|
@@ -311236,8 +311254,9 @@ async function assertSuccess(response, operation) {
|
|
|
311236
311254
|
} catch {}
|
|
311237
311255
|
throw new Error(`${operation} failed: HTTP ${String(response.status)}${detail ? `: ${detail}` : ""}`);
|
|
311238
311256
|
}
|
|
311239
|
-
var BlunMediaService;
|
|
311257
|
+
var createPendingMediaTracker, BlunMediaService;
|
|
311240
311258
|
var init_blun_media = __esmMin((() => {
|
|
311259
|
+
({ createPendingMediaTracker } = createRequire(import.meta.url)("./bin/pending-media-policy.cjs"));
|
|
311241
311260
|
BlunMediaService = class {
|
|
311242
311261
|
tokenProvider;
|
|
311243
311262
|
apiKey;
|
|
@@ -311245,6 +311264,7 @@ var init_blun_media = __esmMin((() => {
|
|
|
311245
311264
|
defaultHeaders;
|
|
311246
311265
|
customHeaders;
|
|
311247
311266
|
fetchImpl;
|
|
311267
|
+
pendingMedia = createPendingMediaTracker();
|
|
311248
311268
|
constructor(options) {
|
|
311249
311269
|
this.tokenProvider = options.tokenProvider;
|
|
311250
311270
|
this.apiKey = options.apiKey;
|
|
@@ -311297,28 +311317,28 @@ var init_blun_media = __esmMin((() => {
|
|
|
311297
311317
|
}
|
|
311298
311318
|
async getMedia(id, options) {
|
|
311299
311319
|
const response = await this.request(`/media/${encodeURIComponent(id)}`, { method: "GET" }, options);
|
|
311300
|
-
if (response.status === 409) return parseBlockedStatus(response, id);
|
|
311301
|
-
if (response.status === 410) return {
|
|
311320
|
+
if (response.status === 409) return this.trackMediaLookup(parseBlockedStatus(response, id));
|
|
311321
|
+
if (response.status === 410) return this.trackMediaLookup({
|
|
311302
311322
|
kind: "status",
|
|
311303
311323
|
id,
|
|
311304
311324
|
status: "expired"
|
|
311305
|
-
};
|
|
311325
|
+
});
|
|
311306
311326
|
await assertSuccess(response, "Media lookup");
|
|
311307
311327
|
const mimeType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
311308
|
-
if (mimeType === "application/json" || mimeType.endsWith("+json")) return parseStatus(await response.json(), id);
|
|
311309
|
-
if (mimeType === "text/plain") return {
|
|
311328
|
+
if (mimeType === "application/json" || mimeType.endsWith("+json")) return this.trackMediaLookup(parseStatus(await response.json(), id));
|
|
311329
|
+
if (mimeType === "text/plain") return this.trackMediaLookup({
|
|
311310
311330
|
kind: "text",
|
|
311311
311331
|
id,
|
|
311312
311332
|
mimeType,
|
|
311313
311333
|
text: await response.text()
|
|
311314
|
-
};
|
|
311334
|
+
});
|
|
311315
311335
|
if (!mimeType.startsWith("image/") && !mimeType.startsWith("audio/") && !mimeType.startsWith("video/")) throw new Error(`Media lookup returned unsupported content type ${mimeType || "(missing)"}`);
|
|
311316
|
-
return {
|
|
311336
|
+
return this.trackMediaLookup({
|
|
311317
311337
|
kind: "file",
|
|
311318
311338
|
id,
|
|
311319
311339
|
mimeType,
|
|
311320
311340
|
data: new Uint8Array(await response.arrayBuffer())
|
|
311321
|
-
};
|
|
311341
|
+
});
|
|
311322
311342
|
}
|
|
311323
311343
|
async submit(path, body, options) {
|
|
311324
311344
|
const response = await this.request(path, {
|
|
@@ -311327,7 +311347,16 @@ var init_blun_media = __esmMin((() => {
|
|
|
311327
311347
|
}, options);
|
|
311328
311348
|
if (response.status === 409) throw await blockedSubmissionError(response);
|
|
311329
311349
|
await assertSuccess(response, "Media request");
|
|
311330
|
-
|
|
311350
|
+
const job = parseJob(await response.json());
|
|
311351
|
+
this.pendingMedia.observeSubmission(job);
|
|
311352
|
+
return job;
|
|
311353
|
+
}
|
|
311354
|
+
trackMediaLookup(result) {
|
|
311355
|
+
this.pendingMedia.observeLookup(result);
|
|
311356
|
+
return result;
|
|
311357
|
+
}
|
|
311358
|
+
pendingMediaJobIds() {
|
|
311359
|
+
return this.pendingMedia.ids();
|
|
311331
311360
|
}
|
|
311332
311361
|
async request(path, init, options) {
|
|
311333
311362
|
const firstToken = await this.resolveToken(false);
|