blun-king-cli 9.1.454 → 9.1.456

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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const crypto = require('node:crypto');
4
+ const { extractChecksumClaims } = require('./outbound-claim-provenance.cjs');
4
5
 
5
6
  const PHASES = new Set(['orient', 'plan', 'act', 'verify', 'learn', 'wait']);
6
7
  const EVIDENCE_BASES = new Set([
@@ -14,15 +15,20 @@ const TRIGGER_KINDS = new Set([
14
15
  ]);
15
16
  const VERIFICATION_SUBJECTS = new Set(['result', 'verifier']);
16
17
  const VERIFICATION_KINDS = new Set(['inspection', 'integrity', 'syntax', 'test', 'reachability']);
18
+ const EXTERNAL_REPORT_SOURCES = new Set(['telegram']);
17
19
  const MODEL_KEYS = new Set([
18
- 'revision', 'phase', 'evidenceBasis', 'epistemicState', 'lastVerified', 'nextAction', 'expectedEvidence', 'verificationProof', 'nextTrigger', 'problemFrame', 'updatedAt',
20
+ 'revision', 'phase', 'evidenceBasis', 'epistemicState', 'lastVerified', 'nextAction', 'expectedEvidence', 'verificationProof', 'nextTrigger', 'problemFrame', 'externalReportSource', 'updatedAt',
19
21
  ]);
20
- const RUNTIME_KEYS = new Set([...MODEL_KEYS, 'evidenceReceipt']);
22
+ const RUNTIME_KEYS = new Set([...MODEL_KEYS, 'evidenceReceipt', 'externalReportOrigin']);
21
23
  const PROBLEM_FRAME_KEYS = new Set([
22
24
  'successCriterion', 'missingKnowledge', 'candidateActions', 'selectedAction',
23
25
  'selectionReason', 'supportChoice', 'risk', 'reversibility', 'decisionBasis',
24
26
  ]);
25
27
  const NEXT_TRIGGER_KEYS = new Set(['kind', 'condition', 'dueAt']);
28
+ const EXTERNAL_REPORT_SELECTOR_KEYS = new Set(['source', 'chatId', 'messageId']);
29
+ const EXTERNAL_REPORT_ORIGIN_KEYS = new Set([
30
+ 'source', 'reporter', 'reporterRef', 'eventRef', 'occurredAt',
31
+ ]);
26
32
  const EVIDENCE_INPUT_KEYS = new Set([
27
33
  'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs', 'toolArgs',
28
34
  'resultEvidenceKinds', 'resultEvidenceScopes',
@@ -32,6 +38,7 @@ const REQUIRED_EVIDENCE_INPUT_KEYS = new Set([
32
38
  ]);
33
39
  const EVIDENCE_DIGEST_RE = /^[a-f0-9]{16}$/u;
34
40
  const EVIDENCE_PRODUCER_REF_RE = /^[a-f0-9]{16}$/u;
41
+ const EXTERNAL_REPORT_REF_RE = /^[a-f0-9]{16}$/u;
35
42
  const DECISION_BASIS_RE = /^[a-f0-9]{16}$/u;
36
43
  const COMPLETION_CRITERION_REF_RE = /^[a-f0-9]{16}$/u;
37
44
  const ISO_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}(?::?\d{2})?)$/u;
@@ -189,6 +196,140 @@ function evidenceProducerRef(identity) {
189
196
  .slice(0, 16);
190
197
  }
191
198
 
199
+ function normalizedExternalReportSource(value, field = 'external report source') {
200
+ const source = String(value ?? '').trim();
201
+ if (!EXTERNAL_REPORT_SOURCES.has(source)) throw new TypeError(`${field} is invalid`);
202
+ return source;
203
+ }
204
+
205
+ function normalizeExternalReportSelector(input) {
206
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
207
+ throw new TypeError('externalReportSource is required for external_report evidenceBasis');
208
+ }
209
+ for (const key of Object.keys(input)) {
210
+ if (!EXTERNAL_REPORT_SELECTOR_KEYS.has(key)) {
211
+ throw new TypeError(`externalReportSource field is unsupported: ${key}`);
212
+ }
213
+ }
214
+ return Object.freeze({
215
+ source: normalizedExternalReportSource(input.source),
216
+ chatId: bounded(input.chatId, 'externalReportSource chatId', 64),
217
+ messageId: bounded(input.messageId, 'externalReportSource messageId', 64),
218
+ });
219
+ }
220
+
221
+ function externalReportSourceFromChannelMeta(meta) {
222
+ if (!meta || typeof meta !== 'object' || Array.isArray(meta)) {
223
+ throw new TypeError('channel metadata is required for external report provenance');
224
+ }
225
+ const reporter = bounded(meta.user ?? meta.user_id, 'external report reporter', 128);
226
+ return Object.freeze({
227
+ source: 'telegram',
228
+ chatId: bounded(meta.chat_id, 'external report chatId', 64),
229
+ messageId: bounded(meta.message_id, 'external report messageId', 64),
230
+ reporter,
231
+ reporterId: bounded(meta.user_id ?? reporter, 'external report reporterId', 128),
232
+ occurredAt: normalizedTimestamp(meta.ts, 'external report occurredAt', true),
233
+ });
234
+ }
235
+
236
+ function normalizeRuntimeExternalReportSource(input) {
237
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
238
+ throw new TypeError('trusted external report source is invalid');
239
+ }
240
+ const reporter = bounded(input.reporter ?? input.reporterId, 'external report reporter', 128);
241
+ const claimTokens = extractChecksumClaims(
242
+ Array.isArray(input.claimTokens) ? input.claimTokens.join(' ') : '',
243
+ );
244
+ return Object.freeze({
245
+ source: normalizedExternalReportSource(input.source),
246
+ chatId: bounded(input.chatId, 'external report chatId', 64),
247
+ messageId: bounded(input.messageId, 'external report messageId', 64),
248
+ reporter,
249
+ reporterId: bounded(input.reporterId ?? reporter, 'external report reporterId', 128),
250
+ occurredAt: normalizedTimestamp(input.occurredAt, 'external report occurredAt', true),
251
+ ...(claimTokens.length > 0 ? { claimTokens } : {}),
252
+ });
253
+ }
254
+
255
+ function externalReportSourcesFromOrigin(origin) {
256
+ if (!origin || typeof origin !== 'object' || !Array.isArray(origin.externalReportSources)) {
257
+ return Object.freeze([]);
258
+ }
259
+ const sources = [];
260
+ const seen = new Set();
261
+ for (const value of origin.externalReportSources) {
262
+ let source;
263
+ try {
264
+ source = normalizeRuntimeExternalReportSource(value);
265
+ } catch {
266
+ continue;
267
+ }
268
+ const key = `${source.source}\0${source.chatId}\0${source.messageId}`;
269
+ if (seen.has(key)) continue;
270
+ seen.add(key);
271
+ sources.push(source);
272
+ }
273
+ return Object.freeze(sources.slice(0, 32));
274
+ }
275
+
276
+ function normalizedExternalReportRef(value, field) {
277
+ const ref = String(value ?? '').trim();
278
+ if (!EXTERNAL_REPORT_REF_RE.test(ref)) throw new TypeError(`${field} is invalid`);
279
+ return ref;
280
+ }
281
+
282
+ function normalizeExternalReportOrigin(input) {
283
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
284
+ throw new TypeError('externalReportOrigin is invalid');
285
+ }
286
+ for (const key of Object.keys(input)) {
287
+ if (!EXTERNAL_REPORT_ORIGIN_KEYS.has(key)) {
288
+ throw new TypeError(`externalReportOrigin field is unsupported: ${key}`);
289
+ }
290
+ }
291
+ return Object.freeze({
292
+ source: normalizedExternalReportSource(input.source, 'externalReportOrigin source'),
293
+ reporter: bounded(input.reporter, 'externalReportOrigin reporter', 128),
294
+ reporterRef: normalizedExternalReportRef(input.reporterRef, 'externalReportOrigin reporterRef'),
295
+ eventRef: normalizedExternalReportRef(input.eventRef, 'externalReportOrigin eventRef'),
296
+ occurredAt: normalizedTimestamp(input.occurredAt, 'externalReportOrigin occurredAt', true),
297
+ });
298
+ }
299
+
300
+ function externalReportOriginFromRuntimeSource(input) {
301
+ const report = normalizeRuntimeExternalReportSource(input);
302
+ const reporterRef = crypto.createHash('sha256')
303
+ .update(`external-report-reporter:${report.source}\0${report.reporterId}`)
304
+ .digest('hex')
305
+ .slice(0, 16);
306
+ const eventRef = crypto.createHash('sha256')
307
+ .update(`external-report-event:${report.source}\0${report.chatId}\0${report.messageId}\0${reporterRef}\0${report.occurredAt}`)
308
+ .digest('hex')
309
+ .slice(0, 16);
310
+ return Object.freeze({
311
+ source: report.source,
312
+ reporter: report.reporter,
313
+ reporterRef,
314
+ eventRef,
315
+ occurredAt: report.occurredAt,
316
+ });
317
+ }
318
+
319
+ function resolveExternalReportOrigin(selectorInput, runtimeExternalReports) {
320
+ const selector = normalizeExternalReportSelector(selectorInput);
321
+ const reports = Array.isArray(runtimeExternalReports)
322
+ ? runtimeExternalReports.map(normalizeRuntimeExternalReportSource)
323
+ : [];
324
+ const report = reports.find((candidate) => candidate.source === selector.source
325
+ && candidate.chatId === selector.chatId
326
+ && candidate.messageId === selector.messageId);
327
+ if (report === undefined) {
328
+ throw new TypeError('externalReportSource does not match a trusted external report in the current turn');
329
+ }
330
+ return externalReportOriginFromRuntimeSource(report);
331
+ }
332
+
192
333
  function normalizedEvidenceProducerRef(value, field = 'evidence producer ref') {
193
334
  const ref = String(value ?? '').trim();
194
335
  if (!EVIDENCE_PRODUCER_REF_RE.test(ref)) throw new TypeError(`${field} is invalid`);
@@ -753,7 +894,7 @@ function assertActionCheckpointRevision(current, input) {
753
894
  return inputRevision;
754
895
  }
755
896
 
756
- function assertActionCheckpointEvidenceBasis(current, input, runtimeEvidence) {
897
+ function assertActionCheckpointEvidenceBasis(current, input, runtimeEvidence, runtimeExternalReports) {
757
898
  const basis = normalizedEvidenceBasis(input?.evidenceBasis);
758
899
  const epistemicState = normalizedEpistemicState(input?.epistemicState);
759
900
  if (basis === 'runtime_tool') {
@@ -765,8 +906,15 @@ function assertActionCheckpointEvidenceBasis(current, input, runtimeEvidence) {
765
906
  throw new TypeError('runtime_tool evidenceBasis requires verified epistemicState');
766
907
  }
767
908
  }
768
- if (basis === 'external_report' && epistemicState === 'verified') {
769
- throw new TypeError('external_report evidenceBasis cannot claim verified epistemicState');
909
+ if (basis === 'external_report') {
910
+ if (epistemicState === 'verified') {
911
+ throw new TypeError('external_report evidenceBasis cannot claim verified epistemicState');
912
+ }
913
+ if (runtimeExternalReports !== undefined) {
914
+ resolveExternalReportOrigin(input?.externalReportSource, runtimeExternalReports);
915
+ }
916
+ } else if (input?.externalReportSource !== undefined) {
917
+ throw new TypeError('externalReportSource requires external_report evidenceBasis');
770
918
  }
771
919
  if (basis === 'carried_forward') {
772
920
  if (!current) throw new TypeError('carried_forward evidenceBasis requires a current checkpoint');
@@ -817,6 +965,22 @@ function normalizeActionCheckpoint(input, options = {}) {
817
965
  if (input.nextTrigger !== undefined) checkpoint.nextTrigger = normalizeNextTrigger(input.nextTrigger, phase);
818
966
  else if (!replay) throw new TypeError('nextTrigger is required');
819
967
  if (input.problemFrame !== undefined) checkpoint.problemFrame = normalizeProblemFrame(input.problemFrame);
968
+ if (input.externalReportSource !== undefined && evidenceBasis !== 'external_report') {
969
+ throw new TypeError('externalReportSource requires external_report evidenceBasis');
970
+ }
971
+ if (evidenceBasis === 'external_report' && options.runtimeExternalReports !== undefined) {
972
+ checkpoint.externalReportOrigin = resolveExternalReportOrigin(
973
+ input.externalReportSource,
974
+ options.runtimeExternalReports,
975
+ );
976
+ } else if (replay && input.externalReportOrigin !== undefined) {
977
+ checkpoint.externalReportOrigin = normalizeExternalReportOrigin(input.externalReportOrigin);
978
+ } else if (evidenceBasis === 'carried_forward'
979
+ && options.previousCheckpoint?.externalReportOrigin !== undefined) {
980
+ checkpoint.externalReportOrigin = normalizeExternalReportOrigin(
981
+ options.previousCheckpoint.externalReportOrigin,
982
+ );
983
+ }
820
984
  const evidenceReceipt = options.runtimeEvidence !== undefined
821
985
  ? normalizeActionEvidenceReceipt(options.runtimeEvidence)
822
986
  : options.preserveRuntimeEvidence === true && input.evidenceReceipt !== undefined
@@ -891,6 +1055,10 @@ function projectActionCheckpoint(checkpoint) {
891
1055
  lines.push(`Reversibility: ${frame.reversibility}`);
892
1056
  if (frame.decisionBasis !== undefined) lines.push(`Decision basis: ${frame.decisionBasis.join(' | ')}`);
893
1057
  }
1058
+ if (value.externalReportOrigin !== undefined) {
1059
+ const report = value.externalReportOrigin;
1060
+ lines.push(`External report origin: ${report.reporter} via ${report.source}; event ${report.eventRef}; occurred ${report.occurredAt}`);
1061
+ }
894
1062
  if (value.evidenceReceipt !== undefined) {
895
1063
  const receipt = value.evidenceReceipt;
896
1064
  lines.push(`Runtime evidence: turn ${receipt.turnId}; ${receipt.completedTools} completed, ${receipt.successfulTools} successful, ${receipt.failedTools} failed; digest ${receipt.digest}`);
@@ -910,6 +1078,9 @@ module.exports = {
910
1078
  completionCriterionRef,
911
1079
  evidenceProducerRef,
912
1080
  emptyActionEvidenceReceipt,
1081
+ externalReportOriginFromRuntimeSource,
1082
+ externalReportSourceFromChannelMeta,
1083
+ externalReportSourcesFromOrigin,
913
1084
  normalizeActionCheckpoint,
914
1085
  normalizeVerificationProof,
915
1086
  projectActionCheckpoint,
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ const MAX_CLAIMS = 32;
4
+ const CHECKSUM_CLAIM_RE = /(?<![A-Za-z0-9])[A-Fa-f0-9]{16,128}(?![A-Za-z0-9])/gu;
5
+ const TELEGRAM_MESSAGE_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__(?:reply|edit_message)$/iu;
6
+ const REF_RE = /^[a-f0-9]{16}$/u;
7
+ const ISO_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}(?::?\d{2})?)$/u;
8
+
9
+ function extractChecksumClaims(value) {
10
+ const claims = [];
11
+ const seen = new Set();
12
+ const text = typeof value === 'string' ? value : String(value ?? '');
13
+ for (const match of text.matchAll(CHECKSUM_CLAIM_RE)) {
14
+ const claim = match[0].toLowerCase();
15
+ if (seen.has(claim)) continue;
16
+ seen.add(claim);
17
+ claims.push(claim);
18
+ if (claims.length >= MAX_CLAIMS) break;
19
+ }
20
+ return Object.freeze(claims);
21
+ }
22
+
23
+ function boundedText(value, max) {
24
+ const text = String(value ?? '')
25
+ .replace(/[\u0000-\u001f\u007f]+/gu, ' ')
26
+ .replace(/\s+/gu, ' ')
27
+ .trim();
28
+ return text.length > 0 ? text.slice(0, max) : undefined;
29
+ }
30
+
31
+ function optionalRef(value) {
32
+ const ref = String(value ?? '').trim().toLowerCase();
33
+ return REF_RE.test(ref) ? ref : undefined;
34
+ }
35
+
36
+ function optionalTimestamp(value) {
37
+ const timestamp = String(value ?? '').trim();
38
+ return ISO_TIMESTAMP_RE.test(timestamp) ? timestamp : undefined;
39
+ }
40
+
41
+ function normalizedExternalReports(value) {
42
+ if (!Array.isArray(value)) return [];
43
+ const reports = [];
44
+ for (const report of value.slice(0, MAX_CLAIMS)) {
45
+ if (!report || typeof report !== 'object' || Array.isArray(report)) continue;
46
+ const reporter = boundedText(report.reporter, 128);
47
+ const eventRef = optionalRef(report.eventRef);
48
+ const occurredAt = optionalTimestamp(report.occurredAt);
49
+ const claimTokens = extractChecksumClaims(
50
+ Array.isArray(report.claimTokens) ? report.claimTokens.join(' ') : '',
51
+ );
52
+ if (reporter === undefined || eventRef === undefined || occurredAt === undefined || claimTokens.length === 0) continue;
53
+ const reporterRef = optionalRef(report.reporterRef);
54
+ reports.push(Object.freeze({ reporter, reporterRef, eventRef, occurredAt, claimTokens }));
55
+ }
56
+ return reports;
57
+ }
58
+
59
+ function assessOutboundClaimProvenance({ text, localClaims = [], externalReports = [] } = {}) {
60
+ const claims = extractChecksumClaims(text);
61
+ const local = new Set(extractChecksumClaims(Array.isArray(localClaims) ? localClaims.join(' ') : ''));
62
+ const reports = normalizedExternalReports(externalReports);
63
+ const localMatches = [];
64
+ const externalMatches = [];
65
+ const unattributed = [];
66
+
67
+ for (const value of claims) {
68
+ if (local.has(value)) {
69
+ localMatches.push(value);
70
+ continue;
71
+ }
72
+ const report = reports.find((candidate) => candidate.claimTokens.includes(value));
73
+ if (report === undefined) {
74
+ unattributed.push(value);
75
+ continue;
76
+ }
77
+ const external = {
78
+ value,
79
+ reporter: report.reporter,
80
+ ...(report.reporterRef !== undefined ? { reporterRef: report.reporterRef } : {}),
81
+ eventRef: report.eventRef,
82
+ occurredAt: report.occurredAt,
83
+ };
84
+ externalMatches.push(Object.freeze(external));
85
+ }
86
+
87
+ return Object.freeze({
88
+ local: Object.freeze(localMatches),
89
+ external: Object.freeze(externalMatches),
90
+ unattributed: Object.freeze(unattributed),
91
+ });
92
+ }
93
+
94
+ function normalizedToolArgs(input) {
95
+ if (input && typeof input === 'object' && !Array.isArray(input)) return input;
96
+ if (typeof input !== 'string') return undefined;
97
+ try {
98
+ const parsed = JSON.parse(input);
99
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : undefined;
100
+ } catch {
101
+ return undefined;
102
+ }
103
+ }
104
+
105
+ function provenanceAdvisoryForToolCall({ toolName, toolArgs, localClaims, externalReports } = {}) {
106
+ if (!TELEGRAM_MESSAGE_TOOL_RE.test(String(toolName ?? ''))) return null;
107
+ const args = normalizedToolArgs(toolArgs);
108
+ if (args === undefined || typeof args.text !== 'string') return null;
109
+ const assessment = assessOutboundClaimProvenance({
110
+ text: args.text,
111
+ localClaims,
112
+ externalReports,
113
+ });
114
+ if (assessment.external.length === 0 && assessment.unattributed.length === 0) return null;
115
+ return Object.freeze({ ...assessment, blocked: false });
116
+ }
117
+
118
+ module.exports = {
119
+ assessOutboundClaimProvenance,
120
+ extractChecksumClaims,
121
+ provenanceAdvisoryForToolCall,
122
+ };
package/blun.mjs CHANGED
@@ -21463,7 +21463,8 @@ var { rollbackPersonalityChoice, setPersonalityEnabledAtomic } = createRequire(i
21463
21463
  var { projectSoulText } = createRequire(import.meta.url)("./bin/soul-organization-policy.cjs");
21464
21464
  var { soulFileInstruction } = createRequire(import.meta.url)("./bin/soul-preservation-policy.cjs");
21465
21465
  var { readProfilePersona, resolveSoulFile } = createRequire(import.meta.url)("./bin/profile-identity-resolution.cjs");
21466
- var { advanceActionEvidenceReceipt, assertActionCheckpointEvidenceBasis, assertActionCheckpointRevision, emptyActionEvidenceReceipt, evidenceProducerRef, normalizeActionCheckpoint, projectActionCheckpoint } = createRequire(import.meta.url)("./bin/cognitive-action-checkpoint.cjs");
21466
+ var { advanceActionEvidenceReceipt, assertActionCheckpointEvidenceBasis, assertActionCheckpointRevision, emptyActionEvidenceReceipt, evidenceProducerRef, externalReportOriginFromRuntimeSource, externalReportSourcesFromOrigin, normalizeActionCheckpoint, projectActionCheckpoint } = createRequire(import.meta.url)("./bin/cognitive-action-checkpoint.cjs");
21467
+ var { extractChecksumClaims, provenanceAdvisoryForToolCall } = createRequire(import.meta.url)("./bin/outbound-claim-provenance.cjs");
21467
21468
  var { evaluateGoalCompletionEvidence } = createRequire(import.meta.url)("./bin/goal-completion-evidence-policy.cjs");
21468
21469
  async function prepareSystemPromptContext(kaos, brandHome, options) {
21469
21470
  const additionalDirs = normalizeAdditionalDirs(options?.additionalDirs ?? []);
@@ -230281,9 +230282,11 @@ var init_goal$1 = __esmMin((() => {
230281
230282
  if (input.actionCheckpoint !== void 0) {
230282
230283
  assertActionCheckpointRevision(undefined, input.actionCheckpoint);
230283
230284
  const runtimeEvidence = this.agent.turn.actionEvidenceReceiptForCurrentTurn();
230284
- assertActionCheckpointEvidenceBasis(undefined, input.actionCheckpoint, runtimeEvidence);
230285
+ const runtimeExternalReports = this.agent.turn.externalReportSourcesForCurrentTurn();
230286
+ assertActionCheckpointEvidenceBasis(undefined, input.actionCheckpoint, runtimeEvidence, runtimeExternalReports);
230285
230287
  state.actionCheckpoint = normalizeActionCheckpoint(input.actionCheckpoint, {
230286
- runtimeEvidence
230288
+ runtimeEvidence,
230289
+ runtimeExternalReports
230287
230290
  });
230288
230291
  }
230289
230292
  this.persistState(state);
@@ -230365,9 +230368,12 @@ var init_goal$1 = __esmMin((() => {
230365
230368
  if (state.status !== "active") throw new BlunError(ErrorCodes.GOAL_STATUS_INVALID, `Cannot checkpoint a goal in status "${state.status}"`);
230366
230369
  assertActionCheckpointRevision(state.actionCheckpoint, input);
230367
230370
  const runtimeEvidence = this.agent.turn.actionEvidenceReceiptForCurrentTurn();
230368
- assertActionCheckpointEvidenceBasis(state.actionCheckpoint, input, runtimeEvidence);
230371
+ const runtimeExternalReports = this.agent.turn.externalReportSourcesForCurrentTurn();
230372
+ assertActionCheckpointEvidenceBasis(state.actionCheckpoint, input, runtimeEvidence, runtimeExternalReports);
230369
230373
  state.actionCheckpoint = normalizeActionCheckpoint(input, {
230370
- runtimeEvidence
230374
+ runtimeEvidence,
230375
+ runtimeExternalReports,
230376
+ previousCheckpoint: state.actionCheckpoint
230371
230377
  });
230372
230378
  this.persistState(state, { change: { kind: "progress", actor } });
230373
230379
  this.appendGoalUpdate({ actionCheckpoint: state.actionCheckpoint, actor });
@@ -245792,6 +245798,13 @@ var init_events$1 = __esmMin((() => {
245792
245798
  phase: _enum(["orient", "plan", "act", "verify", "learn", "wait"]),
245793
245799
  evidenceBasis: _enum(["runtime_tool", "user_statement", "external_report", "carried_forward", "legacy_unknown"]),
245794
245800
  epistemicState: _enum(["verified", "credible_unverified", "hypothesis", "uncertain_memory", "stale", "unknown", "legacy_unknown"]),
245801
+ externalReportOrigin: object({
245802
+ source: _enum(["telegram"]),
245803
+ reporter: string(),
245804
+ reporterRef: string().regex(/^[a-f0-9]{16}$/u),
245805
+ eventRef: string().regex(/^[a-f0-9]{16}$/u),
245806
+ occurredAt: string()
245807
+ }).strict().optional(),
245795
245808
  lastVerified: string(),
245796
245809
  nextAction: string(),
245797
245810
  expectedEvidence: string(),
@@ -260311,6 +260324,7 @@ var create_goal_default;
260311
260324
  var init_create_goal$1 = __esmMin((() => {
260312
260325
  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, expected evidence, and exact next trigger 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";
260313
260326
  create_goal_default += "\nBind each selected action to the projected durable facts or assumptions it relies on by copying their explicit refs into `decisionBasis`. A stale or unknown decision basis requires replanning before execution.\n";
260327
+ create_goal_default += "\nWhen the checkpoint rests on a forwarded Telegram report, use `external_report` with `credible_unverified` and select the exact visible channel event in `externalReportSource` with its `source`, `chat_id` as `chatId`, and `message_id` as `messageId`. The runtime binds the reporter and event reference; never invent them.\n";
260314
260328
  }));
260315
260329
  //#endregion
260316
260330
  //#region ../../packages/agent-core/src/tools/builtin/goal/serialize.ts
@@ -260348,6 +260362,11 @@ function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFra
260348
260362
  phase: _enum(["orient", "plan", "act", "verify", "learn", "wait"]),
260349
260363
  evidenceBasis: _enum(["runtime_tool", "user_statement", "external_report", "carried_forward"]),
260350
260364
  epistemicState: _enum(["verified", "credible_unverified", "hypothesis", "uncertain_memory", "stale", "unknown"]),
260365
+ externalReportSource: object({
260366
+ source: _enum(["telegram"]),
260367
+ chatId: string().min(1).max(64),
260368
+ messageId: string().min(1).max(64)
260369
+ }).strict().optional(),
260351
260370
  lastVerified: string().min(1).max(512),
260352
260371
  nextAction: string().min(1).max(512),
260353
260372
  expectedEvidence: string().min(1).max(512),
@@ -261714,6 +261733,12 @@ function explicitToolResultEvidenceScopes(result) {
261714
261733
  function abandonedToolResultOutput(ended) {
261715
261734
  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.`;
261716
261735
  }
261736
+ function durablePromptOrigin(origin) {
261737
+ if (!origin || typeof origin !== "object" || !Object.hasOwn(origin, "externalReportSources")) return origin;
261738
+ const { externalReportSources, ...durableOrigin } = origin;
261739
+ void externalReportSources;
261740
+ return durableOrigin;
261741
+ }
261717
261742
  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, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildCognitiveWorkFocus, buildAttentionQueueItem, 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;
261718
261743
  var init_turn = __esmMin((() => {
261719
261744
  init_dist$4();
@@ -261803,6 +261828,8 @@ var init_turn = __esmMin((() => {
261803
261828
  cognitiveToolPolicyByCall = /* @__PURE__ */ new Map();
261804
261829
  cognitiveToolBatchesByTurn = /* @__PURE__ */ new Map();
261805
261830
  cognitiveActionEvidenceByTurn = /* @__PURE__ */ new Map();
261831
+ cognitiveExternalReportsByTurn = /* @__PURE__ */ new Map();
261832
+ cognitiveLocalClaimsByTurn = /* @__PURE__ */ new Map();
261806
261833
  constructor(agent) {
261807
261834
  this.agent = agent;
261808
261835
  }
@@ -261882,6 +261909,70 @@ var init_turn = __esmMin((() => {
261882
261909
  const turnId = this.currentId;
261883
261910
  return this.cognitiveActionEvidenceByTurn.get(turnId) ?? emptyActionEvidenceReceipt(turnId, this.agent.evidenceProducerRef);
261884
261911
  }
261912
+ recordExternalReportSources(turnId, origin) {
261913
+ const incoming = externalReportSourcesFromOrigin(origin);
261914
+ if (incoming.length === 0) return;
261915
+ const current = this.cognitiveExternalReportsByTurn.get(turnId) ?? [];
261916
+ const merged = [...current];
261917
+ const seen = new Set(current.map((source) => `${source.source}\0${source.chatId}\0${source.messageId}`));
261918
+ for (const source of incoming) {
261919
+ const key = `${source.source}\0${source.chatId}\0${source.messageId}`;
261920
+ if (seen.has(key)) continue;
261921
+ seen.add(key);
261922
+ merged.push(source);
261923
+ }
261924
+ this.cognitiveExternalReportsByTurn.set(turnId, Object.freeze(merged.slice(-32)));
261925
+ }
261926
+ externalReportSourcesForCurrentTurn() {
261927
+ return this.cognitiveExternalReportsByTurn.get(this.currentId) ?? Object.freeze([]);
261928
+ }
261929
+ recordLocalClaimTokens(turnId, text) {
261930
+ const incoming = extractChecksumClaims(text);
261931
+ if (incoming.length === 0) return;
261932
+ const current = this.cognitiveLocalClaimsByTurn.get(turnId) ?? [];
261933
+ const merged = [...current];
261934
+ const seen = new Set(current);
261935
+ for (const claim of incoming) {
261936
+ if (seen.has(claim)) continue;
261937
+ seen.add(claim);
261938
+ merged.push(claim);
261939
+ }
261940
+ this.cognitiveLocalClaimsByTurn.set(turnId, Object.freeze(merged.slice(-64)));
261941
+ }
261942
+ externalClaimReportsForCurrentTurn() {
261943
+ return this.externalReportSourcesForCurrentTurn().map((source) => ({
261944
+ ...externalReportOriginFromRuntimeSource(source),
261945
+ claimTokens: source.claimTokens ?? []
261946
+ }));
261947
+ }
261948
+ emitOutboundClaimProvenanceAdvisory(turnId, event) {
261949
+ try {
261950
+ const provenanceAdvisory = provenanceAdvisoryForToolCall({
261951
+ toolName: event.name,
261952
+ toolArgs: event.args,
261953
+ localClaims: this.cognitiveLocalClaimsByTurn.get(turnId) ?? [],
261954
+ externalReports: this.externalClaimReportsForCurrentTurn()
261955
+ });
261956
+ if (provenanceAdvisory === null) return;
261957
+ const external = provenanceAdvisory.external.map((entry) => `${entry.value} (${entry.reporter}; ${entry.eventRef}; ${entry.occurredAt})`).join(", ") || "-";
261958
+ const unattributed = provenanceAdvisory.unattributed.join(", ") || "-";
261959
+ this.agent.emitEvent({
261960
+ type: "warning",
261961
+ code: "OUTBOUND_CLAIM_PROVENANCE",
261962
+ message: uiText("sessionEvent.provenance.advisory", { external, unattributed }),
261963
+ blocked: false,
261964
+ details: {
261965
+ blocked: false,
261966
+ external: provenanceAdvisory.external,
261967
+ unattributed: provenanceAdvisory.unattributed
261968
+ }
261969
+ });
261970
+ } catch (error) {
261971
+ this.agent.telemetry.track("outbound_claim_provenance_error", {
261972
+ error_type: error?.code ?? error?.name ?? "Error"
261973
+ });
261974
+ }
261975
+ }
261885
261976
  projectCognitiveState(turnId, input) {
261886
261977
  try {
261887
261978
  const focusScopes = cognitiveFocusScopesForTurn(input);
@@ -261936,7 +262027,7 @@ var init_turn = __esmMin((() => {
261936
262027
  this.agent.records.logRecord({
261937
262028
  type: "turn.prompt",
261938
262029
  input,
261939
- origin
262030
+ origin: durablePromptOrigin(origin)
261940
262031
  });
261941
262032
  const buffered = this.agent.fullCompaction.isCompacting;
261942
262033
  const turnId = this.launch(input, origin);
@@ -261955,7 +262046,7 @@ var init_turn = __esmMin((() => {
261955
262046
  this.agent.records.logRecord({
261956
262047
  type: "turn.steer",
261957
262048
  input,
261958
- origin
262049
+ origin: durablePromptOrigin(origin)
261959
262050
  });
261960
262051
  if (this.activeTurn || this.agent.fullCompaction.isCompacting) {
261961
262052
  this.bufferSteer(input, origin);
@@ -261978,7 +262069,7 @@ var init_turn = __esmMin((() => {
261978
262069
  this.agent.records.logRecord({
261979
262070
  type: "turn.steer",
261980
262071
  input,
261981
- origin
262072
+ origin: durablePromptOrigin(origin)
261982
262073
  });
261983
262074
  this.bufferSteer(input, origin, this.currentId);
261984
262075
  return {
@@ -262110,6 +262201,9 @@ var init_turn = __esmMin((() => {
262110
262201
  return this.flushSteerBuffer(turnId, snapshot.throughSequence);
262111
262202
  }
262112
262203
  bufferSteer(input, origin, targetTurnId) {
262204
+ const active = this.activeTurn;
262205
+ const reportTurnId = targetTurnId ?? (active !== null && active !== "resuming" ? active.turnId : void 0);
262206
+ if (reportTurnId !== void 0) this.recordExternalReportSources(reportTurnId, origin);
262113
262207
  this.steerBuffer.push({
262114
262208
  sequence: this.nextSteerSequence,
262115
262209
  input,
@@ -262127,7 +262221,7 @@ var init_turn = __esmMin((() => {
262127
262221
  remaining.push(steer);
262128
262222
  continue;
262129
262223
  }
262130
- this.agent.context.appendUserMessage(steer.input, steer.origin);
262224
+ this.agent.context.appendUserMessage(steer.input, durablePromptOrigin(steer.origin));
262131
262225
  flushed = true;
262132
262226
  }
262133
262227
  this.steerBuffer = remaining;
@@ -262280,6 +262374,8 @@ var init_turn = __esmMin((() => {
262280
262374
  const telemetryMode = this.telemetryMode();
262281
262375
  this.telemetryModeByTurn.set(turnId, telemetryMode);
262282
262376
  this.currentStepByTurn.set(turnId, 0);
262377
+ this.recordExternalReportSources(turnId, origin);
262378
+ const persistedOrigin = durablePromptOrigin(origin);
262283
262379
  this.agent.telemetry.track("turn_started", {
262284
262380
  mode: telemetryMode,
262285
262381
  ...this.requestProviderProps()
@@ -262290,9 +262386,9 @@ var init_turn = __esmMin((() => {
262290
262386
  this.agent.emitEvent({
262291
262387
  type: "turn.started",
262292
262388
  turnId,
262293
- origin
262389
+ origin: persistedOrigin
262294
262390
  });
262295
- this.agent.context.appendUserMessage(input, origin);
262391
+ this.agent.context.appendUserMessage(input, persistedOrigin);
262296
262392
  this.recordCognitiveStage("startTurn", { turnId, originKind: origin.kind });
262297
262393
  const startedAt = Date.now();
262298
262394
  let ended;
@@ -262300,7 +262396,7 @@ var init_turn = __esmMin((() => {
262300
262396
  let completedStopReason;
262301
262397
  let errorEvent;
262302
262398
  try {
262303
- const promptHookEnded = await this.applyUserPromptHook(turnId, input, origin, signal, startedAt);
262399
+ const promptHookEnded = await this.applyUserPromptHook(turnId, input, persistedOrigin, signal, startedAt);
262304
262400
  this.recordCognitiveStage("recordRightsCheck", {
262305
262401
  turnId,
262306
262402
  decision: origin.kind !== "user" ? "not_applicable" : promptHookEnded?.blocked === true ? "blocked" : "passed",
@@ -262310,7 +262406,7 @@ var init_turn = __esmMin((() => {
262310
262406
  ended = promptHookEnded.event;
262311
262407
  blockedByUserPromptHook = promptHookEnded.blocked;
262312
262408
  } else {
262313
- const stopReason = await this.runStepLoop(turnId, signal, input, origin);
262409
+ const stopReason = await this.runStepLoop(turnId, signal, input, persistedOrigin);
262314
262410
  completedStopReason = stopReason;
262315
262411
  ended = {
262316
262412
  type: "turn.ended",
@@ -262389,6 +262485,8 @@ var init_turn = __esmMin((() => {
262389
262485
  this.currentStepByTurn.delete(turnId);
262390
262486
  this.interruptedTelemetryTurnIds.delete(turnId);
262391
262487
  this.cognitiveActionEvidenceByTurn.delete(turnId);
262488
+ this.cognitiveExternalReportsByTurn.delete(turnId);
262489
+ this.cognitiveLocalClaimsByTurn.delete(turnId);
262392
262490
  this.stepFailureByTurn.delete(turnId);
262393
262491
  await this.agent.records.flush();
262394
262492
  return {
@@ -262779,6 +262877,7 @@ var init_turn = __esmMin((() => {
262779
262877
  if (event.type === "tool.call") {
262780
262878
  const dupType = this.trackDuplicateToolCall(turnId, event.step, event.name, event.args);
262781
262879
  this.toolCallDupType.set(event.toolCallId, dupType === "cross_step" ? "cross_step" : "normal");
262880
+ this.emitOutboundClaimProvenanceAdvisory(turnId, event);
262782
262881
  this.toolCallStartedAt.set(event.toolCallId, {
262783
262882
  name: event.name,
262784
262883
  args: event.args,
@@ -262794,6 +262893,7 @@ var init_turn = __esmMin((() => {
262794
262893
  if (event.type === "tool.result") {
262795
262894
  const started = this.toolCallStartedAt.get(event.toolCallId);
262796
262895
  if (started === void 0) return;
262896
+ this.recordLocalClaimTokens(turnId, toolResultText(event.result));
262797
262897
  rememberDeferredToolAfterNotFound(this.loadedToolNames, started.name, event.result);
262798
262898
  this.toolCallStartedAt.delete(event.toolCallId);
262799
262899
  const dupType = this.toolCallDupType.get(event.toolCallId) ?? "normal";
@@ -262922,7 +263022,7 @@ var init_update_goal$1 = __esmMin((() => {
262922
263022
  update_goal_default = "Update the current autonomous goal. Set `status` only for a lifecycle change. After a coherent work slice, save `actionCheckpoint` with a monotone revision, the last verified result, exact next action, expected evidence, exact `nextTrigger`, and an explicit evidence basis. Persist the exact `nextTrigger` that releases `nextAction`: use `immediate` outside the `wait` phase; while waiting, name the external event, time, dependency, or user decision instead of pretending work can continue. A `time` trigger must include the exact ISO timestamp in `dueAt`; no other trigger kind may include `dueAt`. Use `runtime_tool` only when a successful tool in this turn measured the result; use `user_statement` for a direct user assertion, `external_report` for a report not independently measured here, and `carried_forward` only when the last verified text is unchanged. Classify knowledge as `verified`, `credible_unverified`, `hypothesis`, `uncertain_memory`, `stale`, or `unknown`; never present a weaker state as verified, and preserve the state on carry-forward. Start at revision 1 and increment the currently projected revision by exactly one; stale writers fail closed. This is durable progress state, not permission, and should change only when the facts change. A checkpoint-only call keeps the goal active.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is fully satisfied, all files are written, all tests pass, and any stated validation has passed. When the goal has a completion criterion, first save a `verify` checkpoint with `runtime_tool`, `verified`, and a successful runtime evidence receipt.\n- `blocked` — a genuine external condition or required user decision prevents progress.\n- `paused` — set the goal aside for now.\n\nDo not mark complete after a plan or partial result. If useful work remains, checkpoint it and continue. Do not ask for permission merely to execute an already authorized checkpoint; ask only at a real rights boundary or missing user decision.\n";
262923
263023
  update_goal_default += "\nBefore completing a goal with a criterion, bind the verified claim to the exact successful current-turn verification call in `verificationProof`, including its `toolCallId`. A write, edit, copy, deploy, or other action is not proof that the changed behavior works, even when it shares a mixed-use tool such as `Bash` with tests. Use `subject: result` for a result, report, measurement, or download. Use `subject: verifier` only when the new or changed test, gate, harness, or detector itself is the completion subject; then bind `sharpnessProof` to a separate successful current-turn counterexample or mutation call. Do not require a red probe for a normal report or measurement.\n";
262924
263024
  update_goal_default += "\nCopy the active goal's exact `completionCriterion` into `verificationProof.criterion`. The runtime stores only its bounded reference and refuses completion if the proof belongs to a different or superseded completion criterion.\n";
262925
- update_goal_default += "\nThe runtime binds fresh verification automatically to the session and agent that produced the successful tool result. Do not invent or copy a producer reference. Preserve forwarded measurements as `external_report` with `credible_unverified` until this agent measures them independently; forwarding is allowed, relabelling them as local verification is not.\n";
263025
+ update_goal_default += "\nThe runtime binds fresh verification automatically to the session and agent that produced the successful tool result. Do not invent or copy a producer reference. Preserve forwarded measurements as `external_report` with `credible_unverified` until this agent measures them independently; forwarding is allowed, relabelling them as local verification is not. For a fresh Telegram report, copy the exact visible channel `source`, `chat_id` as `chatId`, and `message_id` as `messageId` into `externalReportSource`. The runtime, not the model, binds the reporter and event reference. A `carried_forward` checkpoint retains that origin automatically.\n";
262926
263026
  update_goal_default += "\nSet the proof `kind` to the exact capability of that call: `inspection` reads or searches, `integrity` compares bytes or hashes, `syntax` parses or type-checks, and `test` runs assertions. None of these alone proves a stronger kind. Use `reachability` only for a successful runtime probe that actually invokes the changed path and emits the exact marker `BLUN_EVIDENCE_KIND=reachability` after its assertions; loading a module without reaching the changed path is not reachability.\n";
262927
263027
  update_goal_default += "\nBind each proof `scope` to the exact target measured by that successful call, never to a free-text claim or intended file. Read and search tools derive scope from their target arguments. For shell or command tools, include the same safe token `BLUN_EVIDENCE_SCOPE=<scope>` in the launched non-mutating verification command and emit it only after that exact target succeeds; the runtime requires both sides.\n";
262928
263028
  update_goal_default += "\nFor a non-trivial or unfamiliar problem, preserve `problemFrame` with the success criterion, missing knowledge, bounded candidate actions, selected action and reason, support choice, risk, and reversibility. The selected action must match one candidate. Bind each selected action to the projected durable facts or assumptions it relies on by copying their explicit refs into `decisionBasis`. A stale or unknown decision basis requires replanning before execution. Problem framing is descriptive state and never grants permission.\n";
@@ -265674,9 +265774,9 @@ var init_agent = __esmMin((() => {
265674
265774
  get rpcMethods() {
265675
265775
  return {
265676
265776
  prompt: (payload) => {
265677
- this.turn.promptWithAcceptance(payload.input);
265777
+ this.turn.promptWithAcceptance(payload.input, payload.origin ?? USER_PROMPT_ORIGIN);
265678
265778
  },
265679
- promptAccepted: (payload) => this.turn.promptWithAcceptance(payload.input),
265779
+ promptAccepted: (payload) => this.turn.promptWithAcceptance(payload.input, payload.origin ?? USER_PROMPT_ORIGIN),
265680
265780
  runShellCommand: (payload) => this.tools.runShellCommand(payload.command, payload.commandId),
265681
265781
  cancelShellCommand: (payload) => this.tools.cancelShellCommand(payload.commandId),
265682
265782
  steer: (payload) => {
@@ -326630,17 +326730,20 @@ var Session = class {
326630
326730
  async prompt(input) {
326631
326731
  await this.promptAccepted(input);
326632
326732
  }
326633
- async promptAccepted(input) {
326733
+ async promptAccepted(input, origin = USER_PROMPT_ORIGIN) {
326634
326734
  this.ensureOpen();
326635
326735
  const normalized = normalizePromptInput(input);
326736
+ const normalizedOrigin = origin && typeof origin === "object" ? origin : USER_PROMPT_ORIGIN;
326636
326737
  const hasPromptAccepted = this.rpc.promptAccepted !== void 0;
326637
326738
  return this.trackUserInputAcceptance(normalized, hasPromptAccepted ? () => this.rpc.promptAccepted({
326638
326739
  sessionId: this.id,
326639
- input: normalized
326740
+ input: normalized,
326741
+ origin: normalizedOrigin
326640
326742
  }) : async () => {
326641
326743
  await this.rpc.prompt({
326642
326744
  sessionId: this.id,
326643
- input: normalized
326745
+ input: normalized,
326746
+ origin: normalizedOrigin
326644
326747
  });
326645
326748
  return {
326646
326749
  accepted: true,
@@ -327909,7 +328012,8 @@ var SDKRpcClientBase = class {
327909
328012
  await rpc.prompt({
327910
328013
  sessionId: input.sessionId,
327911
328014
  agentId,
327912
- input: input.input
328015
+ input: input.input,
328016
+ origin: input.origin
327913
328017
  });
327914
328018
  return {
327915
328019
  accepted: true,
@@ -327920,7 +328024,8 @@ var SDKRpcClientBase = class {
327920
328024
  return rpc.promptAccepted({
327921
328025
  sessionId: input.sessionId,
327922
328026
  agentId,
327923
- input: input.input
328027
+ input: input.input,
328028
+ origin: input.origin
327924
328029
  });
327925
328030
  }
327926
328031
  async runShellCommand(input) {
@@ -419162,12 +419267,14 @@ const CONTEXT_TRUNCATED_MARKER = "\n[Telegram-Kontext gekuerzt]";
419162
419267
  function createChannelPreambleState() {
419163
419268
  return {
419164
419269
  sent: false,
419165
- bufferedByChat: /* @__PURE__ */ new Map()
419270
+ bufferedByChat: /* @__PURE__ */ new Map(),
419271
+ reportSourcesByChat: /* @__PURE__ */ new Map()
419166
419272
  };
419167
419273
  }
419168
419274
  function resetChannelPreambleState(state) {
419169
419275
  state.sent = false;
419170
419276
  state.bufferedByChat?.clear();
419277
+ state.reportSourcesByChat?.clear();
419171
419278
  }
419172
419279
  /** Structured metadata is authoritative; old queue envelopes use the tag note. */
419173
419280
  function channelMessageAddressed(envelope) {
@@ -419177,21 +419284,35 @@ function channelMessageAddressed(envelope) {
419177
419284
  if (addressed === "semantic") return true;
419178
419285
  return !envelope.tag.includes("NUR MITLESEN");
419179
419286
  }
419180
- function bufferContext(state, chatId, tag) {
419287
+ function bufferContext(state, chatId, tag, reportSource) {
419181
419288
  const buffers = state.bufferedByChat ?? /* @__PURE__ */ new Map();
419182
419289
  state.bufferedByChat = buffers;
419290
+ const reportBuffers = state.reportSourcesByChat ?? /* @__PURE__ */ new Map();
419291
+ state.reportSourcesByChat = reportBuffers;
419183
419292
  const messages = buffers.get(chatId) ?? [];
419293
+ const reports = reportBuffers.get(chatId) ?? [];
419184
419294
  const projectedTag = projectUnaddressedTelegramContext(tag);
419185
419295
  const boundedTag = projectedTag.length <= MAX_BUFFERED_CONTEXT_CHARS ? projectedTag : `${projectedTag.slice(0, MAX_BUFFERED_CONTEXT_CHARS - 28)}${CONTEXT_TRUNCATED_MARKER}`;
419186
419296
  messages.push(boundedTag);
419297
+ reports.push(reportSource);
419187
419298
  let chars = messages.reduce((sum, message) => sum + message.length, 0);
419188
- while (messages.length > MAX_BUFFERED_CONTEXT_MESSAGES || chars > MAX_BUFFERED_CONTEXT_CHARS) chars -= messages.shift()?.length ?? 0;
419299
+ while (messages.length > MAX_BUFFERED_CONTEXT_MESSAGES || chars > MAX_BUFFERED_CONTEXT_CHARS) {
419300
+ chars -= messages.shift()?.length ?? 0;
419301
+ reports.shift();
419302
+ }
419189
419303
  buffers.set(chatId, messages);
419304
+ reportBuffers.set(chatId, reports);
419190
419305
  }
419191
419306
  /** Muted origin prefix for the transcript line, e.g. "Telegram · User". */
419192
419307
  function channelOrigin(envelope) {
419193
419308
  return `Telegram · ${envelope.meta.user ?? envelope.meta.chat_id}${envelope.meta["priority"] === "urgent" ? " · Dringend" : ""}`;
419194
419309
  }
419310
+ function channelPromptOrigin(channelReportSources) {
419311
+ return {
419312
+ kind: "user",
419313
+ externalReportSources: channelReportSources
419314
+ };
419315
+ }
419195
419316
  const TELEGRAM_REMOTE_COMMANDS = Object.freeze(["loop", "goal", "idea", "chancenradar", "curiosity", "scout", "reload", "memory", "befehle"]);
419196
419317
  function telegramRemoteCommand(text) {
419197
419318
  const trimmed = text.trim();
@@ -419213,24 +419334,36 @@ function telegramRemoteCommand(text) {
419213
419334
  function injectChannelEnvelope(host, envelope, preamble) {
419214
419335
  const origin = channelOrigin(envelope);
419215
419336
  const contextOnly = !channelMessageAddressed(envelope);
419337
+ const reportSource = {
419338
+ source: "telegram",
419339
+ chatId: envelope.meta.chat_id,
419340
+ messageId: envelope.meta.message_id,
419341
+ reporter: envelope.meta.user,
419342
+ reporterId: envelope.meta.user_id,
419343
+ occurredAt: envelope.meta.ts,
419344
+ claimTokens: extractChecksumClaims(envelope.text)
419345
+ };
419216
419346
  if (contextOnly) {
419217
- bufferContext(preamble, envelope.meta.chat_id, envelope.tag);
419347
+ bufferContext(preamble, envelope.meta.chat_id, envelope.tag, reportSource);
419218
419348
  host.displayContext?.(envelope.text, origin);
419219
419349
  return "buffered";
419220
419350
  }
419221
419351
  const modelParts = [...preamble.bufferedByChat?.get(envelope.meta.chat_id) ?? [], envelope.tag];
419352
+ const channelReportSources = [...preamble.reportSourcesByChat?.get(envelope.meta.chat_id) ?? [], reportSource];
419222
419353
  if (!preamble.sent && envelope.preamble !== void 0 && envelope.preamble.length > 0) {
419223
419354
  modelParts.unshift(envelope.preamble);
419224
419355
  preamble.sent = true;
419225
419356
  }
419226
419357
  const modelInput = modelParts.join("\n\n");
419227
419358
  if (!host.canDeliver() || host.isBusy()) {
419228
- host.enqueue(modelInput, envelope.text, origin, contextOnly);
419359
+ host.enqueue(modelInput, envelope.text, origin, contextOnly, channelReportSources);
419229
419360
  preamble.bufferedByChat?.delete(envelope.meta.chat_id);
419361
+ preamble.reportSourcesByChat?.delete(envelope.meta.chat_id);
419230
419362
  return "queued";
419231
419363
  }
419232
- host.deliverNow(modelInput, envelope.text, origin, contextOnly);
419364
+ host.deliverNow(modelInput, envelope.text, origin, contextOnly, channelReportSources);
419233
419365
  preamble.bufferedByChat?.delete(envelope.meta.chat_id);
419366
+ preamble.reportSourcesByChat?.delete(envelope.meta.chat_id);
419234
419367
  return "delivered";
419235
419368
  }
419236
419369
  /** Parse one queue line defensively — a malformed line must never crash the TUI. */
@@ -506333,6 +506466,7 @@ registerUiCatalogFragment({
506333
506466
  "sessionEvent.goalQueue.blockedTitle": "Goal blocked.",
506334
506467
  "sessionEvent.goalQueue.blockedDetail": "The next queued goal will start only after this goal is complete.",
506335
506468
  "sessionEvent.warning": "Warning: {message}",
506469
+ "sessionEvent.provenance.advisory": "Source check before sending; the message was not blocked. Forwarded report: {external}. Not found in this turn's tool output or a source event: {unattributed}. Forwarding is allowed, but do not present these values as your own measurement.",
506336
506470
  "sessionEvent.mcp.tool.one": "{count} tool",
506337
506471
  "sessionEvent.mcp.tool.other": "{count} tools",
506338
506472
  "sessionEvent.mcp.connected": "MCP server \"{name}\" connected · {tools} ({transport})",
@@ -506363,6 +506497,7 @@ registerUiCatalogFragment({
506363
506497
  "sessionEvent.goalQueue.blockedTitle": "Ziel blockiert.",
506364
506498
  "sessionEvent.goalQueue.blockedDetail": "Das nächste vorgemerkte Ziel startet erst, wenn dieses Ziel abgeschlossen ist.",
506365
506499
  "sessionEvent.warning": "Warnung: {message}",
506500
+ "sessionEvent.provenance.advisory": "Herkunftsprüfung vor dem Senden; die Nachricht wurde nicht blockiert. Weitergeleiteter Bericht: {external}. Weder in einer Werkzeugausgabe dieses Durchlaufs noch in einem Quellereignis gefunden: {unattributed}. Die Weitergabe ist erlaubt, diese Werte dürfen jedoch nicht als eigene Messung dargestellt werden.",
506366
506501
  "sessionEvent.mcp.tool.one": "{count} Tool",
506367
506502
  "sessionEvent.mcp.tool.other": "{count} Tools",
506368
506503
  "sessionEvent.mcp.connected": "MCP-Server „{name}“ verbunden · {tools} ({transport})",
@@ -506393,6 +506528,7 @@ registerUiCatalogFragment({
506393
506528
  "sessionEvent.goalQueue.blockedTitle": "Objetivo bloqueado.",
506394
506529
  "sessionEvent.goalQueue.blockedDetail": "El siguiente objetivo en cola no se iniciará hasta que este objetivo se complete.",
506395
506530
  "sessionEvent.warning": "Advertencia: {message}",
506531
+ "sessionEvent.provenance.advisory": "Comprobación de procedencia antes de enviar; el mensaje no se bloqueó. Informe reenviado: {external}. No se encontraron en la salida de las herramientas de este turno ni en un evento de origen: {unattributed}. Se permite reenviar estos valores, pero no presentarlos como mediciones propias.",
506396
506532
  "sessionEvent.mcp.tool.one": "{count} herramienta",
506397
506533
  "sessionEvent.mcp.tool.other": "{count} herramientas",
506398
506534
  "sessionEvent.mcp.connected": "Servidor MCP «{name}» conectado · {tools} ({transport})",
@@ -506423,6 +506559,7 @@ registerUiCatalogFragment({
506423
506559
  "sessionEvent.goalQueue.blockedTitle": "Objectif bloqué.",
506424
506560
  "sessionEvent.goalQueue.blockedDetail": "L’objectif suivant ne démarrera qu’une fois cet objectif terminé.",
506425
506561
  "sessionEvent.warning": "Avertissement : {message}",
506562
+ "sessionEvent.provenance.advisory": "Vérification de la provenance avant l’envoi ; le message n’a pas été bloqué. Rapport transmis : {external}. Valeurs introuvables dans la sortie des outils de ce tour et dans les événements source : {unattributed}. Leur transmission est autorisée, mais ne les présentez pas comme vos propres mesures.",
506426
506563
  "sessionEvent.mcp.tool.one": "{count} outil",
506427
506564
  "sessionEvent.mcp.tool.other": "{count} outils",
506428
506565
  "sessionEvent.mcp.connected": "Serveur MCP « {name} » connecté · {tools} ({transport})",
@@ -506453,6 +506590,7 @@ registerUiCatalogFragment({
506453
506590
  "sessionEvent.goalQueue.blockedTitle": "Målet är blockerat.",
506454
506591
  "sessionEvent.goalQueue.blockedDetail": "Nästa köade mål startar först när det här målet är slutfört.",
506455
506592
  "sessionEvent.warning": "Varning: {message}",
506593
+ "sessionEvent.provenance.advisory": "Ursprungskontroll före sändning; meddelandet blockerades inte. Vidarebefordrad rapport: {external}. Hittades varken i verktygsutdata från den här körningen eller i en källhändelse: {unattributed}. Värdena får vidarebefordras, men framställ dem inte som egna mätningar.",
506456
506594
  "sessionEvent.mcp.tool.one": "{count} verktyg",
506457
506595
  "sessionEvent.mcp.tool.other": "{count} verktyg",
506458
506596
  "sessionEvent.mcp.connected": "MCP-servern ”{name}” är ansluten · {tools} ({transport})",
@@ -506483,6 +506621,7 @@ registerUiCatalogFragment({
506483
506621
  "sessionEvent.goalQueue.blockedTitle": "Cíl je blokován.",
506484
506622
  "sessionEvent.goalQueue.blockedDetail": "Další cíl ve frontě se spustí pouze po dokončení tohoto cíle.",
506485
506623
  "sessionEvent.warning": "Upozornění: {message}",
506624
+ "sessionEvent.provenance.advisory": "Kontrola původu před odesláním; zpráva nebyla zablokována. Předaný report: {external}. Nenalezeno ve výstupu nástrojů tohoto kola ani ve zdrojové události: {unattributed}. Tyto hodnoty lze předat dál, ale neuvádějte je jako vlastní měření.",
506486
506625
  "sessionEvent.mcp.tool.one": "Nástroje: {count}",
506487
506626
  "sessionEvent.mcp.tool.other": "Nástroje: {count}",
506488
506627
  "sessionEvent.mcp.connected": "Server MCP \"{name}\" připojen · {tools} ({transport})",
@@ -517656,10 +517795,10 @@ var BlunTUI = class {
517656
517795
  injectChannelEnvelope({
517657
517796
  canDeliver: () => this.session !== void 0 && this.state.appState.model.trim().length > 0,
517658
517797
  isBusy: () => this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.deferUserMessages || this.streamingUI.hasActiveTurn() || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting,
517659
- deliverNow: (modelInput, displayText, origin, contextOnly) => {
517660
- this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, routedEnvelope.meta.chat_id, routedEnvelope.meta["image_path"], contextOnly, false, acknowledge, false, void 0, directEnvelope !== void 0, directFocus.resumeGranted);
517798
+ deliverNow: (modelInput, displayText, origin, contextOnly, channelReportSources) => {
517799
+ this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, routedEnvelope.meta.chat_id, routedEnvelope.meta["image_path"], contextOnly, false, acknowledge, false, void 0, directEnvelope !== void 0, directFocus.resumeGranted, channelReportSources);
517661
517800
  },
517662
- enqueue: (modelInput, displayText, origin, contextOnly) => {
517801
+ enqueue: (modelInput, displayText, origin, contextOnly, channelReportSources) => {
517663
517802
  const item = {
517664
517803
  text: modelInput,
517665
517804
  displayText,
@@ -517667,6 +517806,7 @@ var BlunTUI = class {
517667
517806
  agentId: this.harness.interactiveAgentId,
517668
517807
  mode: "channel",
517669
517808
  channelChatId: routedEnvelope.meta.chat_id,
517809
+ channelReportSources: channelReportSources,
517670
517810
  channelContextOnly: contextOnly,
517671
517811
  channelAcknowledge: acknowledge,
517672
517812
  ...urgentEnvelope !== void 0 ? { channelUrgent: true } : {},
@@ -517826,7 +517966,7 @@ var BlunTUI = class {
517826
517966
  this.failSessionRequest(uiText("blunTui.session.sendFailed", { error: formatErrorMessage$2(error) }));
517827
517967
  });
517828
517968
  }
517829
- sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false, acknowledge, channelAttention = false, queueKey, channelDirect = false, channelDirectResume = false) {
517969
+ sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false, acknowledge, channelAttention = false, queueKey, channelDirect = false, channelDirectResume = false, channelReportSources = []) {
517830
517970
  armPersonalMemoryRememberIntent(session.id, displayText, {
517831
517971
  permissionMode: this.state.appState.permissionMode,
517832
517972
  channel: true
@@ -517860,7 +518000,7 @@ var BlunTUI = class {
517860
518000
  type: "text",
517861
518001
  text: focusedModelInput
517862
518002
  }, imagePart] : focusedModelInput;
517863
- session.promptAccepted(promptInput).then((result) => {
518003
+ session.promptAccepted(promptInput, channelPromptOrigin(channelReportSources)).then((result) => {
517864
518004
  if (result.accepted) {
517865
518005
  acknowledge?.();
517866
518006
  return;
@@ -517873,6 +518013,7 @@ var BlunTUI = class {
517873
518013
  agentId: this.harness.interactiveAgentId,
517874
518014
  mode: "channel",
517875
518015
  channelChatId,
518016
+ channelReportSources: channelReportSources,
517876
518017
  channelContextOnly: contextOnly,
517877
518018
  channelTranscriptRendered: true,
517878
518019
  channelAcknowledge: acknowledge,
@@ -518236,7 +518377,7 @@ var BlunTUI = class {
518236
518377
  const activeSession = this.session ?? session;
518237
518378
  if (item.mode === "channel") {
518238
518379
  this.harness.withInteractiveAgent(item.agentId ?? "main", () => {
518239
- this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered, item.channelAcknowledge, item.channelAttention, item.queueKey, item.channelDirect, item.channelDirectResume);
518380
+ this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered, item.channelAcknowledge, item.channelAttention, item.queueKey, item.channelDirect, item.channelDirectResume, item.channelReportSources);
518240
518381
  });
518241
518382
  return;
518242
518383
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.454",
3
+ "version": "9.1.456",
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": {