@ouro.bot/cli 0.1.0-alpha.966 → 0.1.0-alpha.967

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 CHANGED
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.967",
6
+ "changes": [
7
+ "When you reply to an older Telegram message, the Butler now sees which message you are answering, so a quick \"yes\" goes to the question you meant instead of the newest one.",
8
+ "Replies to the Butler's control cards and notices are not mistaken for answers to his questions."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.966",
6
13
  "changes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.966",
2
+ "runtimeVersion": "0.1.0-alpha.967",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-09-03T00:00:00.000Z"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
  <Container version="2">
3
3
  <Name>ouro-butler</Name>
4
- <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.966</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.967</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -5,6 +5,7 @@ exports.priorWorkInstruction = priorWorkInstruction;
5
5
  exports.labelPriorWorkSurface = labelPriorWorkSurface;
6
6
  exports.extractMessageText = extractMessageText;
7
7
  exports.extractOrderedListReferents = extractOrderedListReferents;
8
+ exports.stampReplyingToText = stampReplyingToText;
8
9
  exports.buildOrientationFrame = buildOrientationFrame;
9
10
  exports.renderOrientationFrame = renderOrientationFrame;
10
11
  const runtime_1 = require("../nerves/runtime");
@@ -188,6 +189,16 @@ function deriveActionPolicy(signals, combinedSpeech, priorAssistantReferents, la
188
189
  clearedBy: CORRECTION_HOLD_CLEARED_BY,
189
190
  };
190
191
  }
