@ouro.bot/cli 0.1.0-alpha.696 → 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 (43) hide show
  1. package/changelog.json +9 -0
  2. package/dist/heart/autonomy-budget.js +434 -0
  3. package/dist/heart/core.js +11 -0
  4. package/dist/heart/daemon/cadence.js +110 -0
  5. package/dist/heart/daemon/cli-exec.js +20 -0
  6. package/dist/heart/daemon/cli-help.js +74 -0
  7. package/dist/heart/daemon/cli-parse.js +466 -0
  8. package/dist/heart/daemon/daemon.js +24 -3
  9. package/dist/heart/daemon/doctor.js +151 -0
  10. package/dist/heart/daemon/stale-bundle-prune.js +23 -6
  11. package/dist/heart/habits/habit-parser.js +4 -1
  12. package/dist/heart/habits/habit-scheduler.js +46 -38
  13. package/dist/heart/habits/habit-session.js +2 -3
  14. package/dist/heart/run-ledger.js +247 -0
  15. package/dist/heart/runtime-credentials.js +12 -3
  16. package/dist/mind/prompt-budget.js +380 -0
  17. package/dist/repertoire/tools-base.js +2 -0
  18. package/dist/repertoire/tools-rsvp.js +139 -0
  19. package/dist/rsvp/aisleplanner-client.js +354 -0
  20. package/dist/rsvp/cli.js +679 -0
  21. package/dist/rsvp/config.js +327 -0
  22. package/dist/rsvp/cutover.js +431 -0
  23. package/dist/rsvp/diagnostics.js +222 -0
  24. package/dist/rsvp/diff-renderer.js +159 -0
  25. package/dist/rsvp/habit-policy.js +85 -0
  26. package/dist/rsvp/habit-stage.js +93 -0
  27. package/dist/rsvp/incident-bundle.js +97 -0
  28. package/dist/rsvp/migration.js +204 -0
  29. package/dist/rsvp/outbound-state.js +254 -0
  30. package/dist/rsvp/query.js +118 -0
  31. package/dist/rsvp/replay.js +233 -0
  32. package/dist/rsvp/snapshot.js +232 -0
  33. package/dist/senses/bluebubbles/client.js +13 -7
  34. package/dist/senses/bluebubbles/index.js +227 -22
  35. package/dist/senses/bluebubbles/outbound-state.js +304 -0
  36. package/dist/senses/bluebubbles/replay.js +147 -0
  37. package/dist/senses/context-packet-ledger.js +245 -0
  38. package/dist/senses/context-packets.js +154 -0
  39. package/dist/senses/pipeline.js +91 -1
  40. package/dist/senses/private-runtime-worker.js +170 -31
  41. package/dist/senses/private-runtime.js +13 -1
  42. package/dist/senses/voice/twilio-phone.js +9 -5
  43. package/package.json +1 -1
@@ -51,6 +51,94 @@ const friends_1 = require("@ouro.bot/friends");
51
51
  const tools_base_1 = require("../repertoire/tools-base");
52
52
  const tools_surface_1 = require("../repertoire/tools-surface");
53
53
  const tools_1 = require("../repertoire/tools");
