@ouro.bot/cli 0.1.0-alpha.742 → 0.1.0-alpha.743

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.
Files changed (71) hide show
  1. package/changelog.json +26 -0
  2. package/deploy/unraid/Dockerfile +7 -2
  3. package/deploy/unraid/README.txt +704 -64
  4. package/deploy/unraid/migrate-sanctuary-bundle.mjs +21 -0
  5. package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
  6. package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
  7. package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
  8. package/deploy/unraid/ouro-events/install-usenet-guard.sh +434 -0
  9. package/deploy/unraid/ouro-events/usenet-health.sh +178 -0
  10. package/deploy/unraid/sanctuary-acceptance-contract.json +4 -3
  11. package/deploy/unraid/sanctuary-unit16-host-broker.mjs +5 -1
  12. package/deploy/unraid/sanctuary.ouro/bundle-meta.json +2 -2
  13. package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +1 -1
  14. package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +3 -1
  15. package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +3 -1
  16. package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +4 -0
  17. package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +6 -2
  18. package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +4 -2
  19. package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
  20. package/deploy/unraid/sanctuary.ouro/tool-profiles.json +19 -17
  21. package/deploy/unraid/sanctuary.xml +13 -10
  22. package/dist/arc/cares.js +171 -37
  23. package/dist/arc/obligations.js +38 -0
  24. package/dist/heart/awaiting/await-alert.js +4 -2
  25. package/dist/heart/awaiting/await-expiry.js +39 -4
  26. package/dist/heart/awaiting/await-parser.js +8 -0
  27. package/dist/heart/core.js +37 -7
  28. package/dist/heart/cross-chat-delivery.js +1 -0
  29. package/dist/heart/daemon/container-spec-auditor-main.js +11 -7
  30. package/dist/heart/daemon/container-spec-auditor.js +38 -11
  31. package/dist/heart/daemon/daemon-entry.js +19 -5
  32. package/dist/heart/daemon/daemon.js +154 -22
  33. package/dist/heart/daemon/sanctuary-acceptance-adapter.js +126 -42
  34. package/dist/heart/daemon/sanctuary-acceptance-harness.js +26 -29
  35. package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +42 -51
  36. package/dist/heart/daemon/sanctuary-bundle-migration.js +398 -0
  37. package/dist/heart/external-events/router.js +1025 -43
  38. package/dist/heart/session-events.js +23 -5
  39. package/dist/heart/steward-policy.js +302 -0
  40. package/dist/heart/tool-approval.js +3 -1
  41. package/dist/heart/turn-context.js +1 -0
  42. package/dist/mind/context.js +8 -3
  43. package/dist/mind/pending.js +25 -0
  44. package/dist/mind/prompt.js +49 -1
  45. package/dist/repertoire/guardrails.js +2 -1
  46. package/dist/repertoire/relationship-authorization.js +194 -0
  47. package/dist/repertoire/tools-awaiting.js +229 -26
  48. package/dist/repertoire/tools-base.js +15 -0
  49. package/dist/repertoire/tools-continuity.js +259 -4
  50. package/dist/repertoire/tools-notes.js +29 -3
  51. package/dist/repertoire/tools-session.js +219 -4
  52. package/dist/repertoire/tools-steward-policy.js +88 -0
  53. package/dist/repertoire/tools-telegram-contacts.js +37 -0
  54. package/dist/repertoire/tools-unraid.js +113 -6
  55. package/dist/repertoire/tools.js +104 -9
  56. package/dist/repertoire/unraid-restart.js +86 -4
  57. package/dist/senses/private-runtime-worker.js +36 -3
  58. package/dist/senses/private-runtime.js +310 -63
  59. package/dist/senses/sanctuary-health-acceptance-probe.js +8 -6
  60. package/dist/senses/sanctuary-health-runner.js +47 -103
  61. package/dist/senses/sanctuary-health.js +53 -105
  62. package/dist/senses/sanctuary-runtime.js +36 -2
  63. package/dist/senses/sanctuary-sab.js +80 -0
  64. package/dist/senses/shared-turn.js +64 -9
  65. package/dist/senses/telegram-admission.js +684 -0
  66. package/dist/senses/telegram-approval-runtime.js +46 -6
  67. package/dist/senses/telegram-client.js +212 -66
  68. package/dist/senses/telegram-effect-adapter.js +787 -0
  69. package/dist/senses/telegram.js +728 -48
  70. package/npm-shrinkwrap.json +6 -6
  71. package/package.json +2 -2
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.stripThinkBlocks = stripThinkBlocks;
43
43
  exports.extractOutwardSenseDeliveryText = extractOutwardSenseDeliveryText;
44
+ exports.getSenseSessionPath = getSenseSessionPath;
44
45
  exports.runSenseTurn = runSenseTurn;
