@ouro.bot/cli 0.1.0-alpha.695 → 0.1.0-alpha.697

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 (48) hide show
  1. package/changelog.json +15 -0
  2. package/dist/arc/flight-recorder.js +139 -21
  3. package/dist/arc/obligations.js +28 -6
  4. package/dist/arc/packets.js +48 -0
  5. package/dist/heart/autonomy-budget.js +434 -0
  6. package/dist/heart/core.js +11 -0
  7. package/dist/heart/daemon/cadence.js +110 -0
  8. package/dist/heart/daemon/cli-exec.js +20 -0
  9. package/dist/heart/daemon/cli-help.js +74 -0
  10. package/dist/heart/daemon/cli-parse.js +466 -0
  11. package/dist/heart/daemon/daemon.js +24 -3
  12. package/dist/heart/daemon/doctor.js +151 -0
  13. package/dist/heart/daemon/stale-bundle-prune.js +23 -6
  14. package/dist/heart/habits/habit-parser.js +4 -1
  15. package/dist/heart/habits/habit-scheduler.js +46 -38
  16. package/dist/heart/habits/habit-session.js +2 -3
  17. package/dist/heart/run-ledger.js +247 -0
  18. package/dist/heart/runtime-credentials.js +12 -3
  19. package/dist/heart/work-card.js +1 -11
  20. package/dist/mind/prompt-budget.js +380 -0
  21. package/dist/repertoire/tools-base.js +2 -0
  22. package/dist/repertoire/tools-obligations.js +39 -0
  23. package/dist/repertoire/tools-rsvp.js +139 -0
  24. package/dist/rsvp/aisleplanner-client.js +354 -0
  25. package/dist/rsvp/cli.js +679 -0
  26. package/dist/rsvp/config.js +327 -0
  27. package/dist/rsvp/cutover.js +431 -0
  28. package/dist/rsvp/diagnostics.js +222 -0
  29. package/dist/rsvp/diff-renderer.js +159 -0
  30. package/dist/rsvp/habit-policy.js +85 -0
  31. package/dist/rsvp/habit-stage.js +93 -0
  32. package/dist/rsvp/incident-bundle.js +97 -0
  33. package/dist/rsvp/migration.js +204 -0
  34. package/dist/rsvp/outbound-state.js +254 -0
  35. package/dist/rsvp/query.js +118 -0
  36. package/dist/rsvp/replay.js +233 -0
  37. package/dist/rsvp/snapshot.js +232 -0
  38. package/dist/senses/bluebubbles/client.js +13 -7
  39. package/dist/senses/bluebubbles/index.js +227 -22
  40. package/dist/senses/bluebubbles/outbound-state.js +304 -0
  41. package/dist/senses/bluebubbles/replay.js +147 -0
  42. package/dist/senses/context-packet-ledger.js +245 -0
  43. package/dist/senses/context-packets.js +154 -0
  44. package/dist/senses/pipeline.js +92 -12
  45. package/dist/senses/private-runtime-worker.js +170 -31
  46. package/dist/senses/private-runtime.js +13 -1
  47. package/dist/senses/voice/twilio-phone.js +9 -5
  48. package/package.json +1 -1
@@ -43,6 +43,7 @@ exports.applyRuntimeCredentialBootstrapMessage = applyRuntimeCredentialBootstrap
43
43
  exports.waitForRuntimeCredentialBootstrap = waitForRuntimeCredentialBootstrap;
44
44
  exports.refreshRuntimeCredentialConfig = refreshRuntimeCredentialConfig;
45
45
  exports.refreshMachineRuntimeCredentialConfig = refreshMachineRuntimeCredentialConfig;
46
+ exports.mergeRuntimeCredentialConfig = mergeRuntimeCredentialConfig;
46
47
  exports.upsertRuntimeCredentialConfig = upsertRuntimeCredentialConfig;
47
48
  exports.upsertMachineRuntimeCredentialConfig = upsertMachineRuntimeCredentialConfig;
48
49
  exports.mergeMachineRuntimeCredentialConfig = mergeMachineRuntimeCredentialConfig;
