@ouro.bot/cli 0.1.0-alpha.350 → 0.1.0-alpha.351

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,16 @@
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.351",
6
+ "changes": [
7
+ "Surface tool description rewritten from 'surface progress' to 'send a message to someone' — makes it clear the tool is for interpersonal messaging, not status reporting.",
8
+ "Inner dialog prompt contract now guides agents to use rest(note) for heartbeat state and ponder(reflection) for deeper thoughts, keeping surface strictly for words meant for another person.",
9
+ "Removed [surfaced from inner dialog] prefix from synthetic session messages — provenance is tracked via captureKind: 'synthetic', the prefix was redundant and created echo loops.",
10
+ "Obligation summaries and attention queue headers reframed as structured internal data ([internal] tags) instead of surface-ready prose.",
11
+ "Shared proactive-content-guard module blocks internal content (heartbeat, check-in, task board, obligation status, meta markers) from BlueBubbles and Teams proactive sends."
12
+ ]
13
+ },
4
14
  {
5
15
  "version": "0.1.0-alpha.350",
6
16
  "changes": [
@@ -380,7 +380,7 @@ function runtimeInfoSection(channel, options) {
380
380
  lines.push("i introduce myself on boot with a fun random greeting.");
381
381
  }
382
382
  else if (channel === "inner") {
383
- lines.push("this is my inner session. when a thought is ready to share, i surface it to whoever needs to hear it. when i'm done thinking and the queue is clear, i rest.");
383
+ lines.push("this is my inner session. when i have something to say to someone, i surface it. when i'm done thinking and the queue is clear, i rest.");
384
384
  }
385
385
  else if (channel === "mcp") {
386
386
  lines.push("this message arrived via a dev tool (e.g. claude code, codex) on behalf of a friend in a sense session. the user can see our conversation. respond via settle. if friction appears, i first look for ad-hoc repairs with the tools i already have. if the friction reveals a harness gap, i create or revise a ponder packet and keep working. ponder does not create an outward deferral by itself.");
@@ -599,9 +599,10 @@ function toolContractsSection(channel, options) {
599
599
  lines.push(`## tool behavior`);
600
600
  lines.push(`tool_choice is set to "required" -- I must call a tool on every turn.`);
601
601
  if (channel === "inner") {
602
- lines.push(`- When a thought is ready to go outward, I call \`surface\` with the content and, when available, its delegationId.`);
602
+ lines.push(`- When I have something to say to a person, I call \`surface\` with the content and, when available, its delegationId.`);
603
603
  lines.push(`- \`surface\` does not end the inner turn; after surfacing everything that needs delivery, I call \`rest\`.`);
604
- lines.push(`- \`rest\` must be the only tool call in that turn.`);
604
+ lines.push(`- \`rest\` must be the only tool call in that turn. Internal state notes go in \`rest(note: "...")\` — that is my scratchpad, not \`surface\`.`);
605
+ lines.push(`- For deeper reflection I want to preserve, I use \`ponder\` with kind \`reflection\`.`);
605
606
  lines.push(`- I do not call \`send_message\` or \`settle\` from inner dialogue; those are not inner-session delivery tools.`);
606
607
  }
607
608
  else {
@@ -45,7 +45,7 @@ exports.surfaceToolDef = {
45
45
  type: "function",
46
46
  function: {
47
47
  name: "surface",
48
- description: "share a thought outwarddeliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
48
+ description: "send a message to someone write it the way you'd text a friend. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
49
49
  parameters: {
50
50
  type: "object",
51
51
  properties: {
@@ -124,7 +124,7 @@ exports.surfaceToolDefinition = {
124
124
  // Inject surfaced content into the target session so it knows what was delivered
125
125
  const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
126
126
  const sessionFilePath = path.join(sessionsDir, bridgeTarget.friendId, bridgeTarget.channel, `${bridgeTarget.key}.json`);
127
- appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
127
+ appendSyntheticAssistantMessage(sessionFilePath, content);
128
128
  return { status: "delivered", detail: "via iMessage" };
129
129
  }
130
130
  }
@@ -158,7 +158,7 @@ exports.surfaceToolDefinition = {
158
158
  if (proactiveResult.delivered) {
159
159
  const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
160
160
  const sessionFilePath = path.join(sessionsDir, bbSession.friendId, bbSession.channel, `${bbSession.key}.json`);
161
- appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
161
+ appendSyntheticAssistantMessage(sessionFilePath, content);
162
162
  return { status: "delivered", detail: "via iMessage" };
163
163
  }
164
164
  }
@@ -101,7 +101,7 @@ const CONTENT_PREVIEW_MAX = 80;
101
101
  function buildAttentionQueueSummary(queue) {
102
102
  if (queue.length === 0)
103
103
  return "";
104
- const lines = ["you're holding:"];
104
+ const lines = ["[internal: held work items — not messages to send]"];
105
105
  for (const item of queue) {
106
106
  if (item.packetKind && item.packetObjective) {
107
107
  lines.push(`- [${item.id}] ${item.friendName} -> ${item.packetKind}: ${item.packetObjective}`);
@@ -61,6 +61,7 @@ const prompt_1 = require("../../mind/prompt");
61
61
  const mcp_manager_1 = require("../../repertoire/mcp-manager");
62
62
  // getPhrases removed — no longer needed after debug-activity cleanup
63
63
  const runtime_1 = require("../../nerves/runtime");
64
+ const proactive_content_guard_1 = require("../proactive-content-guard");
64
65
  const model_1 = require("./model");
65
66
  const client_1 = require("./client");
66
67
  const inbound_log_1 = require("./inbound-log");
@@ -1368,6 +1369,17 @@ async function sendProactiveBlueBubblesMessageToSession(params, deps = {}) {
1368
1369
  return { delivered: false, reason: "group_blocked" };
1369
1370
  }
1370
1371
  /* v8 ignore stop */
1372
+ const internalContentBlockReason = (0, proactive_content_guard_1.getProactiveInternalContentBlockReason)(params.text);
1373
+ if (internalContentBlockReason) {
1374
+ (0, proactive_content_guard_1.emitProactiveInternalContentBlocked)({
1375
+ friendId: params.friendId,
1376
+ sessionKey: params.sessionKey,
1377
+ reason: internalContentBlockReason,
1378
+ source: "session_send",
1379
+ intent: params.intent ?? "generic_outreach",
1380
+ });
1381
+ return { delivered: false, reason: "internal_content_blocked" };
1382
+ }
1371
1383
  try {
1372
1384
  await client.sendText({ chat, text: params.text });
1373
1385
  (0, runtime_1.emitNervesEvent)({
@@ -1468,6 +1480,20 @@ async function drainAndSendPendingBlueBubbles(deps = {}, pendingRoot) {
1468
1480
  catch { /* ignore */ }
1469
1481
  continue;
1470
1482
  }
1483
+ const internalBlockReason = (0, proactive_content_guard_1.getProactiveInternalContentBlockReason)(messageText);
1484
+ if (internalBlockReason) {
1485
+ result.skipped++;
1486
+ try {
1487
+ fs.unlinkSync(filePath);
1488
+ }
1489
+ catch { /* ignore */ }
1490
+ (0, proactive_content_guard_1.emitProactiveInternalContentBlocked)({
1491
+ friendId,
1492
+ reason: internalBlockReason,
1493
+ source: "pending_drain",
1494
+ });
1495
+ continue;
1496
+ }
1471
1497
  let friend;
1472
1498
  try {
1473
1499
  friend = await store.get(friendId);
@@ -92,7 +92,7 @@ function appendTrailingExtras(sections, alsoDue, staleObligations, parseErrors,
92
92
  }
93
93
  // 5. Stale obligations
94
94
  if (staleObligations.length > 0) {
95
- const lines = staleObligations.map((o) => `something for ${o.friendName} has been sitting for ${formatElapsed(o.stalenessMs)}`);
95
+ const lines = staleObligations.map((o) => `[internal] obligation: ${o.friendName} waiting ${formatElapsed(o.stalenessMs)}`);
96
96
  sections.push(lines.join("\n"));
97
97
  }
98
98
  // 6. Parse errors
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getProactiveInternalContentBlockReason = getProactiveInternalContentBlockReason;
4
+ exports.emitProactiveInternalContentBlocked = emitProactiveInternalContentBlocked;
5
+ const runtime_1 = require("../nerves/runtime");
6
+ // ── Patterns ────────────────────────────────────────────────────
7
+ const PROACTIVE_INTERNAL_CONTENT_PATTERNS = [
8
+ // PR 447 patterns: raw meta markers
9
+ { reason: "raw_meta_marker", pattern: /<\s*\/?\s*(think|analysis|commentary)\b[^>]*>/i },
10
+ { reason: "raw_meta_marker", pattern: /\[\s*surfaced from inner dialog\s*\]/i },
11
+ // Inner dialog / attention / obligation references
12
+ { reason: "inner_dialog_reference", pattern: /\binner (dialog|dialogue)\b/i },
13
+ { reason: "attention_queue_reference", pattern: /\battention queues?\b/i },
14
+ { reason: "return_obligation_reference", pattern: /\b(return|held|heart|inner)\s+obligations?\b/i },
15
+ // Surfacing mechanics
16
+ { reason: "surfacing_mechanics_reference", pattern: /\b(surface tool|surfacing (mechanics|itself)|surfaced? outward|call `?surface`?|delegationId|delegation id)\b/i },
17
+ // Prompt references
18
+ { reason: "prompt_reference", pattern: /\b(system|developer|inner|tool|orientation)\s+prompts?\b|\bprompt\/orientation\b|\bprompt wording\b/i },
19
+ // Routing references
20
+ { reason: "routing_reference", pattern: /\b(routing target|reply target|route through surface|routed through surface|proactive bluebubbles delivery)\b/i },
21
+ // Heartbeat / status patterns
22
+ { reason: "heartbeat_status", pattern: /\bheartbeat\b/i },
23
+ { reason: "heartbeat_status", pattern: /\bcheck-in\b/i },
24
+ { reason: "heartbeat_status", pattern: /\btask board\b/i },
25
+ { reason: "heartbeat_status", pattern: /\ball else settled\b/i },
26
+ { reason: "heartbeat_status", pattern: /\bobligations?\s+showing\b/i },
27
+ { reason: "heartbeat_status", pattern: /\bsame state\b/i },
28
+ ];
29
+ // ── Public API ──────────────────────────────────────────────────
30
+ function getProactiveInternalContentBlockReason(text) {
31
+ for (const { reason, pattern } of PROACTIVE_INTERNAL_CONTENT_PATTERNS) {
32
+ if (pattern.test(text))
33
+ return reason;
34
+ }
35
+ return null;
36
+ }
37
+ function emitProactiveInternalContentBlocked(params) {
38
+ (0, runtime_1.emitNervesEvent)({
39
+ level: "warn",
40
+ component: "senses",
41
+ event: "senses.proactive_internal_content_blocked",
42
+ message: "proactive send blocked: internal content",
43
+ meta: {
44
+ friendId: params.friendId,
45
+ source: params.source,
46
+ reason: params.reason,
47
+ ...(params.sessionKey ? { sessionKey: params.sessionKey } : {}),
48
+ ...(params.intent ? { intent: params.intent } : {}),
49
+ },
50
+ });
51
+ }
@@ -61,6 +61,7 @@ const context_1 = require("../mind/context");
61
61
  const commands_1 = require("./commands");
62
62
  const nerves_1 = require("../nerves");
63
63
  const runtime_1 = require("../nerves/runtime");
64
+ const proactive_content_guard_1 = require("./proactive-content-guard");
64
65
  const store_file_1 = require("../mind/friends/store-file");
65
66
  const types_1 = require("../mind/friends/types");
66
67
  const resolver_1 = require("../mind/friends/resolver");
@@ -1103,6 +1104,16 @@ async function sendProactiveTeamsMessageToSession(params, deps) {
1103
1104
  });
1104
1105
  return { delivered: false, reason: "missing_target" };
1105
1106
  }
1107
+ const internalContentBlockReason = (0, proactive_content_guard_1.getProactiveInternalContentBlockReason)(params.text);
1108
+ if (internalContentBlockReason) {
1109
+ (0, proactive_content_guard_1.emitProactiveInternalContentBlocked)({
1110
+ friendId: params.friendId,
1111
+ sessionKey: params.sessionKey,
1112
+ reason: internalContentBlockReason,
1113
+ source: "session_send",
1114
+ });
1115
+ return { delivered: false, reason: "internal_content_blocked" };
1116
+ }
1106
1117
  try {
1107
1118
  const conversation = await conversations.create({
1108
1119
  bot: { id: deps.botApi.id },
@@ -1205,6 +1216,20 @@ async function drainAndSendPendingTeams(store, botApi, pendingRoot) {
1205
1216
  catch { /* ignore */ }
1206
1217
  continue;
1207
1218
  }
1219
+ const internalBlockReason = (0, proactive_content_guard_1.getProactiveInternalContentBlockReason)(messageText);
1220
+ if (internalBlockReason) {
1221
+ result.skipped++;
1222
+ try {
1223
+ fs.unlinkSync(filePath);
1224
+ }
1225
+ catch { /* ignore */ }
1226
+ (0, proactive_content_guard_1.emitProactiveInternalContentBlocked)({
1227
+ friendId,
1228
+ reason: internalBlockReason,
1229
+ source: "pending_drain",
1230
+ });
1231
+ continue;
1232
+ }
1208
1233
  const sendResult = await sendProactiveTeamsMessageToSession({
1209
1234
  friendId,
1210
1235
  sessionKey: key,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.350",
3
+ "version": "0.1.0-alpha.351",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",