@ouro.bot/cli 0.1.0-alpha.813 → 0.1.0-alpha.815
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/changelog.json +14 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/core.js +16 -12
- package/dist/heart/session-events.js +125 -61
- package/dist/heart/session-redaction-repair.js +12 -3
- package/dist/heart/session-stats.js +3 -2
- package/dist/mailbox-ui/assets/{index-J8zDwHmE.js → index-Cyv4mw3Y.js} +1 -1
- package/dist/mailbox-ui/index.html +1 -1
- package/dist/mind/context.js +31 -1
- package/dist/senses/sanctuary-interactive-control.js +160 -56
- package/dist/senses/shared-turn.js +18 -5
- package/dist/senses/telegram-effect-adapter.js +10 -2
- package/dist/senses/telegram.js +24 -21
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="color-scheme" content="dark" />
|
|
7
7
|
<title>Ouro Mailbox</title>
|
|
8
8
|
<meta name="description" content="The daemon-hosted shared orientation surface for agents alive on this machine." />
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-Cyv4mw3Y.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-CcN1XpQ9.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-Du_9G9WO.css">
|
|
12
12
|
</head>
|
package/dist/mind/context.js
CHANGED
|
@@ -393,7 +393,37 @@ function postTurnTrim(messages, usage, hooks) {
|
|
|
393
393
|
const currentIngressTimes = preTrimMessages.map(session_events_1.getIngressTime);
|
|
394
394
|
const currentIngressRelations = preTrimMessages.map(session_events_1.getIngressRelations);
|
|
395
395
|
const currentMessages = (0, session_events_1.sanitizeProviderMessages)(messages);
|
|
396
|
-
|
|
396
|
+
let tokenTrimmedMessages = trimMessages(currentMessages, maxTokens, contextMargin, usage?.input_tokens);
|
|
397
|
+
const estimatedTokens = (0, token_estimate_1.estimateTokensForMessages)(tokenTrimmedMessages);
|
|
398
|
+
if (estimatedTokens > maxTokens) {
|
|
399
|
+
const targetTokens = Math.floor(maxTokens * (1 - contextMargin / 100));
|
|
400
|
+
const lastUser = tokenTrimmedMessages.findLastIndex((message) => message.role === "user");
|
|
401
|
+
const lastAssistant = tokenTrimmedMessages.findLastIndex((message) => message.role === "assistant");
|
|
402
|
+
const dropped = new Set();
|
|
403
|
+
let remaining = estimatedTokens;
|
|
404
|
+
for (const block of buildTrimmableBlocks(tokenTrimmedMessages)) {
|
|
405
|
+
if (remaining <= targetTokens)
|
|
406
|
+
break;
|
|
407
|
+
if (block.indices.includes(lastUser) || lastAssistant > lastUser && block.indices.includes(lastAssistant))
|
|
408
|
+
continue;
|
|
409
|
+
for (const index of block.indices)
|
|
410
|
+
dropped.add(index);
|
|
411
|
+
remaining -= block.estimatedTokens;
|
|
412
|
+
}
|
|
413
|
+
tokenTrimmedMessages = remaining > maxTokens ? [] : tokenTrimmedMessages.filter((_message, index) => !dropped.has(index));
|
|
414
|
+
(0, runtime_1.emitNervesEvent)({
|
|
415
|
+
level: tokenTrimmedMessages.length === 0 ? "warn" : "info",
|
|
416
|
+
event: "mind.step_end",
|
|
417
|
+
component: "mind",
|
|
418
|
+
message: "bounded post-turn projection using canonical token estimates",
|
|
419
|
+
meta: {
|
|
420
|
+
maxTokens, targetTokens, estimated_before: estimatedTokens,
|
|
421
|
+
estimated_after: (0, token_estimate_1.estimateTokensForMessages)(tokenTrimmedMessages),
|
|
422
|
+
reported_input_tokens: usage?.input_tokens ?? null,
|
|
423
|
+
emptyProjection: tokenTrimmedMessages.length === 0,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
}
|
|
397
427
|
const trimmedMessages = compactIdleRestOnlyTurns(tokenTrimmedMessages);
|
|
398
428
|
messages.splice(0, messages.length, ...trimmedMessages);
|
|
399
429
|
return { currentMessages, trimmedMessages, currentIngressTimes, currentIngressRelations, maxTokens, contextMargin };
|
|
@@ -229,70 +229,174 @@ function createSanctuaryInteractiveControl(options) {
|
|
|
229
229
|
const socketPath = path.join(options.agentRoot, "state", "acceptance", "telegram-control.sock");
|
|
230
230
|
const runRequest = options.runRequest ?? (async (operation) => operation());
|
|
231
231
|
let server;
|
|
232
|
+
let endpoint;
|
|
233
|
+
let startPromise;
|
|
234
|
+
let stopPromise;
|
|
232
235
|
let updateId = 2_100_000_000;
|
|
236
|
+
const readEndpoint = () => (0, node_fs_1.lstatSync)(socketPath, { bigint: true, throwIfNoEntry: false });
|
|
237
|
+
// Socket mtime, unlike ctime, survives permission-only changes.
|
|
238
|
+
const matches = (observed, current) => current !== undefined && current.isSocket() && current.dev === observed.dev && current.ino === observed.ino
|
|
239
|
+
&& current.birthtimeNs === observed.birthtimeNs && current.mtimeNs === observed.mtimeNs;
|
|
240
|
+
const stopListener = async () => {
|
|
241
|
+
const active = server;
|
|
242
|
+
if (!active)
|
|
243
|
+
return;
|
|
244
|
+
if (active.listening) {
|
|
245
|
+
const current = readEndpoint();
|
|
246
|
+
// Native Server.close() also unlinks its pathname, so ownership must precede it.
|
|
247
|
+
if (current && (!endpoint || !matches(endpoint, current)))
|
|
248
|
+
throw new Error("Sanctuary interactive control socket ownership was replaced");
|
|
249
|
+
await new Promise((resolve, reject) => active.close((error) => error ? reject(error) : resolve()));
|
|
250
|
+
}
|
|
251
|
+
server = undefined;
|
|
252
|
+
endpoint = undefined;
|
|
253
|
+
};
|
|
233
254
|
return {
|
|
234
255
|
socketPath,
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
return;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
start() {
|
|
257
|
+
if (startPromise)
|
|
258
|
+
return startPromise;
|
|
259
|
+
const previousStop = stopPromise;
|
|
260
|
+
stopPromise = undefined;
|
|
261
|
+
const starting = (async () => {
|
|
262
|
+
if (previousStop)
|
|
263
|
+
await previousStop;
|
|
264
|
+
if (server) {
|
|
265
|
+
if (endpoint && matches(endpoint, readEndpoint()))
|
|
266
|
+
return;
|
|
267
|
+
await stopListener();
|
|
268
|
+
}
|
|
269
|
+
(0, node_fs_1.mkdirSync)(path.dirname(socketPath), { recursive: true, mode: 0o700 });
|
|
270
|
+
const previous = readEndpoint();
|
|
271
|
+
if (previous) {
|
|
272
|
+
if (!previous.isSocket())
|
|
273
|
+
throw new Error("Sanctuary interactive control endpoint is not a socket");
|
|
274
|
+
await new Promise((resolve, reject) => {
|
|
275
|
+
const socket = (0, node_net_1.createConnection)(socketPath);
|
|
276
|
+
const finish = (error) => { socket.destroy(); if (error)
|
|
277
|
+
reject(error);
|
|
278
|
+
else
|
|
279
|
+
resolve(); };
|
|
280
|
+
socket.setTimeout(1_000, () => finish(new Error("Sanctuary interactive control ownership probe timed out")));
|
|
281
|
+
socket.once("connect", () => finish(new Error("Sanctuary interactive control endpoint has another live listener")));
|
|
282
|
+
socket.once("error", (error) => finish(error.code === "ECONNREFUSED" ? undefined : error));
|
|
283
|
+
});
|
|
284
|
+
const current = readEndpoint();
|
|
285
|
+
if (!matches(previous, current) || current.ctimeNs !== previous.ctimeNs)
|
|
286
|
+
throw new Error("Sanctuary interactive control endpoint was replaced during the ownership probe");
|
|
287
|
+
(0, node_fs_1.unlinkSync)(socketPath);
|
|
288
|
+
}
|
|
289
|
+
server = (0, node_net_1.createServer)({ allowHalfOpen: true }, (connection) => {
|
|
290
|
+
let raw = "";
|
|
291
|
+
connection.setEncoding("utf8");
|
|
292
|
+
connection.on("error", () => undefined);
|
|
293
|
+
connection.on("data", (chunk) => { raw += chunk; if (Buffer.byteLength(raw) > MAX_CONTROL_REQUEST)
|
|
294
|
+
connection.destroy(); });
|
|
295
|
+
connection.on("end", () => {
|
|
296
|
+
void runRequest(async () => {
|
|
297
|
+
try {
|
|
298
|
+
(0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.sanctuary_interactive_control_request", message: "Sanctuary interactive control request received", meta: { bytes: Buffer.byteLength(raw) } });
|
|
299
|
+
const parsed = object(JSON.parse(raw), "interactive control request");
|
|
300
|
+
if (parsed.operation === "interactive_runtime_ready") {
|
|
301
|
+
exactKeys(parsed, ["operation", "label", "scenarioHandleDigest"], "interactive readiness request");
|
|
302
|
+
if (parsed.label !== "unit-16m-restart-continuation" || typeof parsed.scenarioHandleDigest !== "string" || !SHA256.test(parsed.scenarioHandleDigest))
|
|
303
|
+
throw new Error("interactive readiness binding is invalid");
|
|
304
|
+
connection.end(`${JSON.stringify({ ok: true, result: { ready: true } })}\n`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const result = await executeSanctuaryInteractiveEngine(parsed, {
|
|
308
|
+
agentRoot: options.agentRoot,
|
|
309
|
+
readApprovals: (digest) => (0, approval_store_1.readApprovalsByScenarioHandleDigest)(path.join(options.agentRoot, "state", "approvals", "approvals.sqlite"), digest),
|
|
310
|
+
readPending: () => new telegram_client_1.FileTelegramPendingApprovalStore(path.join(options.agentRoot, "state", "approvals", "telegram-pending.json")).load(),
|
|
311
|
+
createSession: async () => ({
|
|
312
|
+
handle: ({ callbackData, queryId, messageId }) => runRequest(() => options.transport.handleUpdate({
|
|
313
|
+
update_id: updateId++,
|
|
314
|
+
callback_query: {
|
|
315
|
+
id: queryId,
|
|
316
|
+
from: { id: Number(options.authorizedUserId) },
|
|
317
|
+
data: callbackData,
|
|
318
|
+
message: {
|
|
319
|
+
message_id: Number(messageId),
|
|
320
|
+
chat: { id: Number(options.authorizedChatId) },
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
})),
|
|
324
|
+
pendingApprovalIds: () => options.transport.listPendingDeliveries().map(({ approvalId }) => approvalId),
|
|
325
|
+
close: () => undefined,
|
|
326
|
+
}),
|
|
327
|
+
proveIndeterminateRecovery: (approval, digest) => proveSanctuaryAttemptedRecoveryWithoutRetry(options.agentRoot, digest, approval),
|
|
328
|
+
writeCredentialObserved: () => /credential|api[_-]?key|token|secret/iu.test(raw),
|
|
329
|
+
});
|
|
330
|
+
connection.end(`${JSON.stringify({ ok: true, result })}\n`);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
connection.end(`${JSON.stringify({ ok: false, error: "interactive runtime operation failed" })}\n`);
|
|
334
|
+
}
|
|
335
|
+
}).catch(() => { if (!connection.destroyed)
|
|
336
|
+
connection.end(`${JSON.stringify({ ok: false, error: "interactive runtime operation failed" })}\n`); });
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
const active = server;
|
|
340
|
+
try {
|
|
341
|
+
await new Promise((resolve, reject) => {
|
|
342
|
+
const onError = (error) => { active.off("listening", onListening); reject(error); };
|
|
343
|
+
const onListening = () => {
|
|
344
|
+
active.off("error", onError);
|
|
345
|
+
try {
|
|
346
|
+
if (!endpoint || !matches(endpoint, readEndpoint()))
|
|
347
|
+
throw new Error("Sanctuary interactive control socket ownership was replaced during startup");
|
|
348
|
+
resolve();
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
reject(error);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
active.once("error", onError);
|
|
355
|
+
active.once("listening", onListening);
|
|
249
356
|
try {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
return;
|
|
357
|
+
active.listen(socketPath);
|
|
358
|
+
if (active.listening) {
|
|
359
|
+
endpoint = readEndpoint();
|
|
360
|
+
if (!endpoint?.isSocket())
|
|
361
|
+
throw new Error("Sanctuary interactive control startup ownership is unproven");
|
|
362
|
+
(0, node_fs_1.chmodSync)(socketPath, 0o600);
|
|
363
|
+
endpoint = readEndpoint();
|
|
258
364
|
}
|
|
259
|
-
const result = await executeSanctuaryInteractiveEngine(parsed, {
|
|
260
|
-
agentRoot: options.agentRoot,
|
|
261
|
-
readApprovals: (digest) => (0, approval_store_1.readApprovalsByScenarioHandleDigest)(path.join(options.agentRoot, "state", "approvals", "approvals.sqlite"), digest),
|
|
262
|
-
readPending: () => new telegram_client_1.FileTelegramPendingApprovalStore(path.join(options.agentRoot, "state", "approvals", "telegram-pending.json")).load(),
|
|
263
|
-
createSession: async () => ({
|
|
264
|
-
handle: ({ callbackData, queryId, messageId }) => runRequest(() => options.transport.handleUpdate({
|
|
265
|
-
update_id: updateId++,
|
|
266
|
-
callback_query: {
|
|
267
|
-
id: queryId,
|
|
268
|
-
from: { id: Number(options.authorizedUserId) },
|
|
269
|
-
data: callbackData,
|
|
270
|
-
message: {
|
|
271
|
-
message_id: Number(messageId),
|
|
272
|
-
chat: { id: Number(options.authorizedChatId) },
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
})),
|
|
276
|
-
pendingApprovalIds: () => options.transport.listPendingDeliveries().map(({ approvalId }) => approvalId),
|
|
277
|
-
close: () => undefined,
|
|
278
|
-
}),
|
|
279
|
-
proveIndeterminateRecovery: (approval, digest) => proveSanctuaryAttemptedRecoveryWithoutRetry(options.agentRoot, digest, approval),
|
|
280
|
-
writeCredentialObserved: () => /credential|api[_-]?key|token|secret/iu.test(raw),
|
|
281
|
-
});
|
|
282
|
-
connection.end(`${JSON.stringify({ ok: true, result })}\n`);
|
|
283
365
|
}
|
|
284
|
-
catch {
|
|
285
|
-
|
|
366
|
+
catch (error) {
|
|
367
|
+
active.off("error", onError);
|
|
368
|
+
onError(error);
|
|
286
369
|
}
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
try {
|
|
374
|
+
await stopListener();
|
|
375
|
+
}
|
|
376
|
+
catch (cleanupError) {
|
|
377
|
+
throw new AggregateError([error, cleanupError], "Sanctuary interactive control startup and ownership cleanup failed");
|
|
378
|
+
}
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
})().finally(() => { if (startPromise === starting)
|
|
382
|
+
startPromise = undefined; });
|
|
383
|
+
startPromise = starting;
|
|
384
|
+
return starting;
|
|
385
|
+
},
|
|
386
|
+
stop() {
|
|
387
|
+
if (stopPromise)
|
|
388
|
+
return stopPromise;
|
|
389
|
+
const starting = startPromise;
|
|
390
|
+
startPromise = undefined;
|
|
391
|
+
const stopping = (async () => {
|
|
392
|
+
if (starting)
|
|
393
|
+
await starting;
|
|
394
|
+
await stopListener();
|
|
395
|
+
})().finally(() => { if (stopPromise === stopping)
|
|
396
|
+
stopPromise = undefined; });
|
|
397
|
+
stopPromise = stopping;
|
|
398
|
+
return stopping;
|
|
292
399
|
},
|
|
293
|
-
async stop() { const active = server; server = undefined; if (active)
|
|
294
|
-
await new Promise((resolve) => active.close(() => resolve())); if ((0, node_fs_1.existsSync)(socketPath))
|
|
295
|
-
(0, node_fs_1.unlinkSync)(socketPath); },
|
|
296
400
|
};
|
|
297
401
|
}
|
|
298
402
|
async function sanctuaryInteractiveControlReady(socketPath, timeoutMs = 1_000) {
|
|
@@ -268,14 +268,26 @@ function rawSessionEvents(value) {
|
|
|
268
268
|
const record = value;
|
|
269
269
|
return record.version === 2 && Array.isArray(record.events) ? record.events : [];
|
|
270
270
|
}
|
|
271
|
-
function exactProjectedIngressMessage(existing, messages, eventId) {
|
|
271
|
+
function exactProjectedIngressMessage(existing, messages, eventId, nativeValue) {
|
|
272
|
+
if (!nativeValue || typeof nativeValue !== "object" || Array.isArray(nativeValue))
|
|
273
|
+
return null;
|
|
274
|
+
const native = nativeValue;
|
|
275
|
+
if (native.version !== 2 || !native.projection || typeof native.projection !== "object" || Array.isArray(native.projection))
|
|
276
|
+
return null;
|
|
277
|
+
const projection = native.projection;
|
|
278
|
+
if (!Array.isArray(projection.eventIds))
|
|
279
|
+
return null;
|
|
280
|
+
// Authorization must inspect stored IDs before a reader filters unresolved entries.
|
|
281
|
+
const projectionIds = projection.eventIds.length > 0
|
|
282
|
+
? projection.eventIds
|
|
283
|
+
: projection.trimmed === true ? [] : existing.projectionEventIds;
|
|
272
284
|
const eventsById = new Map(existing.events.map((event) => [event.id, event]));
|
|
273
285
|
if (eventsById.size !== existing.events.length)
|
|
274
286
|
return null;
|
|
275
287
|
const seenProjectionIds = new Set();
|
|
276
288
|
const effectiveIds = new Set((0, session_events_1.selectEffectiveSessionEvents)(existing.events).map((event) => event.id));
|
|
277
289
|
const projectedEvents = [];
|
|
278
|
-
for (const projectedId of
|
|
290
|
+
for (const projectedId of projectionIds) {
|
|
279
291
|
if (typeof projectedId !== "string" || !projectedId.trim() || seenProjectionIds.has(projectedId))
|
|
280
292
|
return null;
|
|
281
293
|
const event = eventsById.get(projectedId);
|
|
@@ -285,7 +297,7 @@ function exactProjectedIngressMessage(existing, messages, eventId) {
|
|
|
285
297
|
if (effectiveIds.has(event.id))
|
|
286
298
|
projectedEvents.push(event);
|
|
287
299
|
}
|
|
288
|
-
if (
|
|
300
|
+
if (projectionIds.filter((projectedId) => projectedId === eventId).length !== 1)
|
|
289
301
|
return null;
|
|
290
302
|
const projectedUsers = projectedEvents.filter((event) => event.role === "user");
|
|
291
303
|
const providerUsers = messages.filter((message) => message.role === "user");
|
|
@@ -401,7 +413,8 @@ async function runSenseTurnExclusive(options, owner) {
|
|
|
401
413
|
const runWithLease = options._withSessionTurnLease ?? session_transaction_1.withSessionTurnLease;
|
|
402
414
|
try {
|
|
403
415
|
return await runWithLease(sessPath, async (sessionTurnLease) => {
|
|
404
|
-
const
|
|
416
|
+
const baseSession = (0, session_transaction_1.readSessionTransaction)(sessPath, sessionTurnLease);
|
|
417
|
+
const baseSessionRevision = baseSession.revision;
|
|
405
418
|
const existing = options.disablePersistence ? undefined : (0, context_1.loadSession)(sessPath);
|
|
406
419
|
const precommittedIngressEvent = options.precommittedIngress
|
|
407
420
|
? existing?.events?.find((candidate) => candidate.id === options.precommittedIngress.eventId)
|
|
@@ -424,7 +437,7 @@ async function runSenseTurnExclusive(options, owner) {
|
|
|
424
437
|
content: (0, prompt_1.flattenSystemPrompt)(await (0, prompt_1.buildSystem)(channel, options.disableTools ? { tools: [], hardDisableTools: true } : {}, undefined)),
|
|
425
438
|
}];
|
|
426
439
|
if (precommittedIngressEvent) {
|
|
427
|
-
const projectedIngress = exactProjectedIngressMessage(existing, sessionMessages, precommittedIngressEvent.id);
|
|
440
|
+
const projectedIngress = exactProjectedIngressMessage(existing, sessionMessages, precommittedIngressEvent.id, baseSession.value);
|
|
428
441
|
if (!projectedIngress || projectedIngress.role !== "user" || projectedIngress.content !== userMessage)
|
|
429
442
|
throw new Error("shared turn precommitted ingress is absent from the provider projection");
|
|
430
443
|
(0, session_events_1.stampIngressRelations)(projectedIngress, {
|
|
@@ -724,11 +724,15 @@ function appendTelegramArtifactEvents(envelope, artifact, recordedAt) {
|
|
|
724
724
|
};
|
|
725
725
|
});
|
|
726
726
|
const eventIds = events.map((event) => event.id);
|
|
727
|
+
const priorIds = (0, session_events_1.projectedSessionEventIds)(envelope);
|
|
727
728
|
return {
|
|
728
729
|
envelope: {
|
|
729
730
|
...envelope,
|
|
730
731
|
events: [...envelope.events, ...events],
|
|
731
|
-
projection: {
|
|
732
|
+
projection: {
|
|
733
|
+
...envelope.projection, eventIds: [...priorIds, ...eventIds], projectedAt: recordedAt,
|
|
734
|
+
trimmed: new Set(priorIds).size < (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length,
|
|
735
|
+
},
|
|
732
736
|
},
|
|
733
737
|
eventIds,
|
|
734
738
|
};
|
|
@@ -758,10 +762,14 @@ function appendTelegramInboundEvent(envelope, input) {
|
|
|
758
762
|
},
|
|
759
763
|
provenance: { captureKind: "live", legacyVersion: null, sourceMessageIndex: null },
|
|
760
764
|
};
|
|
765
|
+
const priorIds = (0, session_events_1.projectedSessionEventIds)(envelope);
|
|
761
766
|
return {
|
|
762
767
|
...envelope,
|
|
763
768
|
events: [...envelope.events, event],
|
|
764
|
-
projection: {
|
|
769
|
+
projection: {
|
|
770
|
+
...envelope.projection, eventIds: [...priorIds, id], projectedAt: input.recordedAt,
|
|
771
|
+
trimmed: new Set(priorIds).size < (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length,
|
|
772
|
+
},
|
|
765
773
|
};
|
|
766
774
|
}
|
|
767
775
|
async function recordTelegramEffectsInSession(input) {
|
package/dist/senses/telegram.js
CHANGED
|
@@ -1669,6 +1669,26 @@ function createTelegramSenseApp(options) {
|
|
|
1669
1669
|
catch (error) {
|
|
1670
1670
|
releaseAcceptanceAudit(error);
|
|
1671
1671
|
}
|
|
1672
|
+
const pendingCleanup = new Set([
|
|
1673
|
+
() => poll.stop(),
|
|
1674
|
+
async () => { await runPromise?.catch(() => undefined); },
|
|
1675
|
+
async () => { await Promise.all([...approvalReconciliationsInFlight]); },
|
|
1676
|
+
async () => { await interactiveControl?.stop(); },
|
|
1677
|
+
() => api.stop(),
|
|
1678
|
+
() => approvalRuntime?.close(),
|
|
1679
|
+
() => effectJournal?.close(),
|
|
1680
|
+
() => admissionStore?.close(),
|
|
1681
|
+
() => (0, tools_awaiting_1.resetAwaitToolDeps)(),
|
|
1682
|
+
() => runWithAcceptanceAuditOwner(() => {
|
|
1683
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1684
|
+
component: "senses",
|
|
1685
|
+
event: "senses.telegram_poll_end",
|
|
1686
|
+
message: "Telegram long poll stopped",
|
|
1687
|
+
meta: { agentName: options.agentName, subject },
|
|
1688
|
+
});
|
|
1689
|
+
}),
|
|
1690
|
+
retireAcceptanceAudit,
|
|
1691
|
+
]);
|
|
1672
1692
|
return {
|
|
1673
1693
|
run(signal) {
|
|
1674
1694
|
if (runPromise)
|
|
@@ -1762,37 +1782,20 @@ function createTelegramSenseApp(options) {
|
|
|
1762
1782
|
return stopPromise;
|
|
1763
1783
|
stopPromise = (async () => {
|
|
1764
1784
|
const errors = [];
|
|
1765
|
-
const
|
|
1785
|
+
for (const operation of pendingCleanup) {
|
|
1766
1786
|
try {
|
|
1767
1787
|
await operation();
|
|
1788
|
+
pendingCleanup.delete(operation);
|
|
1768
1789
|
}
|
|
1769
1790
|
catch (error) {
|
|
1770
1791
|
errors.push(error);
|
|
1771
1792
|
}
|
|
1772
|
-
}
|
|
1773
|
-
await attempt(() => poll.stop());
|
|
1774
|
-
await attempt(async () => { await runPromise?.catch(() => undefined); });
|
|
1775
|
-
await attempt(async () => { await Promise.all([...approvalReconciliationsInFlight]); });
|
|
1776
|
-
await attempt(async () => { await interactiveControl?.stop(); });
|
|
1777
|
-
await attempt(() => api.stop());
|
|
1778
|
-
await attempt(() => approvalRuntime?.close());
|
|
1779
|
-
await attempt(() => effectJournal?.close());
|
|
1780
|
-
await attempt(() => admissionStore?.close());
|
|
1781
|
-
await attempt(() => (0, tools_awaiting_1.resetAwaitToolDeps)());
|
|
1782
|
-
await attempt(() => runWithAcceptanceAuditOwner(() => {
|
|
1783
|
-
(0, runtime_1.emitNervesEvent)({
|
|
1784
|
-
component: "senses",
|
|
1785
|
-
event: "senses.telegram_poll_end",
|
|
1786
|
-
message: "Telegram long poll stopped",
|
|
1787
|
-
meta: { agentName: options.agentName, subject },
|
|
1788
|
-
});
|
|
1789
|
-
}));
|
|
1790
|
-
await attempt(retireAcceptanceAudit);
|
|
1793
|
+
}
|
|
1791
1794
|
if (errors.length === 1)
|
|
1792
1795
|
throw errors[0];
|
|
1793
1796
|
if (errors.length > 1)
|
|
1794
1797
|
throw new AggregateError(errors, "Telegram sense cleanup failed");
|
|
1795
|
-
})();
|
|
1798
|
+
})().catch((error) => { stopPromise = undefined; throw error; });
|
|
1796
1799
|
return stopPromise;
|
|
1797
1800
|
},
|
|
1798
1801
|
};
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.815",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.815",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|