@ouro.bot/cli 0.1.0-alpha.696 → 0.1.0-alpha.698

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 (46) hide show
  1. package/changelog.json +18 -0
  2. package/dist/heart/agent-entry.js +32 -2
  3. package/dist/heart/autonomy-budget.js +434 -0
  4. package/dist/heart/core.js +11 -0
  5. package/dist/heart/daemon/cadence.js +110 -0
  6. package/dist/heart/daemon/cli-exec.js +20 -0
  7. package/dist/heart/daemon/cli-help.js +74 -0
  8. package/dist/heart/daemon/cli-parse.js +466 -0
  9. package/dist/heart/daemon/daemon-entry.js +104 -3
  10. package/dist/heart/daemon/daemon.js +24 -3
  11. package/dist/heart/daemon/doctor.js +151 -0
  12. package/dist/heart/daemon/stale-bundle-prune.js +23 -6
  13. package/dist/heart/habits/habit-parser.js +4 -1
  14. package/dist/heart/habits/habit-scheduler.js +46 -38
  15. package/dist/heart/habits/habit-session.js +2 -3
  16. package/dist/heart/provider-credentials.js +16 -0
  17. package/dist/heart/run-ledger.js +247 -0
  18. package/dist/heart/runtime-credentials.js +12 -3
  19. package/dist/mind/prompt-budget.js +380 -0
  20. package/dist/repertoire/tools-base.js +2 -0
  21. package/dist/repertoire/tools-rsvp.js +139 -0
  22. package/dist/rsvp/aisleplanner-client.js +354 -0
  23. package/dist/rsvp/cli.js +704 -0
  24. package/dist/rsvp/config.js +327 -0
  25. package/dist/rsvp/cutover.js +431 -0
  26. package/dist/rsvp/diagnostics.js +222 -0
  27. package/dist/rsvp/diff-renderer.js +161 -0
  28. package/dist/rsvp/habit-policy.js +85 -0
  29. package/dist/rsvp/habit-stage.js +93 -0
  30. package/dist/rsvp/incident-bundle.js +97 -0
  31. package/dist/rsvp/migration.js +204 -0
  32. package/dist/rsvp/outbound-state.js +254 -0
  33. package/dist/rsvp/query.js +118 -0
  34. package/dist/rsvp/replay.js +233 -0
  35. package/dist/rsvp/snapshot.js +232 -0
  36. package/dist/senses/bluebubbles/client.js +13 -7
  37. package/dist/senses/bluebubbles/index.js +227 -22
  38. package/dist/senses/bluebubbles/outbound-state.js +304 -0
  39. package/dist/senses/bluebubbles/replay.js +147 -0
  40. package/dist/senses/context-packet-ledger.js +245 -0
  41. package/dist/senses/context-packets.js +154 -0
  42. package/dist/senses/pipeline.js +91 -1
  43. package/dist/senses/private-runtime-worker.js +170 -31
  44. package/dist/senses/private-runtime.js +13 -1
  45. package/dist/senses/voice/twilio-phone.js +9 -5
  46. package/package.json +1 -1