45
46
  const os = __importStar(require("os"));
46
47
  const path = __importStar(require("path"));
@@ -175,6 +176,26 @@ function extractOutwardSenseDeliveryText(messages) {
175
176
  return assistantContentText(assistant.content)
176
177
  ?? outwardDeliveryTextFromAssistantTools(messages, assistantIndex);
177
178
  }
179
+ function newOutwardCoordinates(events, existingEventIds) {
180
+ return events.flatMap((event) => {
181
+ if (existingEventIds.has(event.id) || event.role !== "assistant")
182
+ return [];
183
+ const outwardTools = event.toolCalls.filter((call) => call.function.name === "speak" || call.function.name === "settle");
184
+ if (outwardTools.length > 0)
185
+ return outwardTools.map((call) => ({ kind: call.function.name, eventId: event.id }));
186
+ return typeof event.content === "string" && event.content.trim() ? [{ kind: "text", eventId: event.id }] : [];
187
+ });
188
+ }
189
+ function causalSessionEventIds(events, existingEventIds, attempts) {
190
+ const coordinates = newOutwardCoordinates(events, existingEventIds);
191
+ const aligned = coordinates.length === attempts.length && coordinates.every((coordinate, index) => coordinate.kind === attempts[index].kind)
192
+ ? coordinates.map((coordinate) => coordinate.eventId)
193
+ : attempts.map(() => null);
194
+ return attempts.flatMap((attempt, index) => attempt.delivered ? [aligned[index] ?? null] : []);
195
+ }
196
+ function getSenseSessionPath(agentName, friendId, channel, sessionKey, agentRootOverride) {
197
+ return path.join(agentRootOverride ?? (0, identity_1.getAgentRoot)(agentName), "state", "sessions", friendId, channel, `${(0, config_1.sanitizeKey)(sessionKey)}.json`);
198
+ }
178
199
  /**
179
200
  * Run a single agent turn through the inbound pipeline.
180
201
  * Caller provides channel, session key, friend, and message;
@@ -234,11 +255,20 @@ async function runSenseTurn(options) {
234
255
  // Session path and loading
235
256
  const sessionDir = path.join(agentRoot, "state", "sessions", friendId, channel);
236
257
  fs.mkdirSync(sessionDir, { recursive: true });
237
- const sessPath = path.join(sessionDir, `${(0, config_1.sanitizeKey)(sessionKey)}.json`);
258
+ const sessPath = getSenseSessionPath(agentName, friendId, channel, sessionKey, agentRoot);
238
259
  const runWithLease = options._withSessionTurnLease ?? session_transaction_1.withSessionTurnLease;
239
260
  return runWithLease(sessPath, async (sessionTurnLease) => {
240
261
  const baseSessionRevision = (0, session_transaction_1.readSessionTransaction)(sessPath, sessionTurnLease).revision;
241
262
  const existing = (0, context_1.loadSession)(sessPath);
263
+ if (options.precommittedIngress) {
264
+ const event = existing?.events?.find((candidate) => candidate.id === options.precommittedIngress.eventId);
265
+ const latestUserEvent = existing?.events?.filter((candidate) => candidate.role === "user").at(-1);
266
+ if (!event || event !== latestUserEvent || event.role !== "user" || event.content !== userMessage
267
+ || !event.relations.references.includes(options.precommittedIngress.reference)) {
268
+ throw new Error("shared turn precommitted ingress is missing, mismatched, or no longer current");
269
+ }
270
+ }
271
+ const existingEventIds = new Set(existing?.events?.map((event) => event.id) ?? []);
242
272
  let sessionState = existing?.state;
243
273
  let persistPromise;
244
274
  const sessionMessages = existing?.messages && existing.messages.length > 0
@@ -254,6 +284,7 @@ async function runSenseTurn(options) {
254
284
  let terminalDeliveryKind = "text";
255
285
  const deliveries = [];
256
286
  const deliveryFailures = [];
287
+ const deliveryAttempts = [];
257
288
  let providerInvocationCount = 0;
258
289
  let toolInvocationCount = 0;
259
290
  const commitResponseText = (text) => {
@@ -272,8 +303,11 @@ async function runSenseTurn(options) {
272
303
  if (!text)
273
304
  return;
274
305
  const delivery = { kind, text };
306
+ const attempt = { kind, delivered: false };
307
+ deliveryAttempts.push(attempt);
275
308
  try {
276
309
  await options.deliverySink?.onDelivery(delivery);
310
+ attempt.delivered = true;
277
311
  deliveries.push(delivery);
278
312
  commitResponseText(text);
279
313
  }
@@ -312,14 +346,20 @@ async function runSenseTurn(options) {
312
346
  };
313
347
  /* v8 ignore stop */
