blun-king-cli 9.1.304 → 9.1.305

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.
@@ -235,7 +235,15 @@ function openCognitiveStateStore({ home } = {}) {
235
235
  return { valid: true, events: rows.length, head_hash: previousHash };
236
236
  }
237
237
 
238
- return { commit, read, verify, close: () => db.close() };
238
+ return {
239
+ commit,
240
+ read,
241
+ verify,
242
+ close: () => {
243
+ try { db.exec('PRAGMA wal_checkpoint(TRUNCATE)'); } catch {}
244
+ db.close();
245
+ },
246
+ };
239
247
  }
240
248
 
241
249
  module.exports = { openCognitiveStateStore };
@@ -0,0 +1,158 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
5
+
6
+ const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
7
+ const RIGHTS_AUTHORITIES = new Set(['runtime_user_prompt_hook', 'runtime_tool_policy']);
8
+ const RIGHTS_DECISIONS = new Set(['passed', 'blocked', 'not_applicable']);
9
+ const TURN_REASONS = new Set(['completed', 'cancelled', 'filtered', 'failed']);
10
+
11
+ function fail(code) {
12
+ const error = new Error(code);
13
+ error.code = code;
14
+ throw error;
15
+ }
16
+
17
+ function exactKeys(value, keys) {
18
+ return value && typeof value === 'object' && !Array.isArray(value)
19
+ && Object.keys(value).every((key) => keys.has(key));
20
+ }
21
+
22
+ function safeId(value) {
23
+ const text = String(value ?? '').trim();
24
+ return SAFE_ID_RE.test(text) ? text : '';
25
+ }
26
+
27
+ function safeTurnId(value) {
28
+ return Number.isSafeInteger(value) && value >= 0 ? value : null;
29
+ }
30
+
31
+ function digestId(prefix, values) {
32
+ const digest = crypto.createHash('sha256').update(values.join('\0')).digest('hex').slice(0, 40);
33
+ return `${prefix}-${digest}`;
34
+ }
35
+
36
+ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now = () => new Date().toISOString() } = {}) {
37
+ const tenant = safeId(tenantId);
38
+ const agent = safeId(agentId);
39
+ const runtime = safeId(runtimeId ?? `runtime-${process.pid}-${Date.now()}`);
40
+ if (!tenant || !agent || !runtime || typeof now !== 'function') fail('COGNITIVE_LIFECYCLE_INVALID');
41
+ const store = openCognitiveStateStore({ home });
42
+ const stageTimes = new Map();
43
+ const stageResults = new Map();
44
+
45
+ function stageTime(stageKey) {
46
+ if (!stageTimes.has(stageKey)) {
47
+ const occurredAt = String(now());
48
+ if (Number.isNaN(Date.parse(occurredAt))) fail('COGNITIVE_LIFECYCLE_INVALID');
49
+ stageTimes.set(stageKey, occurredAt);
50
+ }
51
+ return stageTimes.get(stageKey);
52
+ }
53
+
54
+ function commitStage(stageKey, observations) {
55
+ if (stageResults.has(stageKey)) return { ...stageResults.get(stageKey), idempotent: true };
56
+ const occurredAt = stageTime(stageKey);
57
+ const eventId = digestId('cycle', [tenant, agent, runtime, stageKey]);
58
+ const normalized = observations.map((item, index) => ({
59
+ observation_id: digestId('cycleobs', [eventId, String(index)]),
60
+ ...item,
61
+ }));
62
+ for (let attempt = 0; attempt < 4; attempt += 1) {
63
+ const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
64
+ try {
65
+ const result = store.commit({
66
+ tenantId: tenant,
67
+ agentId: agent,
68
+ eventId,
69
+ expectedVersion,
70
+ occurredAt,
71
+ source: {
72
+ provider: 'runtime',
73
+ actor_id: agent,
74
+ context_id: runtime,
75
+ message_id: stageKey,
76
+ },
77
+ observations: normalized,
78
+ });
79
+ stageResults.set(stageKey, result);
80
+ return result;
81
+ } catch (error) {
82
+ if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
83
+ }
84
+ }
85
+ fail('COGNITIVE_VERSION_CONFLICT');
86
+ }
87
+
88
+ function startTurn(input) {
89
+ if (!exactKeys(input, new Set(['turnId', 'originKind']))) fail('COGNITIVE_LIFECYCLE_INVALID');
90
+ const turnId = safeTurnId(input.turnId);
91
+ const originKind = safeId(input.originKind);
92
+ if (turnId === null || !originKind) fail('COGNITIVE_LIFECYCLE_INVALID');
93
+ const key = `turn:${turnId}`;
94
+ return commitStage(`turn-${turnId}-start`, [
95
+ { domain: 'open_thread', key: `${key}:phase`, value: 'perceived', confidence: 1, scope: 'runtime' },
96
+ { domain: 'assumption', key: `${key}:classification`, value: `origin:${originKind}`, confidence: 1, scope: 'runtime' },
97
+ { domain: 'goal', key: `${key}:plan`, value: 'run-bounded-model-turn', confidence: 1, scope: 'runtime' },
98
+ { domain: 'next_trigger', key: `${key}:next`, value: 'runtime-policy-check', confidence: 1, scope: 'runtime' },
99
+ { domain: 'expected_evidence', key: `${key}:evidence`, value: 'turn.ended-event', confidence: 1, scope: 'runtime' },
100
+ ]);
101
+ }
102
+
103
+ function recordRightsCheck(input) {
104
+ if (!exactKeys(input, new Set(['turnId', 'decision', 'authority']))) fail('COGNITIVE_LIFECYCLE_INVALID');
105
+ const turnId = safeTurnId(input.turnId);
106
+ const decision = String(input.decision ?? '');
107
+ const authority = String(input.authority ?? '');
108
+ if (turnId === null || !RIGHTS_DECISIONS.has(decision)) fail('COGNITIVE_LIFECYCLE_INVALID');
109
+ if (!RIGHTS_AUTHORITIES.has(authority)) fail('COGNITIVE_RIGHTS_AUTHORITY_REQUIRED');
110
+ return commitStage(`turn-${turnId}-rights-${authority}`, [{
111
+ domain: 'world',
112
+ key: `turn:${turnId}:rights-check`,
113
+ value: `${decision}:${authority}`,
114
+ confidence: 1,
115
+ scope: 'runtime',
116
+ }]);
117
+ }
118
+
119
+ function endTurn(input) {
120
+ if (!exactKeys(input, new Set(['turnId', 'reason', 'durationMs']))) fail('COGNITIVE_LIFECYCLE_INVALID');
121
+ const turnId = safeTurnId(input.turnId);
122
+ const reason = String(input.reason ?? '');
123
+ const durationMs = Number(input.durationMs);
124
+ if (turnId === null || !TURN_REASONS.has(reason) || !Number.isSafeInteger(durationMs) || durationMs < 0) {
125
+ fail('COGNITIVE_LIFECYCLE_INVALID');
126
+ }
127
+ const key = `turn:${turnId}`;
128
+ return commitStage(`turn-${turnId}-end`, [
129
+ { domain: 'open_thread', key: `${key}:phase`, value: reason, confidence: 1, scope: 'runtime' },
130
+ { domain: 'expected_evidence', key: `${key}:result`, value: `turn.ended:${reason}:${durationMs}ms`, confidence: 1, scope: 'runtime' },
131
+ { domain: 'next_trigger', key: `${key}:next`, value: reason === 'completed' ? 'await-next-input' : 'inspect-turn-outcome', confidence: 1, scope: 'runtime' },
132
+ ]);
133
+ }
134
+
135
+ return {
136
+ startTurn,
137
+ recordRightsCheck,
138
+ endTurn,
139
+ read: () => store.read({ tenantId: tenant, agentId: agent }),
140
+ verify: () => store.verify({ tenantId: tenant, agentId: agent }),
141
+ close: () => store.close(),
142
+ };
143
+ }
144
+
145
+ function createRuntimeCognitiveTurnLifecycle({ home, agentName, runtimeId, now } = {}) {
146
+ const resolvedHome = String(home ?? '').trim();
147
+ const resolvedAgent = String(agentName ?? '').trim();
148
+ if (!resolvedHome || !resolvedAgent) fail('COGNITIVE_LIFECYCLE_INVALID');
149
+ return createCognitiveTurnLifecycle({
150
+ home: resolvedHome,
151
+ tenantId: digestId('home', [resolvedHome.toLowerCase()]),
152
+ agentId: digestId('agent', [resolvedAgent.toLowerCase()]),
153
+ runtimeId,
154
+ now,
155
+ });
156
+ }
157
+
158
+ module.exports = { createCognitiveTurnLifecycle, createRuntimeCognitiveTurnLifecycle };
package/blun.mjs CHANGED
@@ -261391,7 +261391,7 @@ function toolResultText(result) {
261391
261391
  function abandonedToolResultOutput(ended) {
261392
261392
  return `Tool call did not complete: ${ended.reason === "cancelled" ? "the turn was cancelled" : ended.reason === "failed" ? `the turn failed${ended.error !== void 0 ? ` (${ended.error.message})` : ""}` : "the turn ended"} before its result was recorded. Do not assume the tool completed successfully.`;
261393
261393
  }
261394
- var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, projectRecurringCronHistory, TelegramDeliveryLedger, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261394
+ var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261395
261395
  var init_turn = __esmMin((() => {
261396
261396
  init_dist$4();
261397
261397
  init_src$4();
@@ -261411,6 +261411,7 @@ var init_turn = __esmMin((() => {
261411
261411
  ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
261412
261412
  ({ projectRecurringCronHistory } = createRequire(import.meta.url)("./bin/recurring-cron-history-policy.cjs"));
261413
261413
  ({ TelegramDeliveryLedger } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
261414
+ ({ createRuntimeCognitiveTurnLifecycle } = createRequire(import.meta.url)("./bin/cognitive-turn-lifecycle.cjs"));
261414
261415
  BLUN_LEAN_TOOL_NAMES = new Set(BLUN_CORE_TOOL_NAMES);
261415
261416
  BLUN_ATTACHMENT_MARKER_RE = /\b(?:attachment_file_id|telegram-anhang|telegram attachment)\b/i;
261416
261417
  BLUN_TELEGRAM_OUTBOUND_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__(?:reply|react|edit_message)$/i;
@@ -261471,6 +261472,8 @@ var init_turn = __esmMin((() => {
261471
261472
  interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
261472
261473
  stepFailureByTurn = /* @__PURE__ */ new Map();
261473
261474
  currentStep = 0;
261475
+ cognitiveLifecycle;
261476
+ cognitiveLifecycleUnavailable = false;
261474
261477
  constructor(agent) {
261475
261478
  this.agent = agent;
261476
261479
  }
@@ -261478,6 +261481,33 @@ var init_turn = __esmMin((() => {
261478
261481
  get agentId() {
261479
261482
  return this.agent.homedir ? basename$2(this.agent.homedir) : this.agent.type;
261480
261483
  }
261484
+ getCognitiveLifecycle() {
261485
+ if (this.cognitiveLifecycleUnavailable) return null;
261486
+ if (this.cognitiveLifecycle !== void 0) return this.cognitiveLifecycle;
261487
+ const home = this.agent.blunHomeDir ?? this.agent.homedir;
261488
+ if (home === void 0) {
261489
+ this.cognitiveLifecycleUnavailable = true;
261490
+ return null;
261491
+ }
261492
+ try {
261493
+ this.cognitiveLifecycle = createRuntimeCognitiveTurnLifecycle({
261494
+ home,
261495
+ agentName: this.agent.activeProfile?.name ?? this.agent.type
261496
+ });
261497
+ return this.cognitiveLifecycle;
261498
+ } catch (error) {
261499
+ this.cognitiveLifecycleUnavailable = true;
261500
+ this.agent.telemetry.track("cognitive_lifecycle_error", { stage: "open", error_type: error?.code ?? error?.name ?? "Error" });
261501
+ return null;
261502
+ }
261503
+ }
261504
+ recordCognitiveStage(method, input) {
261505
+ try {
261506
+ this.getCognitiveLifecycle()?.[method](input);
261507
+ } catch (error) {
261508
+ this.agent.telemetry.track("cognitive_lifecycle_error", { stage: method, error_type: error?.code ?? error?.name ?? "Error" });
261509
+ }
261510
+ }
261481
261511
  prompt(input, origin = USER_PROMPT_ORIGIN) {
261482
261512
  return this.promptWithAcceptance(input, origin).turnId;
261483
261513
  }
@@ -261805,6 +261835,12 @@ var init_turn = __esmMin((() => {
261805
261835
  origin
261806
261836
  });
261807
261837
  this.agent.context.appendUserMessage(input, origin);
261838
+ this.recordCognitiveStage("startTurn", { turnId, originKind: origin.kind });
261839
+ this.recordCognitiveStage("recordRightsCheck", {
261840
+ turnId,
261841
+ decision: "not_applicable",
261842
+ authority: "runtime_user_prompt_hook"
261843
+ });
261808
261844
  const ended = {
261809
261845
  type: "turn.ended",
261810
261846
  turnId,
@@ -261812,6 +261848,7 @@ var init_turn = __esmMin((() => {
261812
261848
  durationMs: Date.now() - startedAt
261813
261849
  };
261814
261850
  this.agent.usage.endTurn();
261851
+ this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
261815
261852
  this.agent.emitEvent(ended);
261816
261853
  return ended;
261817
261854
  }
@@ -261841,6 +261878,7 @@ var init_turn = __esmMin((() => {
261841
261878
  origin
261842
261879
  });
261843
261880
  this.agent.context.appendUserMessage(input, origin);
261881
+ this.recordCognitiveStage("startTurn", { turnId, originKind: origin.kind });
261844
261882
  const startedAt = Date.now();
261845
261883
  let ended;
261846
261884
  let blockedByUserPromptHook = false;
@@ -261848,6 +261886,11 @@ var init_turn = __esmMin((() => {
261848
261886
  let errorEvent;
261849
261887
  try {
261850
261888
  const promptHookEnded = await this.applyUserPromptHook(turnId, input, origin, signal, startedAt);
261889
+ this.recordCognitiveStage("recordRightsCheck", {
261890
+ turnId,
261891
+ decision: origin.kind !== "user" ? "not_applicable" : promptHookEnded?.blocked === true ? "blocked" : "passed",
261892
+ authority: "runtime_user_prompt_hook"
261893
+ });
261851
261894
  if (promptHookEnded !== void 0) {
261852
261895
  ended = promptHookEnded.event;
261853
261896
  blockedByUserPromptHook = promptHookEnded.blocked;
@@ -261919,6 +261962,7 @@ var init_turn = __esmMin((() => {
261919
261962
  mode: this.telemetryModeByTurn.get(turnId) ?? this.telemetryMode(),
261920
261963
  ...this.requestProviderProps()
261921
261964
  });
261965
+ this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
261922
261966
  this.agent.emitEvent(ended);
261923
261967
  this.agent.endResponderTurn();
261924
261968
  if (standalone && this.currentId === turnId && this.agent.goal.getGoal().goal?.status !== "active") this.activeTurn = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.304",
3
+ "version": "9.1.305",
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": {