@@ -0,0 +1,247 @@
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.runLedgerHash = runLedgerHash;
37
+ exports.usageMetadataFromUsageData = usageMetadataFromUsageData;
38
+ exports.deriveRunLedgerIds = deriveRunLedgerIds;
39
+ exports.createRunLedgerRecord = createRunLedgerRecord;
40
+ exports.runLedgerPath = runLedgerPath;
41
+ exports.appendRunLedgerRecord = appendRunLedgerRecord;
42
+ exports.appendRunLedgerRecordNonFatal = appendRunLedgerRecordNonFatal;
43
+ exports.readRunLedger = readRunLedger;
44
+ const node_crypto_1 = require("node:crypto");
45
+ const fs = __importStar(require("node:fs"));
46
+ const path = __importStar(require("node:path"));
47
+ const runtime_1 = require("../nerves/runtime");
48
+ function sha256Hex(input) {
49
+ return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex");
50
+ }
51
+ function canonicalJson(value) {
52
+ if (Array.isArray(value)) {
53
+ return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
54
+ }
55
+ if (value && typeof value === "object") {
56
+ const record = value;
57
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
58
+ }
59
+ return JSON.stringify(value);
60
+ }
61
+ function hashValue(value) {
62
+ return sha256Hex(canonicalJson(value));
63
+ }
64
+ function runLedgerHash(value) {
65
+ return `sha256:${hashValue(value)}`;
66
+ }
67
+ function stableUnique(values) {
68
+ return [...new Set((values ?? []).filter((value) => typeof value === "string" && value.trim().length > 0))];
69
+ }
70
+ function numberOrZero(value) {
71
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
72
+ }
73
+ function usageMetadataFromUsageData(usage, source) {
74
+ return {
75
+ source,
76
+ inputTokens: numberOrZero(usage?.input_tokens),
77
+ outputTokens: numberOrZero(usage?.output_tokens),
78
+ reasoningTokens: numberOrZero(usage?.reasoning_tokens),
79
+ totalTokens: numberOrZero(usage?.total_tokens),
80
+ };
81
+ }
82
+ function deriveRunLedgerIds(input) {
83
+ const targetHash = runLedgerHash(input.target);
84
+ const idempotencyKey = `idem_${hashValue({
85
+ agent: input.agent,
86
+ triggerType: input.triggerType,
87
+ sourceKind: input.sourceKind,
88
+ senseOrHabit: input.senseOrHabit,
89
+ scope: input.idempotencyScope ?? input.target,
90
+ }).slice(0, 32)}`;
91
+ const runId = `run_${hashValue({
92
+ agent: input.agent,
93
+ triggerType: input.triggerType,
94
+ sourceKind: input.sourceKind,
95
+ senseOrHabit: input.senseOrHabit,
96
+ targetHash,
97
+ idempotencyKey,
98
+ parentRunId: input.parentRunId ?? null,
99
+ }).slice(0, 24)}`;
100
+ return {
101
+ runId,
102
+ rootRunId: input.rootRunId ?? input.parentRunId ?? runId,
103
+ ...(input.parentRunId ? { parentRunId: input.parentRunId } : {}),
104
+ idempotencyKey,
105
+ targetHash,
106
+ };
107
+ }
108
+ function createRunLedgerRecord(input) {
109
+ const ids = deriveRunLedgerIds(input);
110
+ return {
111
+ schemaVersion: 1,
112
+ recordedAt: new Date().toISOString(),
113
+ ...ids,
114
+ agent: input.agent,
115
+ triggerType: input.triggerType,
116
+ sourceKind: input.sourceKind,
117
+ senseOrHabit: input.senseOrHabit,
118
+ lifecycle: input.lifecycle,
119
+ startedAt: input.startedAt,
120
+ ...(input.endedAt ? { endedAt: input.endedAt } : {}),
121
+ ...(input.usage ? { usage: input.usage } : {}),
122
+ ...(input.provider ? { provider: input.provider } : {}),
123
+ ...(input.model ? { model: input.model } : {}),
124
+ ...(input.sessionRef ? { sessionRef: input.sessionRef } : {}),
125
+ contextPacketIds: stableUnique(input.contextPacketIds),
126
+ contentStored: false,
127
+ ...(input.errorName ? { errorName: input.errorName } : {}),
128
+ ...(input.errorCode ? { errorCode: input.errorCode } : {}),
129
+ };
130
+ }
131
+ function runLedgerPath(agentRoot) {
132
+ return path.join(agentRoot, "state", "run-ledger", "runs.jsonl");
133
+ }
134
+ function appendRunLedgerRecord(agentRoot, record) {
135
+ const filePath = runLedgerPath(agentRoot);
136
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
137
+ fs.appendFileSync(filePath, `${JSON.stringify(record)}\n`, "utf-8");
138
+ (0, runtime_1.emitNervesEvent)({
139
+ component: "heart",
140
+ event: "heart.run_ledger_recorded",
141
+ message: "recorded causal run ledger row",
142
+ meta: {
143
+ agent: record.agent,
144
+ runId: record.runId,
145
+ triggerType: record.triggerType,
146
+ sourceKind: record.sourceKind,
147
+ lifecycle: record.lifecycle,
148
+ senseOrHabit: record.senseOrHabit,
149
+ },
150
+ });
151
+ }
152
+ function appendRunLedgerRecordNonFatal(agentRoot, record) {
153
+ try {
154
+ appendRunLedgerRecord(agentRoot, record);
155
+ return true;
156
+ }
157
+ catch (error) {
158
+ (0, runtime_1.emitNervesEvent)({
159
+ level: "error",
160
+ component: "heart",
161
+ event: "heart.run_ledger_record_error",
162
+ message: "failed to record causal run ledger row",
163
+ meta: {
164
+ agent: record.agent,
165
+ runId: record.runId,
166
+ lifecycle: record.lifecycle,
167
+ error: String(error),
168
+ },
169
+ });
170
+ return false;
171
+ }
172
+ }
173
+ function isStringArray(value) {
174
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
175
+ }
176
+ function isUsageMetadata(value) {
177
+ const usage = value;
178
+ return !!usage
179
+ && (usage.source === "provider" || usage.source === "none" || usage.source === "reported-unavailable")
180
+ && typeof usage.inputTokens === "number"
181
+ && typeof usage.outputTokens === "number"
182
+ && typeof usage.reasoningTokens === "number"
183
+ && typeof usage.totalTokens === "number";
184
+ }
185
+ function isSessionRef(value) {
186
+ const ref = value;
187
+ return !!ref
188
+ && typeof ref.channel === "string"
189
+ && typeof ref.keyHash === "string";
190
+ }
191
+ function isRunLedgerRecord(value) {
192
+ const record = value;
193
+ return !!record
194
+ && record.schemaVersion === 1
195
+ && typeof record.recordedAt === "string"
196
+ && typeof record.runId === "string"
197
+ && typeof record.rootRunId === "string"
198
+ && (record.parentRunId === undefined || typeof record.parentRunId === "string")
199
+ && typeof record.idempotencyKey === "string"
200
+ && typeof record.agent === "string"
201
+ && (record.triggerType === "inbound" || record.triggerType === "habit" || record.triggerType === "reload" || record.triggerType === "recovery" || record.triggerType === "manual")
202
+ && (record.sourceKind === "sense" || record.sourceKind === "private-runtime" || record.sourceKind === "daemon" || record.sourceKind === "cli")
203
+ && typeof record.senseOrHabit === "string"
204
+ && typeof record.targetHash === "string"
205
+ && (record.lifecycle === "started" || record.lifecycle === "completed" || record.lifecycle === "skipped" || record.lifecycle === "blocked" || record.lifecycle === "error")
206
+ && typeof record.startedAt === "string"
207
+ && (record.endedAt === undefined || typeof record.endedAt === "string")
208
+ && (record.usage === undefined || isUsageMetadata(record.usage))
209
+ && (record.provider === undefined || typeof record.provider === "string")
210
+ && (record.model === undefined || typeof record.model === "string")
211
+ && (record.sessionRef === undefined || isSessionRef(record.sessionRef))
212
+ && isStringArray(record.contextPacketIds)
213
+ && record.contentStored === false
214
+ && (record.errorName === undefined || typeof record.errorName === "string")
215
+ && (record.errorCode === undefined || typeof record.errorCode === "string");
216
+ }
217
+ function emitMalformedRunLedgerRow(lineNumber, reason) {
218
+ (0, runtime_1.emitNervesEvent)({
219
+ level: "warn",
220
+ component: "heart",
221
+ event: "heart.run_ledger_malformed",
222
+ message: "skipped malformed causal run ledger row",
223
+ meta: { lineNumber, reason },
224
+ });
225
+ }
226
+ function readRunLedger(agentRoot) {
227
+ const filePath = runLedgerPath(agentRoot);
228
+ if (!fs.existsSync(filePath))
229
+ return [];
230
+ const rows = [];
231
+ const lines = fs.readFileSync(filePath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
232
+ lines.forEach((line, index) => {
233
+ try {
234
+ const parsed = JSON.parse(line);
235
+ if (isRunLedgerRecord(parsed)) {
236
+ rows.push(parsed);
237
+ }
238
+ else {
239
+ emitMalformedRunLedgerRow(index + 1, "invalid shape");
240
+ }
241
+ }
242
+ catch (error) {
243
+ emitMalformedRunLedgerRow(index + 1, String(error));
244
+ }
245
+ });
246
+ return rows;
247
+ }
@@ -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();
@@ -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.