192
+ // A reply names the message it answers. The sense stamps that message's text on the
193
+ // user message, so "yes" binds to what was replied to, not to the latest thing said.
194
+ function stampReplyingToText(message, text) {
195
+ ;
196
+ message._replyingToText = text;
197
+ }
198
+ function replyingToTextOf(message) {
199
+ const text = message._replyingToText;
200
+ return typeof text === "string" && text.trim() ? text.trim() : undefined;
201
+ }
191
202
  function buildOrientationFrame(input) {
192
203
  const derivedCurrent = input.currentUserMessages
193
204
  ? { messages: input.currentUserMessages, firstIndex: input.messages.length }
@@ -195,8 +206,10 @@ function buildOrientationFrame(input) {
195
206
  const currentUserSpeech = derivedCurrent.messages
196
207
  .map((message) => extractMessageText(message))
197
208
  .filter((text) => text.length > 0);
209
+ const replyingToText = derivedCurrent.messages.map(replyingToTextOf).find((text) => text !== undefined);
198
210
  const previousAssistant = latestAssistantBefore(input.messages, derivedCurrent.firstIndex);
199
- const priorAssistantReferents = extractOrderedListReferents(extractMessageText(previousAssistant));
211
+ const priorAssistantReferents = extractOrderedListReferents(replyingToText ?? extractMessageText(previousAssistant));
212
+ const source = replyingToText && !input.source?.replyingToText ? { kind: input.channel, ...input.source, replyingToText } : input.source;
200
213
  const candidateStructuredOutput = latestStructuredOutputFrom(input.structuredOutputs);
201
214
  const speechKind = input.speechKind ?? "utterance";
202
215
  const signals = deriveSignals(currentUserSpeech, priorAssistantReferents, candidateStructuredOutput, speechKind);
@@ -213,7 +226,7 @@ function buildOrientationFrame(input) {
213
226
  ...(latestStructuredOutput ? { latestStructuredOutput } : {}),
214
227
  signals,
215
228
  actionPolicy,
216
- ...(input.source ? { source: input.source } : {}),
229
+ ...(source ? { source } : {}),
217
230
  ...(speechKind === "utterance" ? {} : { speechKind }),
218
231
  };
219
232
  (0, runtime_1.emitNervesEvent)({
@@ -62,6 +62,7 @@ const pipeline_1 = require("./pipeline");
62
62
  const mcp_manager_1 = require("../repertoire/mcp-manager");
63
63
  const runtime_1 = require("../nerves/runtime");
64
64
  const session_transaction_1 = require("../mind/session-transaction");
65
+ const orientation_frame_1 = require("../heart/orientation-frame");
65
66
  const turn_execution_lease_1 = require("../heart/turn-execution-lease");
66
67
  const RESPONSE_CAP = 50_000;
67
68
  const OUTWARD_DELIVERY_TOOL_ACKS = new Map([
@@ -270,6 +271,23 @@ function rawSessionEvents(value) {
270
271
  const record = value;
271
272
  return record.version === 2 && Array.isArray(record.events) ? record.events : [];
272
273
  }
274
+ // What the agent said in a replied-to message: the settle answer it delivered, else its text.
275
+ // Only the agent's own messages are quoted; a control card or notice is not something it asked.
276
+ function spokenText(event) {
277
+ if (event?.role !== "assistant")
278
+ return "";
279
+ for (const call of event.toolCalls) {
280
+ if (call.function.name !== "settle")
281
+ continue;
282
+ try {
283
+ const answer = JSON.parse(call.function.arguments).answer;
284
+ if (typeof answer === "string" && answer.trim())
285
+ return answer.trim().slice(0, 1200);
286
+ }
287
+ catch { /* a malformed settle names nothing */ }
288
+ }
289
+ return typeof event.content === "string" ? event.content.trim().slice(0, 1200) : "";
290
+ }
273
291
  function exactProjectedIngressMessage(existing, messages, eventId, nativeValue) {
274
292
  if (!nativeValue || typeof nativeValue !== "object" || Array.isArray(nativeValue))
275
293
  return null;
@@ -462,6 +480,8 @@ async function runSenseTurnExclusive(options, owner) {
462
480
  system.content = system.content.split(`\n${marker}`)[0] + `\n${marker}\n${JSON.stringify(options.shepherdSession)}\nUse this exact UUID for shepherd_read/shepherd_send. If gone, fail explicitly; never substitute a short ref. This locator grants no authority.`;
463
481
  }
464
482
  }
483
+ const replyToEventId = precommittedIngressEvent?.relations.replyToEventId ?? options.ingressRelations?.replyToEventId;
484
+ const repliedToText = spokenText(existing?.events?.find((event) => event.id === replyToEventId));
465
485
  if (precommittedIngressEvent) {
466
486
  const projectedIngress = exactProjectedIngressMessage(existing, sessionMessages, precommittedIngressEvent.id, baseSession.value);
467
487
  if (!projectedIngress || projectedIngress.role !== "user" || projectedIngress.content !== userMessage)
@@ -471,6 +491,8 @@ async function runSenseTurnExclusive(options, owner) {
471
491
  threadRootEventId: precommittedIngressEvent.relations.threadRootEventId,
472
492
  references: precommittedIngressEvent.relations.references,
473
493
  });
494
+ if (repliedToText)
495
+ (0, orientation_frame_1.stampReplyingToText)(projectedIngress, repliedToText);
474
496
  }
475
497
  // Pending dir
476
498
  const pendingDir = (0, pending_1.getPendingDir)(agentName, friendId, channel, sessionKey);
@@ -580,6 +602,8 @@ async function runSenseTurnExclusive(options, owner) {
580
602
  (0, session_events_1.stampIngressTime)(userMsg);
581
603
  if (options.ingressRelations)
582
604
  (0, session_events_1.stampIngressRelations)(userMsg, options.ingressRelations);
605
+ if (repliedToText)
606
+ (0, orientation_frame_1.stampReplyingToText)(userMsg, repliedToText);
583
607
  inboundMessages.push(userMsg);
584
608
  }
585
609
  const turnResult = await (0, pipeline_1.handleInboundTurn)({
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.966",
3
+ "version": "0.1.0-alpha.967",
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.966",
9
+ "version": "0.1.0-alpha.967",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.966",
3
+ "version": "0.1.0-alpha.967",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },