@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.
- package/changelog.json +9 -0
- package/dist/heart/autonomy-budget.js +434 -0
- package/dist/heart/core.js +11 -0
- package/dist/heart/daemon/cadence.js +110 -0
- package/dist/heart/daemon/cli-exec.js +20 -0
- package/dist/heart/daemon/cli-help.js +74 -0
- package/dist/heart/daemon/cli-parse.js +466 -0
- package/dist/heart/daemon/daemon.js +24 -3
- package/dist/heart/daemon/doctor.js +151 -0
- package/dist/heart/daemon/stale-bundle-prune.js +23 -6
- package/dist/heart/habits/habit-parser.js +4 -1
- package/dist/heart/habits/habit-scheduler.js +46 -38
- package/dist/heart/habits/habit-session.js +2 -3
- package/dist/heart/run-ledger.js +247 -0
- package/dist/heart/runtime-credentials.js +12 -3
- package/dist/mind/prompt-budget.js +380 -0
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-rsvp.js +139 -0
- package/dist/rsvp/aisleplanner-client.js +354 -0
- package/dist/rsvp/cli.js +679 -0
- package/dist/rsvp/config.js +327 -0
- package/dist/rsvp/cutover.js +431 -0
- package/dist/rsvp/diagnostics.js +222 -0
- package/dist/rsvp/diff-renderer.js +159 -0
- package/dist/rsvp/habit-policy.js +85 -0
- package/dist/rsvp/habit-stage.js +93 -0
- package/dist/rsvp/incident-bundle.js +97 -0
- package/dist/rsvp/migration.js +204 -0
- package/dist/rsvp/outbound-state.js +254 -0
- package/dist/rsvp/query.js +118 -0
- package/dist/rsvp/replay.js +233 -0
- package/dist/rsvp/snapshot.js +232 -0
- package/dist/senses/bluebubbles/client.js +13 -7
- package/dist/senses/bluebubbles/index.js +227 -22
- package/dist/senses/bluebubbles/outbound-state.js +304 -0
- package/dist/senses/bluebubbles/replay.js +147 -0
- package/dist/senses/context-packet-ledger.js +245 -0
- package/dist/senses/context-packets.js +154 -0
- package/dist/senses/pipeline.js +91 -1
- package/dist/senses/private-runtime-worker.js +170 -31
- package/dist/senses/private-runtime.js +13 -1
- package/dist/senses/voice/twilio-phone.js +9 -5
- 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
|
|
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
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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 =
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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`);
|