54
+ const habit_policy_1 = require("../rsvp/habit-policy");
55
+ const run_ledger_1 = require("../heart/run-ledger");
56
+ const autonomy_budget_1 = require("../heart/autonomy-budget");
57
+ function isUsageData(value) {
58
+ const usage = value;
59
+ return !!usage
60
+ && typeof usage.input_tokens === "number"
61
+ && typeof usage.output_tokens === "number"
62
+ && typeof usage.total_tokens === "number";
63
+ }
64
+ function extractUsageFromHabitResults(results) {
65
+ const aggregate = {
66
+ input_tokens: 0,
67
+ output_tokens: 0,
68
+ reasoning_tokens: 0,
69
+ total_tokens: 0,
70
+ };
71
+ let found = false;
72
+ for (const result of results) {
73
+ if (!result || typeof result !== "object")
74
+ continue;
75
+ const usage = result.usage;
76
+ if (!isUsageData(usage))
77
+ continue;
78
+ found = true;
79
+ aggregate.input_tokens += usage.input_tokens;
80
+ aggregate.output_tokens += usage.output_tokens;
81
+ aggregate.reasoning_tokens += typeof usage.reasoning_tokens === "number" ? usage.reasoning_tokens : 0;
82
+ aggregate.total_tokens += usage.total_tokens;
83
+ }
84
+ return found ? aggregate : undefined;
85
+ }
86
+ function habitRunLedgerBase(habitRun) {
87
+ const target = {
88
+ habitName: habitRun.habit.name,
89
+ runId: habitRun.runId,
90
+ trigger: habitRun.trigger,
91
+ operationId: habitRun.operationId,
92
+ };
93
+ return {
94
+ agent: (0, identity_1.getAgentName)(),
95
+ triggerType: "habit",
96
+ sourceKind: "private-runtime",
97
+ senseOrHabit: habitRun.habit.name,
98
+ startedAt: habitRun.startedAt,
99
+ target,
100
+ idempotencyScope: target,
101
+ provider: "unknown",
102
+ model: "unknown",
103
+ sessionRef: {
104
+ channel: "inner",
105
+ keyHash: (0, run_ledger_1.runLedgerHash)({ habitName: habitRun.habit.name, runId: habitRun.runId }),
106
+ },
107
+ };
108
+ }
109
+ function recordHabitRunLedger(habitRun, lifecycle, endedAt) {
110
+ const usage = extractUsageFromHabitResults(habitRun.results);
111
+ (0, run_ledger_1.appendRunLedgerRecordNonFatal)(habitRun.agentRoot, (0, run_ledger_1.createRunLedgerRecord)({
112
+ ...habitRunLedgerBase(habitRun),
113
+ lifecycle,
114
+ ...(endedAt ? { endedAt } : {}),
115
+ ...(lifecycle === "completed" || lifecycle === "error"
116
+ ? { usage: (0, run_ledger_1.usageMetadataFromUsageData)(usage, usage ? "provider" : "none") }
117
+ : {}),
118
+ }));
119
+ }
120
+ function reserveHabitAutonomyBudget(habitRun, nowIso) {
121
+ const target = {
122
+ habitName: habitRun.habit.name,
123
+ runId: habitRun.runId,
124
+ trigger: habitRun.trigger,
125
+ operationId: habitRun.operationId,
126
+ };
127
+ if (habitRun.rsvpPolicy) {
128
+ target.rsvpSnapshotRef = habitRun.rsvpPolicy.snapshotRef;
129
+ target.rsvpBudgetRef = habitRun.rsvpPolicy.budgetRef;
130
+ target.rsvpIdempotencyRef = habitRun.rsvpPolicy.idempotencyRef;
131
+ }
132
+ return (0, autonomy_budget_1.reserveAutonomyBudget)(habitRun.agentRoot, {
133
+ agent: (0, identity_1.getAgentName)(),
134
+ triggerType: "habit",
135
+ sourceKind: "private-runtime",
136
+ senseOrHabit: habitRun.habit.name,
137
+ target,
138
+ idempotencyKey: `habit:${habitRun.habit.name}:${habitRun.runId}`,
139
+ now: nowIso,
140
+ });
141
+ }
54
142
  /**
55
143
  * Cap on consecutive `instinct` follow-on turns triggered by `hasPendingWork()`
56
144
  * with no externally-queued work in between. Without this cap, a turn that
@@ -208,13 +296,20 @@ async function prepareHabitRun(habitName, trigger, startedAt) {
208
296
  const agentRoot = (0, identity_1.getAgentRoot)();
209
297
  const errors = [];
210
298
  const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, readHabitForRun(agentRoot, habitName, errors));
299
+ const blockedReason = (0, habit_policy_1.isRsvpHabitName)(habitName) && !habit.rsvp
300
+ ? "RSVP habit metadata is required before private runtime execution"
301
+ : null;
302
+ if (blockedReason && !errors.includes(blockedReason))
303
+ errors.push(blockedReason);
211
304
  const runId = (0, flight_recorder_1.createHabitRunId)(habitName, new Date(startedAt));
212
305
  const operationId = habit.continuity.mode === "stateful" ? `habit:${habit.name}` : null;
213
306
  const priorSessionSummary = readPriorSessionSummary(agentRoot, operationId);
214
307
  const paths = (0, habit_session_1.createHabitSessionPaths)(agentRoot, runId, habit.name);
215
308
  const friendStore = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
216
309
  const permissionEnvelope = await (0, habit_session_1.normalizeHabitPermissionEnvelope)(habit, { agentRoot, friendStore });
217
- const toolPolicy = (0, habit_session_1.filterHabitToolsForEnvelope)([...tools_base_1.baseToolDefinitions, tools_surface_1.surfaceToolDefinition], habit.tools ?? null, permissionEnvelope, riskProfileForHabitPolicy);
310
+ const rsvpPolicy = habit.rsvp ? (0, habit_policy_1.rsvpHabitRuntimePolicy)(habit.rsvp) : undefined;
311
+ const requestedTools = blockedReason ? [] : habit.rsvp ? [...habit_policy_1.RSVP_HABIT_ALLOWED_TOOLS] : habit.tools ?? null;
312
+ const toolPolicy = (0, habit_session_1.filterHabitToolsForEnvelope)([...tools_base_1.baseToolDefinitions, tools_surface_1.surfaceToolDefinition], requestedTools, permissionEnvelope, riskProfileForHabitPolicy);
218
313
  return {
219
314
  agentRoot,
220
315
  habit,
@@ -226,6 +321,8 @@ async function prepareHabitRun(habitName, trigger, startedAt) {
226
321
  paths,
227
322
  permissionEnvelope,
228
323
  toolPolicy,
324
+ ...(rsvpPolicy ? { rsvpPolicy } : {}),
325
+ ...(blockedReason ? { blockedReason } : {}),
229
326
  friendStore,
230
327
  results: [],
231
328
  errors,
@@ -265,8 +362,17 @@ function createPrivateRuntimeWorker(runTurn = (options) => (0, private_runtime_1
265
362
  const queue = [];
266
363
  const lastFireByHabit = new Map();
267
364
  const recentHabitFires = [];
365
+ const startedHabitLedgerRunIds = new Set();
268
366
  let heartbeatOkRestedAt = null;
367
+ function recordHabitStartIfNeeded(habitRun) {
368
+ if (startedHabitLedgerRunIds.has(habitRun.runId))
369
+ return;
370
+ recordHabitRunLedger(habitRun, "started");
371
+ startedHabitLedgerRunIds.add(habitRun.runId);
372
+ }
269
373
  function recordHabitCompletion(habitRun, endedAt = habitRun.startedAt) {
374
+ recordHabitStartIfNeeded(habitRun);
375
+ recordHabitRunLedger(habitRun, habitRun.errors.length > 0 ? "error" : "completed", endedAt);
270
376
  (0, habit_session_1.completeHabitRun)({
271
377
  agentRoot: habitRun.agentRoot,
272
378
  habit: habitRun.habit,
@@ -390,38 +496,67 @@ function createPrivateRuntimeWorker(runTurn = (options) => (0, private_runtime_1
390
496
  clearHeartbeatRestShield();
391
497
  }
392
498
  let turnResult;
499
+ let blockedAutonomyTurn = false;
393
500
  try {
394
- const turnOptions = {
395
- reason: nextReason,
396
- taskId: nextTaskId,
397
- habitName: nextHabitName,
398
- awaitName: nextAwaitName,
399
- ...(nextPrivateTurnDecision ? { privateTurnDecision: nextPrivateTurnDecision } : {}),
400
- ...(currentHabitRun
401
- ? {
402
- trigger: currentHabitRun.trigger,
403
- preparedHabit: {
404
- runId: currentHabitRun.runId,
501
+ const turnStartedAt = new Date(nowSource()).toISOString();
502
+ const autonomyDecision = currentHabitRun && !currentHabitRun.blockedReason
503
+ ? reserveHabitAutonomyBudget(currentHabitRun, turnStartedAt)
504
+ : null;
505
+ if (currentHabitRun)
506
+ recordHabitStartIfNeeded(currentHabitRun);
507
+ if (currentHabitRun?.blockedReason) {
508
+ blockedAutonomyTurn = true;
509
+ turnResult = {
510
+ turnOutcome: "blocked",
511
+ reason: currentHabitRun.blockedReason,
512
+ };
513
+ clearHeartbeatRestShield();
514
+ }
515
+ else if (autonomyDecision && !autonomyDecision.allowed) {
516
+ blockedAutonomyTurn = true;
517
+ const reason = `autonomy budget blocked: ${autonomyDecision.reason}`;
518
+ turnErrors.push(reason);
519
+ turnResult = {
520
+ turnOutcome: "blocked",
521
+ reason,
522
+ autonomyReceiptId: autonomyDecision.receiptId,
523
+ };
524
+ clearHeartbeatRestShield();
525
+ }
526
+ else {
527
+ const turnOptions = {
528
+ reason: nextReason,
529
+ taskId: nextTaskId,
530
+ habitName: nextHabitName,
531
+ awaitName: nextAwaitName,
532
+ ...(nextPrivateTurnDecision ? { privateTurnDecision: nextPrivateTurnDecision } : {}),
533
+ ...(currentHabitRun
534
+ ? {
405
535
  trigger: currentHabitRun.trigger,
406
- operationId: currentHabitRun.operationId,
407
- habit: currentHabitRun.habit,
408
- priorSessionSummary: currentHabitRun.priorSessionSummary,
409
- },
410
- habitSession: {
411
- runId: currentHabitRun.runId,
412
- sessionPath: currentHabitRun.paths.sessionPath,
413
- pendingDir: currentHabitRun.paths.pendingDir,
414
- permissionEnvelope: currentHabitRun.permissionEnvelope,
415
- toolPolicy: currentHabitRun.toolPolicy,
416
- friendStore: currentHabitRun.friendStore,
417
- recordProducedRef: (ref) => { currentHabitRun.producedRefs.push(ref); },
418
- recordSurfaceAttempt: (attempt) => { currentHabitRun.surfaceAttempts.push(attempt); },
419
- recordError: (error) => { currentHabitRun.errors.push(error); },
420
- },
421
- }
422
- : {}),
423
- };
424
- turnResult = await runTurn(turnOptions);
536
+ preparedHabit: {
537
+ runId: currentHabitRun.runId,
538
+ trigger: currentHabitRun.trigger,
539
+ operationId: currentHabitRun.operationId,
540
+ habit: currentHabitRun.habit,
541
+ priorSessionSummary: currentHabitRun.priorSessionSummary,
542
+ },
543
+ habitSession: {
544
+ runId: currentHabitRun.runId,
545
+ sessionPath: currentHabitRun.paths.sessionPath,
546
+ pendingDir: currentHabitRun.paths.pendingDir,
547
+ permissionEnvelope: currentHabitRun.permissionEnvelope,
548
+ toolPolicy: currentHabitRun.toolPolicy,
549
+ ...(currentHabitRun.rsvpPolicy ? { rsvpPolicy: currentHabitRun.rsvpPolicy } : {}),
550
+ friendStore: currentHabitRun.friendStore,
551
+ recordProducedRef: (ref) => { currentHabitRun.producedRefs.push(ref); },
552
+ recordSurfaceAttempt: (attempt) => { currentHabitRun.surfaceAttempts.push(attempt); },
553
+ recordError: (error) => { currentHabitRun.errors.push(error); },
554
+ },
555
+ }
556
+ : {}),
557
+ };
558
+ turnResult = await runTurn(turnOptions);
559
+ }
425
560
  }
426
561
  catch (error) {
427
562
  clearHeartbeatRestShield();
@@ -466,6 +601,10 @@ function createPrivateRuntimeWorker(runTurn = (options) => (0, private_runtime_1
466
601
  consecutiveInstinctTurns = nextReason === "instinct" ? consecutiveInstinctTurns + 1 : 0;
467
602
  continue runLoop;
468
603
  }
604
+ if (blockedAutonomyTurn) {
605
+ finalizeCurrentHabitRun();
606
+ break;
607
+ }
469
608
  // Then check hasPendingWork fallback. This is the loop site: any
470
609
  // tool that writes to the private-runtime pending dir during a turn
471
610
  // would cause hasPendingWork() to be true here, producing a
@@ -77,6 +77,7 @@ const await_runtime_state_1 = require("../heart/awaiting/await-runtime-state");
77
77
  const habit_parser_1 = require("../heart/habits/habit-parser");
78
78
  const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
79
79
  const cadence_1 = require("../heart/daemon/cadence");
80
+ const habit_policy_1 = require("../rsvp/habit-policy");
80
81
  const daemon_health_1 = require("../heart/daemon/daemon-health");
81
82
  const flight_recorder_1 = require("../arc/flight-recorder");
82
83
  const desk_section_1 = require("../mind/desk-section");
@@ -863,6 +864,7 @@ async function runPrivateRuntimeTurn(options) {
863
864
  const habitName = options.habitName;
864
865
  const habitFilePath = path.join(agentRoot, "habits", `${habitName}.md`);
865
866
  const preparedHabit = options.preparedHabit?.habit.name === habitName ? options.preparedHabit.habit : null;
867
+ const rsvpHabit = (0, habit_policy_1.isRsvpHabitName)(habitName);
866
868
  // Read and parse the habit file
867
869
  let habitBody;
868
870
  let habitTitle = habitName;
@@ -870,6 +872,9 @@ async function runPrivateRuntimeTurn(options) {
870
872
  let habitOrigin = null;
871
873
  let habitSurface = { family: true, originator: true, extra: [] };
872
874
  if (preparedHabit) {
875
+ if (rsvpHabit && !preparedHabit.rsvp) {
876
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${habitName}`);
877
+ }
873
878
  habitBody = preparedHabit.body || undefined;
874
879
  habitTitle = preparedHabit.title || habitName;
875
880
  habitLastRun = preparedHabit.lastRun;
@@ -881,6 +886,9 @@ async function runPrivateRuntimeTurn(options) {
881
886
  try {
882
887
  const habitContent = fs.readFileSync(habitFilePath, "utf-8");
883
888
  const parsed = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(habitContent, habitFilePath));
889
+ if (rsvpHabit && !parsed.rsvp) {
890
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${habitName}`);
891
+ }
884
892
  habitBody = parsed.body || undefined;
885
893
  habitTitle = parsed.title || habitName;
886
894
  habitLastRun = parsed.lastRun;
@@ -888,7 +896,11 @@ async function runPrivateRuntimeTurn(options) {
888
896
  habitOrigin = parsed.origin;
889
897
  habitSurface = parsed.surface;
890
898
  }
891
- catch {
899
+ catch (error) {
900
+ if (rsvpHabit) {
901
+ const reason = error instanceof Error ? error.message : String(error);
902
+ throw new Error(`RSVP habit metadata is required before private runtime execution: ${reason}`);
903
+ }
892
904
  // Habit file missing or unreadable
893
905
  }
894
906
  }
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.DEFAULT_TWILIO_MEDIA_MAX_UTTERANCE_MS = exports.DEFAULT_TWILIO_MEDIA_MIN_SPEECH_MS = exports.DEFAULT_TWILIO_MEDIA_SILENCE_END_MS = exports.DEFAULT_TWILIO_MEDIA_SPEECH_RMS_THRESHOLD = exports.DEFAULT_TWILIO_PHONE_TRANSPORT_MODE = exports.DEFAULT_TWILIO_PHONE_PLAYBACK_MODE = exports.TWILIO_PHONE_WEBHOOK_BASE_PATH = exports.DEFAULT_TWILIO_GREETING_PREBUFFER_MS = exports.DEFAULT_TWILIO_RECORD_MAX_LENGTH_SECONDS = exports.DEFAULT_TWILIO_RECORD_TIMEOUT_SECONDS = exports.DEFAULT_TWILIO_PHONE_PORT = exports.normalizeTwilioE164PhoneNumber = void 0;
37
+ exports.resolveTwilioPhoneAgentRoot = resolveTwilioPhoneAgentRoot;
37
38
  exports.normalizeTwilioPhoneBasePath = normalizeTwilioPhoneBasePath;
38
39
  exports.normalizeTwilioPhonePlaybackMode = normalizeTwilioPhonePlaybackMode;
39
40
  exports.normalizeTwilioPhoneTransportMode = normalizeTwilioPhoneTransportMode;
@@ -92,6 +93,9 @@ exports.DEFAULT_TWILIO_MEDIA_MIN_SPEECH_MS = 120;
92
93
  exports.DEFAULT_TWILIO_MEDIA_MAX_UTTERANCE_MS = 15_000;
93
94
  const TWILIO_MEDIA_HANGUP_FALLBACK_MS = 10_000;
94
95
  const TWILIO_STREAM_FAILURE_SILENCE_MP3 = Buffer.from("SUQzBAAAAAAAIlRTU0UAAAAOAAADTGF2ZjYyLjMuMTAwAAAAAAAAAAAAAAD/+0DAAAAAAAAAAAAAAAAAAAAAAABJbmZvAAAADwAAAAsAAAUuADc3Nzc3Nzc3N0tLS0tLS0tLS19fX19fX19fX3Nzc3Nzc3Nzc4eHh4eHh4eHh5ubm5ubm5ubm6+vr6+vr6+vr8PDw8PDw8PDw9fX19fX19fX1+vr6+vr6+vr6////////////wAAAABMYXZjNjIuMTEAAAAAAAAAAAAAAAAkBC8AAAAAAAAFLpJQTFMAAAAAAP/7EMQAA8AAAaQAAAAgAAA0gAAABExBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVV//sQxCmDwAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVX/+xDEUwPAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVf/7EMR8g8AAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVV//sQxKYDwAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVX/+xDEz4PAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7EMTWA8AAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sQxNYDwAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+xDE1gPAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7EMTWA8AAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sQxNYDwAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU=", "base64");
96
+ function resolveTwilioPhoneAgentRoot(options) {
97
+ return options.agentRoot ?? (0, identity_1.getAgentRoot)(options.agentName);
98
+ }
95
99
  function bodyText(body) {
96
100
  if (body === undefined)
97
101
  return "";
@@ -356,7 +360,7 @@ function voiceFriendId(options, from, callSid) {
356
360
  return options.defaultFriendId?.trim() || friendIdFromCaller(from, callSid);
357
361
  }
358
362
  async function resolveVoiceFriendContext(options, input) {
359
- const agentRoot = options.agentRoot ?? (0, identity_1.getAgentRoot)(options.agentName);
363
+ const agentRoot = resolveTwilioPhoneAgentRoot(options);
360
364
  const friendStore = new friends_1.FileFriendStore(path.join(agentRoot, "friends"));
361
365
  const explicitFriendId = input.friendId?.trim();
362
366
  if (explicitFriendId) {
@@ -1047,7 +1051,7 @@ class TwilioMediaStreamSession {
1047
1051
  }
1048
1052
  async playPreparedAudio(request) {
1049
1053
  const prepared = await (0, audio_playback_1.prepareVoiceCallAudio)(request, {
1050
- agentRoot: this.options.agentRoot ?? (0, identity_1.getAgentRoot)(this.options.agentName),
1054
+ agentRoot: resolveTwilioPhoneAgentRoot(this.options),
1051
1055
  });
1052
1056
  const generation = this.startPlayback();
1053
1057
  for (let offset = 0; offset < prepared.audio.byteLength; offset += 160) {
@@ -1793,7 +1797,7 @@ class TwilioOpenAIRealtimeMediaStreamSession {
1793
1797
  }
1794
1798
  async buildInstructions() {
1795
1799
  (0, identity_1.setAgentName)(this.options.agentName);
1796
- const agentRoot = this.options.agentRoot ?? (0, identity_1.getAgentRoot)(this.options.agentName);
1800
+ const agentRoot = resolveTwilioPhoneAgentRoot(this.options);
1797
1801
  const sessionDir = path.join(agentRoot, "state", "sessions", this.friendId, "voice");
1798
1802
  await fs.mkdir(sessionDir, { recursive: true });
1799
1803
  this.sessionPath = path.join(sessionDir, `${(0, config_1.sanitizeKey)(this.sessionKey)}.json`);
@@ -2471,7 +2475,7 @@ class TwilioOpenAIRealtimeMediaStreamSession {
2471
2475
  throw new Error("voice call media stream is not ready");
2472
2476
  }
2473
2477
  const prepared = await (0, audio_playback_1.prepareVoiceCallAudio)(request, {
2474
- agentRoot: this.options.agentRoot ?? (0, identity_1.getAgentRoot)(this.options.agentName),
2478
+ agentRoot: resolveTwilioPhoneAgentRoot(this.options),
2475
2479
  });
2476
2480
  this.playbackMarks.clear();
2477
2481
  this.playbackState = undefined;
@@ -2860,7 +2864,7 @@ class OpenAISipPhoneSession {
2860
2864
  }
2861
2865
  async buildInstructions() {
2862
2866
  (0, identity_1.setAgentName)(this.options.agentName);
2863
- const agentRoot = this.options.agentRoot ?? (0, identity_1.getAgentRoot)(this.options.agentName);
2867
+ const agentRoot = resolveTwilioPhoneAgentRoot(this.options);
2864
2868
  const sessionDir = path.join(agentRoot, "state", "sessions", this.friendId, "voice");
2865
2869
  await fs.mkdir(sessionDir, { recursive: true });
2866
2870
  this.sessionPath = path.join(sessionDir, `${(0, config_1.sanitizeKey)(this.sessionKey)}.json`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.696",
3
+ "version": "0.1.0-alpha.697",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",