@@ -315,17 +316,25 @@ async function refreshRuntimeCredentialConfig(agentName, options = {}) {
315
316
  async function refreshMachineRuntimeCredentialConfig(agentName, machineId, options = {}) {
316
317
  return refreshRuntimeCredentialConfigItem(agentName, machineRuntimeConfigItemName(machineId), cacheMachineResult, options);
317
318
  }
318
- function mergeRuntimeCredentialConfig(base, patch) {
319
+ function mergeRuntimeCredentialConfigObjects(base, patch) {
319
320
  const next = { ...base };
320
321
  for (const key of Object.keys(patch)) {
321
322
  const baseValue = next[key];
322
323
  const patchValue = patch[key];
323
324
  next[key] = isRecord(baseValue) && isRecord(patchValue)
324
- ? mergeRuntimeCredentialConfig(baseValue, patchValue)
325
+ ? mergeRuntimeCredentialConfigObjects(baseValue, patchValue)
325
326
  : patchValue;
326
327
  }
327
328
  return next;
328
329
  }
330
+ async function mergeRuntimeCredentialConfig(agentName, patch, now = new Date()) {
331
+ const current = await refreshRuntimeCredentialConfig(agentName);
332
+ if (!current.ok && current.reason !== "missing") {
333
+ throw new Error(`cannot merge runtime config at ${current.itemPath}: ${current.error}`);
334
+ }
335
+ const base = current.ok ? current.config : {};
336
+ return upsertRuntimeCredentialConfig(agentName, mergeRuntimeCredentialConfigObjects(base, patch), now);
337
+ }
329
338
  async function upsertRuntimeCredentialConfig(agentName, config, now = new Date()) {
330
339
  const payload = {
331
340
  schemaVersion: 1,
@@ -381,7 +390,7 @@ async function mergeMachineRuntimeCredentialConfig(agentName, machineId, patch,
381
390
  throw new Error(`cannot merge machine runtime config at ${current.itemPath}: ${current.error}`);
382
391
  }
383
392
  const base = current.ok ? current.config : {};
384
- return upsertMachineRuntimeCredentialConfig(agentName, machineId, mergeRuntimeCredentialConfig(base, patch), now);
393
+ return upsertMachineRuntimeCredentialConfig(agentName, machineId, mergeRuntimeCredentialConfigObjects(base, patch), now);
385
394
  }
386
395
  function resetRuntimeCredentialConfigCache() {
387
396
  cachedRuntimeConfigs = new Map();
@@ -44,14 +44,6 @@ const evolution_1 = require("../arc/evolution");
44
44
  const obligations_1 = require("../arc/obligations");
45
45
  const packets_1 = require("../arc/packets");
46
46
  const flight_recorder_1 = require("../arc/flight-recorder");
47
- const ACTIVE_PACKET_STATUSES = new Set([
48
- "drafting",
49
- "processing",
50
- "validating",
51
- "collaborating",
52
- "paused",
53
- "blocked",
54
- ]);
55
47
  function isoFromMs(ms) {
56
48
  return new Date(ms).toISOString();
57
49
  }
@@ -244,9 +236,7 @@ function buildWorkCard(agentName, agentRoot, options = {}) {
244
236
  const sourceIssues = scanArcSourceIssues(agentRoot);
245
237
  const owed = (0, obligations_1.readPendingObligations)(agentRoot).map(obligationItem);
246
238
  const returnObligations = (0, obligations_1.listActiveReturnObligationsForRoot)(agentRoot, { now: options.nowMs }).map(returnObligationItem);
247
- const activePackets = (0, packets_1.listPonderPackets)(agentRoot)
248
- .filter((packet) => ACTIVE_PACKET_STATUSES.has(packet.status))
249
- .map(packetItem);
239
+ const activePackets = (0, packets_1.listActivePonderPackets)(agentRoot, { now: options.nowMs }).map(packetItem);
250
240
  const evolutionCases = (0, evolution_1.listOpenEvolutionCases)(agentRoot).map(evolutionItem);
251
241
  const activeWork = [...activePackets, ...evolutionCases];
252
242
  const waiting = waitingOnHuman([...owed, ...returnObligations, ...activeWork]);
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT_BUDGET_FALLBACK_CONTEXT_WINDOW_TOKENS = exports.PROMPT_BUDGET_POLICY_VERSION = void 0;
4
+ exports.estimatePromptBudgetTokensForMessage = estimatePromptBudgetTokensForMessage;
5
+ exports.estimatePromptBudgetTokens = estimatePromptBudgetTokens;
6
+ exports.applyPromptBudget = applyPromptBudget;
7
+ const runtime_1 = require("../nerves/runtime");
8
+ exports.PROMPT_BUDGET_POLICY_VERSION = "prompt-budget/v1";
9
+ exports.PROMPT_BUDGET_FALLBACK_CONTEXT_WINDOW_TOKENS = 24_000;
10
+ function contentCharacters(content) {
11
+ if (typeof content === "string")
12
+ return content.length;
13
+ if (!content)
14
+ return 0;
15
+ if (Array.isArray(content)) {
16
+ return content.reduce((total, part) => {
17
+ if (typeof part === "string")
18
+ return total + part.length;
19
+ if (!part || typeof part !== "object")
20
+ return total;
21
+ const record = part;
22
+ if (typeof record.text === "string")
23
+ return total + record.text.length;
24
+ if (typeof record.content === "string")
25
+ return total + record.content.length;
26
+ try {
27
+ return total + JSON.stringify(record).length;
28
+ }
29
+ catch {
30
+ return total;
31
+ }
32
+ }, 0);
33
+ }
34
+ if (typeof content === "object") {
35
+ const record = content;
36
+ if (typeof record.text === "string")
37
+ return record.text.length;
38
+ if (typeof record.content === "string")
39
+ return record.content.length;
40
+ try {
41
+ return JSON.stringify(record).length;
42
+ }
43
+ catch {
44
+ return 0;
45
+ }
46
+ }
47
+ return 0;
48
+ }
49
+ function toolCallCharacters(toolCalls) {
50
+ if (!Array.isArray(toolCalls))
51
+ return 0;
52
+ let total = 0;
53
+ for (const call of toolCalls) {
54
+ if (!call || typeof call !== "object")
55
+ continue;
56
+ const record = call;
57
+ if (typeof record.id === "string")
58
+ total += record.id.length;
59
+ const fn = record.function;
60
+ if (fn && typeof fn === "object") {
61
+ const fnRecord = fn;
62
+ if (typeof fnRecord.name === "string")
63
+ total += fnRecord.name.length;
64
+ if (typeof fnRecord.arguments === "string")
65
+ total += fnRecord.arguments.length;
66
+ }
67
+ }
68
+ return total;
69
+ }
70
+ function estimatePromptBudgetTokensForMessage(message) {
71
+ const record = message;
72
+ let characters = 0;
73
+ if (typeof record.role === "string")
74
+ characters += record.role.length;
75
+ if (typeof record.name === "string")
76
+ characters += record.name.length;
77
+ if (typeof record.tool_call_id === "string")
78
+ characters += record.tool_call_id.length;
79
+ characters += contentCharacters(record.content);
80
+ characters += toolCallCharacters(record.tool_calls);
81
+ return Math.ceil(characters / 4);
82
+ }
83
+ function estimatePromptBudgetTokens(messages) {
84
+ return messages.reduce((total, message) => total + estimatePromptBudgetTokensForMessage(message), 0);
85
+ }
86
+ function itemTokens(item) {
87
+ return estimatePromptBudgetTokens(item.messages);
88
+ }
89
+ function cloneMessage(message) {
90
+ return { ...message };
91
+ }
92
+ function messageText(message) {
93
+ return typeof message.content === "string" ? message.content : "";
94
+ }
95
+ function isSenseContextPacketText(text) {
96
+ return /^Untrusted\s+\S+\s+context for this same thread\./.test(text);
97
+ }
98
+ function sourceRefsFrom(text) {
99
+ return [...new Set(text.match(/\bbbmsg:[^\]\s,]+/g) ?? [])];
100
+ }
101
+ function compactSenseContextItem(item) {
102
+ const message = item.messages[0];
103
+ const text = messageText(message);
104
+ const firstLine = text.split("\n").find((line) => line.trim().length > 0);
105
+ const refs = sourceRefsFrom(text);
106
+ const content = [
107
+ firstLine,
108
+ `[prompt budget compacted message excerpts; source refs retained: ${refs.length > 0 ? refs.join(", ") : "none"}]`,
109
+ ].join("\n");
110
+ return {
111
+ ...item,
112
+ compacted: true,
113
+ messages: [{ ...cloneMessage(message), content }],
114
+ };
115
+ }
116
+ const SYSTEM_MARKERS = [
117
+ { marker: "## from my kept record", source: "kept-memory", priority: 5 },
118
+ { marker: "## retrieved from my Desk record diary", source: "kept-memory", priority: 5 },
119
+ { marker: "## habit receipt", source: "habit-receipt", priority: 6 },
120
+ { marker: "## run ledger", source: "habit-receipt", priority: 6 },
121
+ { marker: "## diagnostics", source: "diagnostics", priority: 7 },
122
+ { marker: "## doctor", source: "diagnostics", priority: 7 },
123
+ { marker: "## incident bundle", source: "diagnostics", priority: 7 },
124
+ { marker: "## replay", source: "diagnostics", priority: 7 },
125
+ ];
126
+ function classifySystemSegment(text) {
127
+ const lower = text.toLowerCase();
128
+ if (lower.includes("habit receipt") || lower.includes("run ledger"))
129
+ return { source: "habit-receipt", priority: 6 };
130
+ if (lower.includes("diagnostics") || lower.includes("doctor") || lower.includes("incident bundle") || lower.includes("replay")) {
131
+ return { source: "diagnostics", priority: 7 };
132
+ }
133
+ return { source: "system-prompt", priority: 1 };
134
+ }
135
+ function systemItems(message, index) {
136
+ const text = messageText(message);
137
+ if (isSenseContextPacketText(text)) {
138
+ return [{
139
+ id: `system:${index}:context`,
140
+ priority: 4,
141
+ source: "sense-context-packet",
142
+ messages: [cloneMessage(message)],
143
+ originalMessageCount: 1,
144
+ }];
145
+ }
146
+ const markerPositions = SYSTEM_MARKERS
147
+ .map((marker) => ({ ...marker, start: text.toLowerCase().indexOf(marker.marker.toLowerCase()) }))
148
+ .filter((entry) => entry.start >= 0)
149
+ .sort((left, right) => left.start - right.start);
150
+ if (markerPositions.length === 0) {
151
+ const classified = classifySystemSegment(text);
152
+ return [{
153
+ id: `system:${index}:0`,
154
+ priority: classified.priority,
155
+ source: classified.source,
156
+ messages: [cloneMessage(message)],
157
+ originalMessageCount: 1,
158
+ }];
159
+ }
160
+ const segments = [];
161
+ if (markerPositions[0].start > 0) {
162
+ segments.push({ start: 0, end: markerPositions[0].start, source: "system-prompt", priority: 1 });
163
+ }
164
+ markerPositions.forEach((position, markerIndex) => {
165
+ segments.push({
166
+ start: position.start,
167
+ end: markerPositions[markerIndex + 1]?.start ?? text.length,
168
+ source: position.source,
169
+ priority: position.priority,
170
+ });
171
+ });
172
+ return segments
173
+ .map((segment, segmentIndex) => {
174
+ const content = text.slice(segment.start, segment.end).trim();
175
+ if (!content)
176
+ return null;
177
+ return {
178
+ id: `system:${index}:${segmentIndex}`,
179
+ priority: segment.priority,
180
+ source: segment.source,
181
+ messages: [{ ...cloneMessage(message), content }],
182
+ originalMessageCount: segmentIndex === 0 ? 1 : 0,
183
+ };
184
+ })
185
+ .filter((item) => item !== null);
186
+ }
187
+ function assistantHasToolCalls(message) {
188
+ return message.role === "assistant"
189
+ && Array.isArray(message.tool_calls)
190
+ && message.tool_calls.length > 0;
191
+ }
192
+ function nonSystemSourceFor(messages) {
193
+ const text = messages.map(messageText).join("\n").toLowerCase();
194
+ if (text.includes("habit receipt") || text.includes("run ledger"))
195
+ return "habit-receipt";
196
+ if (text.includes("diagnostics") || text.includes("doctor") || text.includes("incident bundle") || text.includes("replay"))
197
+ return "diagnostics";
198
+ return "recent-session-tail";
199
+ }
200
+ function buildPromptBudgetItems(messages) {
201
+ const rawItems = [];
202
+ let index = 0;
203
+ while (index < messages.length) {
204
+ const message = messages[index];
205
+ if (message.role === "system") {
206
+ rawItems.push(...systemItems(message, index));
207
+ index += 1;
208
+ continue;
209
+ }
210
+ if (assistantHasToolCalls(message)) {
211
+ const block = [cloneMessage(message)];
212
+ let next = index + 1;
213
+ while (messages[next]?.role === "tool") {
214
+ block.push(cloneMessage(messages[next]));
215
+ next += 1;
216
+ }
217
+ rawItems.push({
218
+ id: `conversation:${index}`,
219
+ priority: 3,
220
+ source: nonSystemSourceFor(block),
221
+ messages: block,
222
+ originalMessageCount: block.length,
223
+ });
224
+ index = next;
225
+ continue;
226
+ }
227
+ rawItems.push({
228
+ id: `conversation:${index}`,
229
+ priority: 3,
230
+ source: nonSystemSourceFor([message]),
231
+ messages: [cloneMessage(message)],
232
+ originalMessageCount: 1,
233
+ });
234
+ index += 1;
235
+ }
236
+ const lastUserItemIndex = rawItems.findLastIndex((item) => item.messages.some((message) => message.role === "user"));
237
+ const latestToolItemIndex = rawItems.findLastIndex((item) => item.messages.some((message) => message.role === "tool" || assistantHasToolCalls(message)));
238
+ return rawItems.map((item, itemIndex) => {
239
+ if (itemIndex === lastUserItemIndex) {
240
+ return { ...item, priority: 1, source: "current-user-message" };
241
+ }
242
+ if (itemIndex === latestToolItemIndex) {
243
+ return { ...item, priority: 1, source: "active-tool-result-context" };
244
+ }
245
+ if (item.messages.every((message) => message.role === "system"))
246
+ return item;
247
+ if (item.source === "habit-receipt")
248
+ return { ...item, priority: 6 };
249
+ if (item.source === "diagnostics")
250
+ return { ...item, priority: 7 };
251
+ if (lastUserItemIndex >= 0 && itemIndex < lastUserItemIndex)
252
+ return { ...item, priority: 8, source: "older-session-history" };
253
+ return { ...item, priority: 3, source: "recent-session-tail" };
254
+ });
255
+ }
256
+ function flattenItems(items) {
257
+ return items.flatMap((item) => item.messages.map(cloneMessage));
258
+ }
259
+ function budgetFor(input) {
260
+ const contextWindowTokens = typeof input.contextWindowTokens === "number" && Number.isFinite(input.contextWindowTokens) && input.contextWindowTokens > 0
261
+ ? Math.floor(input.contextWindowTokens)
262
+ : exports.PROMPT_BUDGET_FALLBACK_CONTEXT_WINDOW_TOKENS;
263
+ const outputReserveRatio = input.outputReserveRatio ?? 0.2;
264
+ const protocolReserveRatio = input.protocolReserveRatio ?? 0.1;
265
+ const outputReserveTokens = Math.floor(contextWindowTokens * outputReserveRatio);
266
+ const protocolReserveTokens = Math.floor(contextWindowTokens * protocolReserveRatio);
267
+ return {
268
+ provider: input.provider,
269
+ model: input.model,
270
+ contextWindowTokens,
271
+ outputReserveTokens,
272
+ protocolReserveTokens,
273
+ inputTokenLimit: Math.max(0, contextWindowTokens - outputReserveTokens - protocolReserveTokens),
274
+ };
275
+ }
276
+ function totalItemTokens(items) {
277
+ return estimatePromptBudgetTokens(flattenItems(items));
278
+ }
279
+ function truncationFor(item, reason, beforeTokens, afterTokens) {
280
+ return {
281
+ source: item.source,
282
+ reason,
283
+ beforeTokens,
284
+ afterTokens,
285
+ messageCount: item.originalMessageCount,
286
+ };
287
+ }
288
+ function emitPromptBudgetEvent(result) {
289
+ (0, runtime_1.emitNervesEvent)({
290
+ component: "mind",
291
+ event: "mind.prompt_budget_applied",
292
+ message: "applied final prompt budget before provider turn",
293
+ meta: {
294
+ status: result.status,
295
+ provider: result.budget.provider,
296
+ model: result.budget.model,
297
+ contextWindowTokens: result.budget.contextWindowTokens,
298
+ inputTokenLimit: result.budget.inputTokenLimit,
299
+ estimatedBeforeTokens: result.stats.estimatedBeforeTokens,
300
+ estimatedAfterTokens: result.stats.estimatedAfterTokens,
301
+ droppedMessages: result.stats.droppedMessages,
302
+ truncationCount: result.stats.truncations.length,
303
+ },
304
+ });
305
+ }
306
+ function applyPromptBudget(input) {
307
+ const budget = budgetFor(input);
308
+ const estimatedBeforeTokens = estimatePromptBudgetTokens(input.messages);
309
+ const truncations = [];
310
+ let droppedMessages = 0;
311
+ if (estimatedBeforeTokens <= budget.inputTokenLimit) {
312
+ const result = {
313
+ policyVersion: exports.PROMPT_BUDGET_POLICY_VERSION,
314
+ status: "within_budget",
315
+ messages: input.messages.map(cloneMessage),
316
+ budget,
317
+ stats: {
318
+ estimatedBeforeTokens,
319
+ estimatedAfterTokens: estimatedBeforeTokens,
320
+ originalMessages: input.messages.length,
321
+ finalMessages: input.messages.length,
322
+ droppedMessages,
323
+ truncations,
324
+ },
325
+ };
326
+ emitPromptBudgetEvent(result);
327
+ return result;
328
+ }
329
+ let items = buildPromptBudgetItems(input.messages);
330
+ for (const priority of [8, 7, 6, 5, 4, 3]) {
331
+ if (totalItemTokens(items) <= budget.inputTokenLimit)
332
+ break;
333
+ if (priority === 4) {
334
+ items = items.map((item) => {
335
+ if (item.priority !== 4 || item.compacted)
336
+ return item;
337
+ const beforeTokens = itemTokens(item);
338
+ const compacted = compactSenseContextItem(item);
339
+ const afterTokens = itemTokens(compacted);
340
+ if (afterTokens < beforeTokens) {
341
+ truncations.push(truncationFor(item, "compacted message excerpts to source refs", beforeTokens, afterTokens));
342
+ }
343
+ return compacted;
344
+ });
345
+ if (totalItemTokens(items) <= budget.inputTokenLimit)
346
+ break;
347
+ }
348
+ for (let itemIndex = 0; itemIndex < items.length && totalItemTokens(items) > budget.inputTokenLimit; itemIndex += 1) {
349
+ const item = items[itemIndex];
350
+ if (item.priority !== priority)
351
+ continue;
352
+ const beforeTokens = itemTokens(item);
353
+ droppedMessages += item.originalMessageCount;
354
+ truncations.push(truncationFor(item, "dropped to fit prompt budget", beforeTokens, 0));
355
+ items = items.filter((_, index) => index !== itemIndex);
356
+ itemIndex -= 1;
357
+ }
358
+ }
359
+ const messages = flattenItems(items);
360
+ const estimatedAfterTokens = estimatePromptBudgetTokens(messages);
361
+ const status = estimatedAfterTokens <= budget.inputTokenLimit
362
+ ? "trimmed"
363
+ : "over_budget";
364
+ const result = {
365
+ policyVersion: exports.PROMPT_BUDGET_POLICY_VERSION,
366
+ status,
367
+ messages,
368
+ budget,
369
+ stats: {
370
+ estimatedBeforeTokens,
371
+ estimatedAfterTokens,
372
+ originalMessages: input.messages.length,
373
+ finalMessages: messages.length,
374
+ droppedMessages,
375
+ truncations,
376
+ },
377
+ };
378
+ emitPromptBudgetEvent(result);
379
+ return result;
380
+ }
@@ -26,6 +26,7 @@ const tools_obligations_1 = require("./tools-obligations");
26
26
  const tools_evolution_1 = require("./tools-evolution");
27
27
  const tools_runtime_1 = require("./tools-runtime");
28
28
  const tools_orientation_1 = require("./tools-orientation");
29
+ const tools_rsvp_1 = require("./tools-rsvp");
29
30
  // Re-export flow tools for consumers that import them from tools-base
30
31
  var tools_flow_1 = require("./tools-flow");
31
32
  Object.defineProperty(exports, "ponderTool", { enumerable: true, get: function () { return tools_flow_1.ponderTool; } });
@@ -67,6 +68,7 @@ exports.baseToolDefinitions = [
67
68
  ...tools_evolution_1.evolutionToolDefinitions,
68
69
  ...tools_orientation_1.orientationToolDefinitions,
69
70
  ...tools_runtime_1.runtimeToolDefinitions,
71
+ ...tools_rsvp_1.rsvpToolDefinitions,
70
72
  ];
71
73
  // Convenience array of just the tool schemas (no handler/integration metadata).
72
74
  // Used by consumers that need the OpenAI function-tool format.
@@ -39,6 +39,7 @@ const identity_1 = require("../heart/identity");
39
39
  const runtime_1 = require("../nerves/runtime");
40
40
  const json_store_1 = require("../arc/json-store");
41
41
  const obligations_1 = require("../arc/obligations");
42
+ const packets_1 = require("../arc/packets");
42
43
  /**
43
44
  * `let_go` lets the agent release a held work item from its attention loop.
44
45
  *
@@ -61,6 +62,40 @@ function outerObligationsDir(agentRoot) {
61
62
  function readOuterObligation(agentRoot, id) {
62
63
  return (0, json_store_1.readJsonFile)(outerObligationsDir(agentRoot), id) ?? null;
63
64
  }
65
+ function completeRelatedPacket(agentRoot, packet, relation) {
66
+ try {
67
+ (0, packets_1.completePonderPacket)(agentRoot, packet.id);
68
+ (0, runtime_1.emitNervesEvent)({
69
+ component: "repertoire",
70
+ event: "repertoire.packet_completed_for_released_obligation",
71
+ message: "linked packet completed for released return obligation",
72
+ meta: { ...relation, packetId: packet.id },
73
+ });
74
+ }
75
+ catch (error) {
76
+ (0, runtime_1.emitNervesEvent)({
77
+ level: "warn",
78
+ component: "repertoire",
79
+ event: "repertoire.packet_completion_for_released_obligation_failed",
80
+ message: "failed to complete linked packet for released return obligation",
81
+ meta: {
82
+ ...relation,
83
+ packetId: packet.id,
84
+ error: error instanceof Error ? error.message : String(error),
85
+ },
86
+ });
87
+ }
88
+ }
89
+ function completePacketsForReturnObligation(agentRoot, returnObligationId) {
90
+ for (const packet of (0, packets_1.listPonderPacketsByRelatedReturnObligationId)(agentRoot, returnObligationId)) {
91
+ completeRelatedPacket(agentRoot, packet, { returnObligationId });
92
+ }
93
+ }
94
+ function completePacketsForObligation(agentRoot, obligationId) {
95
+ for (const packet of (0, packets_1.listPonderPacketsByRelatedObligationId)(agentRoot, obligationId)) {
96
+ completeRelatedPacket(agentRoot, packet, { obligationId });
97
+ }
98
+ }
64
99
  function letGo(args, agentRoot, agentName) {
65
100
  if (typeof args.id !== "string" || args.id.trim().length === 0) {
66
101
  return JSON.stringify({ error: "id is required" });
@@ -73,6 +108,7 @@ function letGo(args, agentRoot, agentName) {
73
108
  const ret = (0, obligations_1.readReturnObligation)(agentName, id);
74
109
  if (ret) {
75
110
  if (ret.status === "returned" || ret.status === "deferred") {
111
+ completePacketsForReturnObligation(agentRoot, id);
76
112
  return JSON.stringify({ kind: "return_obligation", id, already: ret.status });
77
113
  }
78
114
  (0, obligations_1.advanceReturnObligation)(agentName, id, {
@@ -80,6 +116,7 @@ function letGo(args, agentRoot, agentName) {
80
116
  returnedAt: Date.now(),
81
117
  returnTarget: "surface",
82
118
  });
119
+ completePacketsForReturnObligation(agentRoot, id);
83
120
  (0, runtime_1.emitNervesEvent)({
84
121
  component: "repertoire",
85
122
  event: "repertoire.obligation_let_go",
@@ -92,9 +129,11 @@ function letGo(args, agentRoot, agentName) {
92
129
  const outer = readOuterObligation(agentRoot, id);
93
130
  if (outer) {
94
131
  if (outer.status === "fulfilled") {
132
+ completePacketsForObligation(agentRoot, id);
95
133
  return JSON.stringify({ kind: "obligation", id, already: "fulfilled" });
96
134
  }
97
135
  (0, obligations_1.fulfillObligation)(agentRoot, id);
136
+ completePacketsForObligation(agentRoot, id);
98
137
  if (reason !== null) {
99
138
  // Persist the dismissal reason as the obligation's latestNote so future-me
100
139
  // can read why this was released (the nerves event also captures it).
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.rsvpToolDefinitions = void 0;
37
+ const fs = __importStar(require("node:fs"));
38
+ const runtime_1 = require("../nerves/runtime");
39
+ const query_1 = require("../rsvp/query");
40
+ const snapshot_1 = require("../rsvp/snapshot");
41
+ function readSnapshot(snapshotPath) {
42
+ if (!snapshotPath || snapshotPath.trim().length === 0) {
43
+ return { ok: false, reason: "missing", message: "RSVP snapshot not found." };
44
+ }
45
+ try {
46
+ const raw = fs.readFileSync(snapshotPath, "utf-8");
47
+ const parsed = (0, snapshot_1.parseRsvpSnapshot)(JSON.parse(raw));
48
+ if (!parsed.ok) {
49
+ return { ok: false, reason: "invalid", message: "RSVP snapshot could not be read or failed integrity validation." };
50
+ }
51
+ return { ok: true, snapshot: parsed.snapshot };
52
+ }
53
+ catch (error) {
54
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
55
+ return { ok: false, reason: "missing", message: "RSVP snapshot not found." };
56
+ }
57
+ return { ok: false, reason: "invalid", message: "RSVP snapshot could not be read or failed integrity validation." };
58
+ }
59
+ }
60
+ function emitToolRead(toolName, result) {
61
+ (0, runtime_1.emitNervesEvent)({
62
+ component: "repertoire",
63
+ event: "repertoire.rsvp_tool_read",
64
+ message: "RSVP tool read snapshot",
65
+ meta: result.ok
66
+ ? { toolName, snapshotId: result.snapshot.snapshotId, total: result.snapshot.summary.total }
67
+ : { toolName, reason: result.reason },
68
+ });
69
+ }
70
+ exports.rsvpToolDefinitions = [
71
+ {
72
+ tool: {
73
+ type: "function",
74
+ function: {
75
+ name: "rsvp_query",
76
+ description: "answer deterministic questions about a native RSVP snapshot file, such as who is pending, declined, attending, unknown, or matching a guest name.",
77
+ parameters: {
78
+ type: "object",
79
+ properties: {
80
+ snapshot_path: {
81
+ type: "string",
82
+ description: "absolute path to a native RSVP snapshot JSON file.",
83
+ },
84
+ query: {
85
+ type: "string",
86
+ description: "natural-language query or guest-name filter.",
87
+ },
88
+ status: {
89
+ type: "string",
90
+ enum: ["attending", "declined", "pending", "unknown", "all"],
91
+ description: "optional explicit RSVP status filter.",
92
+ },
93
+ },
94
+ required: ["snapshot_path"],
95
+ },
96
+ },
97
+ },
98
+ handler: async (args) => {
99
+ const result = readSnapshot(args.snapshot_path);
100
+ emitToolRead("rsvp_query", result);
101
+ if (!result.ok)
102
+ return result.message;
103
+ return (0, query_1.queryRsvpSnapshot)(result.snapshot, {
104
+ query: args.query,
105
+ status: args.status,
106
+ }).text;
107
+ },
108
+ summaryKeys: ["snapshot_path", "query", "status"],
109
+ riskProfile: { mutates: "none", risk: "low", reason: "reads a local native RSVP snapshot" },
110
+ },
111
+ {
112
+ tool: {
113
+ type: "function",
114
+ function: {
115
+ name: "rsvp_summary",
116
+ description: "summarize counts and provenance for a native RSVP snapshot file.",
117
+ parameters: {
118
+ type: "object",
119
+ properties: {
120
+ snapshot_path: {
121
+ type: "string",
122
+ description: "absolute path to a native RSVP snapshot JSON file.",
123
+ },
124
+ },
125
+ required: ["snapshot_path"],
126
+ },
127
+ },
128
+ },
129
+ handler: async (args) => {
130
+ const result = readSnapshot(args.snapshot_path);
131
+ emitToolRead("rsvp_summary", result);
132
+ if (!result.ok)
133
+ return result.message;
134
+ return (0, query_1.summarizeRsvpSnapshot)(result.snapshot);
135
+ },
136
+ summaryKeys: ["snapshot_path"],
137
+ riskProfile: { mutates: "none", risk: "low", reason: "reads a local native RSVP snapshot" },
138
+ },
139
+ ];