blun-king-cli 9.1.342 → 9.1.344

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.
@@ -198,6 +198,50 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
198
198
  ]);
199
199
  }
200
200
 
201
+ function recordToolBatch(input) {
202
+ if (!exactKeys(input, new Set(['turnId', 'entries']))) fail('COGNITIVE_LIFECYCLE_INVALID');
203
+ const turnId = safeTurnId(input.turnId);
204
+ if (turnId === null || !Array.isArray(input.entries) || input.entries.length < 1 || input.entries.length > 10) {
205
+ fail('COGNITIVE_LIFECYCLE_INVALID');
206
+ }
207
+ const observations = [];
208
+ const stageParts = [];
209
+ for (const entry of input.entries) {
210
+ const { toolCallId, toolName, callKey } = toolFields(
211
+ { turnId, ...entry },
212
+ new Set(['turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs']),
213
+ );
214
+ const decision = String(entry.decision ?? '');
215
+ const outcome = String(entry.outcome ?? '');
216
+ const durationMs = Number(entry.durationMs);
217
+ if (!TOOL_POLICY_DECISIONS.has(decision) || !TOOL_OUTCOMES.has(outcome)
218
+ || !Number.isSafeInteger(durationMs) || durationMs < 0) fail('COGNITIVE_LIFECYCLE_INVALID');
219
+ stageParts.push(`${toolCallId}:${decision}:${outcome}:${durationMs}`);
220
+ observations.push({
221
+ domain: 'world',
222
+ key: `turn:${turnId}:${callKey}:tool-policy`,
223
+ value: `${decision}:runtime_tool_policy:${toolName}`,
224
+ confidence: 1,
225
+ scope: 'runtime',
226
+ }, {
227
+ domain: 'expected_evidence',
228
+ key: `turn:${turnId}:${callKey}:tool-result`,
229
+ value: `${outcome}:${durationMs}ms:${toolName}`,
230
+ confidence: 1,
231
+ scope: 'runtime',
232
+ }, {
233
+ domain: 'next_trigger',
234
+ key: `turn:${turnId}:${callKey}:tool-next`,
235
+ value: outcome === 'success' ? 'continue-after-tool' : 'inspect-tool-failure',
236
+ confidence: 1,
237
+ scope: 'runtime',
238
+ });
239
+ }
240
+ const batchKey = digestId('toolbatch', stageParts);
241
+ const result = commitStage(`turn-${turnId}-${batchKey}`, observations);
242
+ return { ...result, events: 1, entries: input.entries.length };
243
+ }
244
+
201
245
  function projectForTurn(input) {
202
246
  if (!exactKeys(input, new Set(['turnId', 'focusScopes']))) fail('COGNITIVE_LIFECYCLE_INVALID');
203
247
  const turnId = safeTurnId(input.turnId);
@@ -226,6 +270,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
226
270
  recordRightsCheck,
227
271
  recordToolPolicy,
228
272
  recordToolResult,
273
+ recordToolBatch,
229
274
  recordFocusSnapshot,
230
275
  authorizeAttention,
231
276
  projectForTurn,
@@ -8,6 +8,8 @@ const DEFAULT_SILENCE_MS = 60_000;
8
8
  const RESUME_APPROVAL = /^(?:ja|yes|weiter|mach(?:e)? weiter|du kannst weiter(?:machen)?|bitte weiter|fortsetzen|resume|go)(?:[\s.!?,].*)?$/iu;
9
9
  const CONVERSATION_CLOSE = /^(?:danke(?: dir)?|dankesch(?:oe|\u00f6)n|alles klar|ok(?:ay)?|passt|das war(?:'s| es| alles)|mehr nicht|fertig)(?:[\s.!?,].*)?$/iu;
10
10
  const EXPLICIT_PAUSE = /^(?:(?:bitte\s+)?(?:pause|pausier(?:e)?|stop|stopp|warte|halt(?:e)?\s+an|nicht\s+weiter(?:machen)?))(?:[\s.!?,].*)?$/iu;
11
+ const DIRECT_TELEGRAM_CHANNEL = /<channel\b(?=[^>]*\bsource=["']telegram["'])(?=[^>]*\bpriority=["']direct["'])[^>]*>/iu;
12
+ const TELEGRAM_REPLY_TOOL = /^mcp__[^\s]*telegram[^\s]*__reply$/iu;
11
13
 
12
14
  function isPrivateTelegramChat(chatId) {
13
15
  return /^[1-9]\d*$/u.test(String(chatId ?? '').trim());
@@ -53,6 +55,20 @@ function isExplicitPauseRequest(text) {
53
55
  return EXPLICIT_PAUSE.test(String(text ?? '').trim());
54
56
  }
55
57
 
58
+ function createDirectReplyTurnStop(inputText) {
59
+ const direct = DIRECT_TELEGRAM_CHANNEL.test(String(inputText ?? ''));
60
+ let delivered = false;
61
+ return {
62
+ noteToolResult(toolName, isError) {
63
+ if (direct && isError !== true && TELEGRAM_REPLY_TOOL.test(String(toolName ?? ''))) {
64
+ delivered = true;
65
+ }
66
+ return delivered;
67
+ },
68
+ shouldStop: () => delivered,
69
+ };
70
+ }
71
+
56
72
  function createDirectFocusController(options = {}) {
57
73
  const setTimer = options.setTimer ?? setTimeout;
58
74
  const clearTimer = options.clearTimer ?? clearTimeout;
@@ -213,6 +229,7 @@ function readDirectFocusCheckpoint(env = process.env) {
213
229
  module.exports = {
214
230
  DEFAULT_SILENCE_MS,
215
231
  createDirectFocusController,
232
+ createDirectReplyTurnStop,
216
233
  directFocusCheckpointPath,
217
234
  enqueueTelegramDirect,
218
235
  isConversationClose,
package/blun.mjs CHANGED
@@ -261553,6 +261553,8 @@ var init_turn = __esmMin((() => {
261553
261553
  currentStep = 0;
261554
261554
  cognitiveLifecycle;
261555
261555
  cognitiveLifecycleUnavailable = false;
261556
+ cognitiveToolPolicyByCall = /* @__PURE__ */ new Map();
261557
+ cognitiveToolBatchesByTurn = /* @__PURE__ */ new Map();
261556
261558
  constructor(agent) {
261557
261559
  this.agent = agent;
261558
261560
  }
@@ -261587,6 +261589,40 @@ var init_turn = __esmMin((() => {
261587
261589
  this.agent.telemetry.track("cognitive_lifecycle_error", { stage: method, error_type: error?.code ?? error?.name ?? "Error" });
261588
261590
  }
261589
261591
  }
261592
+ bufferCognitiveToolPolicy(input) {
261593
+ this.cognitiveToolPolicyByCall.set(input.toolCallId, input);
261594
+ }
261595
+ bufferCognitiveToolResult(input) {
261596
+ const policy = this.cognitiveToolPolicyByCall.get(input.toolCallId);
261597
+ if (policy === void 0 || policy.turnId !== input.turnId) {
261598
+ this.recordCognitiveStage("recordToolResult", input);
261599
+ return;
261600
+ }
261601
+ this.cognitiveToolPolicyByCall.delete(input.toolCallId);
261602
+ const entries = this.cognitiveToolBatchesByTurn.get(input.turnId) ?? [];
261603
+ entries.push({
261604
+ toolCallId: input.toolCallId,
261605
+ toolName: input.toolName,
261606
+ decision: policy.decision,
261607
+ outcome: input.outcome,
261608
+ durationMs: input.durationMs
261609
+ });
261610
+ this.cognitiveToolBatchesByTurn.set(input.turnId, entries);
261611
+ }
261612
+ flushCognitiveToolEvidence(turnId, includePending) {
261613
+ const entries = this.cognitiveToolBatchesByTurn.get(turnId) ?? [];
261614
+ this.cognitiveToolBatchesByTurn.delete(turnId);
261615
+ for (let offset = 0; offset < entries.length; offset += 10) this.recordCognitiveStage("recordToolBatch", {
261616
+ turnId,
261617
+ entries: entries.slice(offset, offset + 10)
261618
+ });
261619
+ if (!includePending) return;
261620
+ for (const [toolCallId, policy] of this.cognitiveToolPolicyByCall) {
261621
+ if (policy.turnId !== turnId) continue;
261622
+ this.cognitiveToolPolicyByCall.delete(toolCallId);
261623
+ this.recordCognitiveStage("recordToolPolicy", policy);
261624
+ }
261625
+ }
261590
261626
  projectCognitiveState(turnId) {
261591
261627
  try {
261592
261628
  return this.getCognitiveLifecycle()?.projectForTurn({ turnId }) ?? null;
@@ -261948,6 +261984,7 @@ var init_turn = __esmMin((() => {
261948
261984
  durationMs: Date.now() - startedAt
261949
261985
  };
261950
261986
  this.agent.usage.endTurn();
261987
+ this.flushCognitiveToolEvidence(turnId, true);
261951
261988
  this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
261952
261989
  this.agent.emitEvent(ended);
261953
261990
  return ended;
@@ -262062,6 +262099,7 @@ var init_turn = __esmMin((() => {
262062
262099
  mode: this.telemetryModeByTurn.get(turnId) ?? this.telemetryMode(),
262063
262100
  ...this.requestProviderProps()
262064
262101
  });
262102
+ this.flushCognitiveToolEvidence(turnId, true);
262065
262103
  this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
262066
262104
  this.agent.emitEvent(ended);
262067
262105
  this.agent.endResponderTurn();
@@ -262140,6 +262178,7 @@ var init_turn = __esmMin((() => {
262140
262178
  async runStepLoop(turnId, signal, input, origin) {
262141
262179
  let stopHookContinuationUsed = false;
262142
262180
  let goalOutcomeMessageContinuationUsed = false;
262181
+ const directReplyTurnStop = createDirectReplyTurnStop(blunExtractText(input));
262143
262182
  const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
262144
262183
  if (blunTurnNeedsInitialMcp(input, origin)) await this.agent.mcp?.waitForInitialLoad(signal);
262145
262184
  const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
@@ -262269,13 +262308,14 @@ var init_turn = __esmMin((() => {
262269
262308
  },
262270
262309
  afterStep: async ({ usage }) => {
262271
262310
  previousStepToolOutcome = currentStepHadTool ? currentStepHadFailure ? "failure" : "success" : "none";
262311
+ this.flushCognitiveToolEvidence(turnId, false);
262272
262312
  this.agent.usage.record(this.agent.activeResponderModel ?? model, usage, "turn");
262273
262313
  if (stopForGoalBudget) this.setActiveSteerAcceptance(turnId, false);
262274
262314
  await this.agent.toolResultBatchOffload.detect();
262275
262315
  await this.agent.fullCompaction.afterStep(signal);
262276
262316
  if (compactConversationTool !== void 0 && this.agent.fullCompaction.isProactiveCompactionEligible() && !selectedTools.includes(compactConversationTool)) selectedTools.push(compactConversationTool);
262277
262317
  deduper.endStep();
262278
- return stopForGoalBudget ? { stopTurn: true } : void 0;
262318
+ return stopForGoalBudget || directReplyTurnStop.shouldStop() ? { stopTurn: true } : void 0;
262279
262319
  },
262280
262320
  shouldContinueAfterStop: async (ctx) => {
262281
262321
  const { signal } = ctx;
@@ -262321,7 +262361,7 @@ var init_turn = __esmMin((() => {
262321
262361
  authorizeToolExecution: async (ctx) => {
262322
262362
  try {
262323
262363
  const resolution = await this.agent.permission.beforeToolCall(ctx);
262324
- this.recordCognitiveStage("recordToolPolicy", {
262364
+ this.bufferCognitiveToolPolicy({
262325
262365
  turnId,
262326
262366
  toolCallId: ctx.toolCall.id,
262327
262367
  toolName: ctx.toolCall.name,
@@ -262329,7 +262369,7 @@ var init_turn = __esmMin((() => {
262329
262369
  });
262330
262370
  return resolution;
262331
262371
  } catch (error) {
262332
- this.recordCognitiveStage("recordToolPolicy", {
262372
+ this.bufferCognitiveToolPolicy({
262333
262373
  turnId,
262334
262374
  toolCallId: ctx.toolCall.id,
262335
262375
  toolName: ctx.toolCall.name,
@@ -262343,6 +262383,7 @@ var init_turn = __esmMin((() => {
262343
262383
  const { isError, output } = finalResult;
262344
262384
  currentStepHadTool = true;
262345
262385
  if (isError === true) currentStepHadFailure = true;
262386
+ directReplyTurnStop.noteToolResult(ctx.toolCall.name, isError);
262346
262387
  const event = isError === true ? "PostToolUseFailure" : "PostToolUse";
262347
262388
  this.agent.hooks?.fireAndForgetTrigger(event, {
262348
262389
  matcherValue: ctx.toolCall.name,
@@ -262478,7 +262519,7 @@ var init_turn = __esmMin((() => {
262478
262519
  };
262479
262520
  const errorType = outcome === "error" ? telemetryToolErrorType(event.result) : void 0;
262480
262521
  if (errorType !== void 0) properties["error_type"] = errorType;
262481
- this.recordCognitiveStage("recordToolResult", {
262522
+ this.bufferCognitiveToolResult({
262482
262523
  turnId,
262483
262524
  toolCallId: event.toolCallId,
262484
262525
  toolName: started.name,
@@ -419037,7 +419078,7 @@ registerUiCatalogFragment({
419037
419078
  */
419038
419079
  var { projectUnaddressedTelegramContext } = createRequire(import.meta.url)("./bin/telegram-context-projection-policy.cjs");
419039
419080
  var { enqueueTelegramUrgent, rewriteTelegramUrgentEnvelope, telegramUrgentMessage } = createRequire(import.meta.url)("./bin/telegram-urgent-policy.cjs");
419040
- var { createDirectFocusController, enqueueTelegramDirect, readDirectFocusCheckpoint, rewriteTelegramDirectEnvelope, telegramDirectMessage, writeDirectFocusCheckpoint } = createRequire(import.meta.url)("./bin/telegram-direct-focus-policy.cjs");
419081
+ var { createDirectFocusController, createDirectReplyTurnStop, enqueueTelegramDirect, readDirectFocusCheckpoint, rewriteTelegramDirectEnvelope, telegramDirectMessage, writeDirectFocusCheckpoint } = createRequire(import.meta.url)("./bin/telegram-direct-focus-policy.cjs");
419041
419082
  var { removeQueuedReloadCommands, removeQueuedSlashCommands } = createRequire(import.meta.url)("./bin/reload-queue-policy.cjs");
419042
419083
  const MAX_BUFFERED_CONTEXT_MESSAGES = 20;
419043
419084
  const MAX_BUFFERED_CONTEXT_CHARS = 24e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.342",
3
+ "version": "9.1.344",
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": {