314
348
  // Run the pipeline
315
- const userMsg = { role: "user", content: userMessage };
316
- (0, session_events_1.stampIngressTime)(userMsg);
349
+ const inboundMessages = [];
350
+ if (!options.precommittedIngress) {
351
+ const userMsg = { role: "user", content: userMessage };
352
+ (0, session_events_1.stampIngressTime)(userMsg);
353
+ if (options.ingressRelations)
354
+ (0, session_events_1.stampIngressRelations)(userMsg, options.ingressRelations);
355
+ inboundMessages.push(userMsg);
356
+ }
317
357
  const turnResult = await (0, pipeline_1.handleInboundTurn)({
318
358
  channel,
319
359
  latencyMode: options.latencyMode,
320
360
  sessionKey,
321
361
  capabilities,
322
- messages: [userMsg],
362
+ messages: inboundMessages,
323
363
  callbacks,
324
364
  sessionTurnLease,
325
365
  /* v8 ignore start — delegation wrappers; pipeline integration tested separately */
@@ -345,12 +385,14 @@ async function runSenseTurn(options) {
345
385
  mcpManager,
346
386
  ...(options.approvalCoordinatorFactory ? { approvalCoordinator: options.approvalCoordinatorFactory({ sessionPath: sessPath, baseSessionRevision }) } : {}),
347
387
  ...(options.latencyMode === "live" ? { skipKeptNotes: true } : {}),
388
+ ...(options.orientationFrame ? { orientationFrame: options.orientationFrame } : {}),
348
389
  toolContext: {
349
390
  signin: async () => undefined,
350
391
  ...(options.toolContext ? options.toolContext : {}),
351
392
  currentUserMessage: userMessage,
352
393
  },
353
394
  },
395
+ ...(options.prepareRunAgentOptions ? { prepareRunAgentOptions: options.prepareRunAgentOptions } : {}),
354
396
  /* v8 ignore start — delegation wrappers; these just forward to the real functions */
355
397
  runAgent: (msgs, cb, ch, sig, opts) => (0, core_1.runAgent)(msgs, cb, ch, sig, opts),
356
398
  postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
@@ -372,14 +414,15 @@ async function runSenseTurn(options) {
372
414
  deliveryFailures,
373
415
  providerInvocationCount,
374
416
  toolInvocationCount,
417
+ sessionPath: sessPath,
375
418
  };
376
419
  }
377
- if (persistPromise)
378
- await persistPromise;
420
+ const persistedEvents = persistPromise ? await persistPromise : [];
379
421
  await deliverPending(terminalDeliveryKind, { throwOnError: false });
380
422
  const ponderDeferred = false;
381
423
  // Build response
382
424
  let finalResponse;
425
+ let responseCausalSessionEventId;
383
426
  if (committedResponseText.length === 0) {
384
427
  // Agent settled but no text came through callbacks — check session transcript for the settle answer
385
428
  // Await deferred persist so the session file is up-to-date before readback
@@ -388,8 +431,10 @@ async function runSenseTurn(options) {
388
431
  await persistPromise;
389
432
  const postTurnSession = (0, context_1.loadSession)(sessPath);
390
433
  if (postTurnSession?.messages) {
391
- finalResponse = extractOutwardSenseDeliveryText(postTurnSession.messages)
392
- ?? "(agent responded but response was empty)";
434
+ const recovered = extractOutwardSenseDeliveryText(postTurnSession.messages);
435
+ finalResponse = recovered ?? "(agent responded but response was empty)";
436
+ if (recovered)
437
+ responseCausalSessionEventId = newOutwardCoordinates(persistedEvents, existingEventIds).at(-1)?.eventId;
393
438
  }
394
439
  else {
395
440
  finalResponse = "(agent responded but response was empty)";
@@ -427,6 +472,16 @@ async function runSenseTurn(options) {
427
472
  message: "shared turn runner complete",
428
473
  meta: { agentName, channel, sessionKey, friendId, ponderDeferred, responseLength: finalResponse.length },
429
474
  });
430
- return { response: finalResponse, ponderDeferred, deliveries, deliveryFailures, providerInvocationCount, toolInvocationCount };
475
+ return {
476
+ response: finalResponse,
477
+ ponderDeferred,
478
+ deliveries,
479
+ deliveryFailures,
480
+ providerInvocationCount,
481
+ toolInvocationCount,
482
+ sessionPath: sessPath,
483
+ ...(deliveries.length > 0 ? { causalSessionEventIds: causalSessionEventIds(persistedEvents, existingEventIds, deliveryAttempts) } : {}),
484
+ ...(responseCausalSessionEventId ? { responseCausalSessionEventId } : {}),
485
+ };
431
486
  });
432
487
  }