@ouro.bot/cli 0.1.0-alpha.720 → 0.1.0-alpha.721
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 +6 -0
- package/dist/arc/flight-recorder.js +112 -6
- package/dist/heart/habits/habit-session.js +7 -4
- package/dist/heart/mailbox/mailbox-http-hooks.js +2 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +23 -0
- package/dist/heart/mailbox/mailbox-read.js +3 -1
- package/dist/heart/mailbox/readers/runtime-readers.js +9 -0
- package/dist/rsvp/native-habit-runner.js +173 -5
- package/dist/senses/bluebubbles/context-packet.js +22 -1
- package/dist/senses/bluebubbles/index.js +54 -28
- package/dist/senses/context-packet-ledger.js +126 -0
- package/dist/senses/pipeline.js +37 -1
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.721",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Make Slugger context hydration and native habit traces inspectable and coverage-gated."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.720",
|
|
6
12
|
"changes": [
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.isHabitRunTrigger = isHabitRunTrigger;
|
|
37
37
|
exports.flightRecorderLatestPath = flightRecorderLatestPath;
|
|
38
|
+
exports.decisionsFromHabitRunTraceSteps = decisionsFromHabitRunTraceSteps;
|
|
38
39
|
exports.isFlightRecorderResume = isFlightRecorderResume;
|
|
39
40
|
exports.readFlightRecorderResume = readFlightRecorderResume;
|
|
40
41
|
exports.writeFlightRecorderResume = writeFlightRecorderResume;
|
|
@@ -86,6 +87,17 @@ function atomicWriteJson(filePath, value) {
|
|
|
86
87
|
function cappedArray(values) {
|
|
87
88
|
return values.map((value) => (0, session_events_1.capStructuredRecordString)(value));
|
|
88
89
|
}
|
|
90
|
+
function decisionsFromHabitRunTraceSteps(traceSteps = []) {
|
|
91
|
+
const decisions = [];
|
|
92
|
+
for (const step of traceSteps) {
|
|
93
|
+
for (const decision of step.decisions ?? []) {
|
|
94
|
+
const trimmed = decision.trim();
|
|
95
|
+
if (trimmed.length > 0)
|
|
96
|
+
decisions.push((0, session_events_1.capStructuredRecordString)(trimmed));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return uniqueStrings(decisions);
|
|
100
|
+
}
|
|
89
101
|
function normalizeEvent(input) {
|
|
90
102
|
const recordedAt = input.recordedAt ?? new Date().toISOString();
|
|
91
103
|
return {
|
|
@@ -604,6 +616,55 @@ function isHabitSurfaceAttemptArray(value) {
|
|
|
604
616
|
&& (entry.rawStatus === undefined || typeof entry.rawStatus === "string")
|
|
605
617
|
&& (entry.error === undefined || typeof entry.error === "string"));
|
|
606
618
|
}
|
|
619
|
+
function isHabitRunTraceStepKind(value) {
|
|
620
|
+
return value === "trigger"
|
|
621
|
+
|| value === "habit_definition"
|
|
622
|
+
|| value === "fetch"
|
|
623
|
+
|| value === "snapshot"
|
|
624
|
+
|| value === "render"
|
|
625
|
+
|| value === "decision"
|
|
626
|
+
|| value === "produced_ref"
|
|
627
|
+
|| value === "surface_attempt"
|
|
628
|
+
|| value === "send"
|
|
629
|
+
|| value === "ledger"
|
|
630
|
+
|| value === "error"
|
|
631
|
+
|| value === "complete";
|
|
632
|
+
}
|
|
633
|
+
function isHabitRunTraceStepStatus(value) {
|
|
634
|
+
return value === "started"
|
|
635
|
+
|| value === "succeeded"
|
|
636
|
+
|| value === "skipped"
|
|
637
|
+
|| value === "blocked"
|
|
638
|
+
|| value === "failed";
|
|
639
|
+
}
|
|
640
|
+
function isHabitRunTraceRefArray(value) {
|
|
641
|
+
return Array.isArray(value)
|
|
642
|
+
&& value.every((entry) => isPlainRecord(entry)
|
|
643
|
+
&& typeof entry.kind === "string"
|
|
644
|
+
&& entry.kind.trim().length > 0
|
|
645
|
+
&& typeof entry.locator === "string"
|
|
646
|
+
&& entry.locator.trim().length > 0
|
|
647
|
+
&& (entry.label === undefined || typeof entry.label === "string"));
|
|
648
|
+
}
|
|
649
|
+
function isHabitRunTraceStepArray(value) {
|
|
650
|
+
return Array.isArray(value)
|
|
651
|
+
&& value.every((entry) => isPlainRecord(entry)
|
|
652
|
+
&& entry.schemaVersion === 1
|
|
653
|
+
&& typeof entry.stepId === "string"
|
|
654
|
+
&& entry.stepId.trim().length > 0
|
|
655
|
+
&& isHabitRunTraceStepKind(entry.kind)
|
|
656
|
+
&& isHabitRunTraceStepStatus(entry.status)
|
|
657
|
+
&& typeof entry.at === "string"
|
|
658
|
+
&& entry.at.trim().length > 0
|
|
659
|
+
&& typeof entry.summary === "string"
|
|
660
|
+
&& entry.summary.trim().length > 0
|
|
661
|
+
&& (entry.refs === undefined || isHabitRunTraceRefArray(entry.refs))
|
|
662
|
+
&& (entry.producedRefs === undefined || isProducedRefArray(entry.producedRefs))
|
|
663
|
+
&& (entry.decisions === undefined || isStringArray(entry.decisions))
|
|
664
|
+
&& (entry.surfaceAttempt === undefined || isHabitSurfaceAttemptArray([entry.surfaceAttempt]))
|
|
665
|
+
&& (entry.error === undefined || typeof entry.error === "string")
|
|
666
|
+
&& (entry.meta === undefined || isPlainRecord(entry.meta)));
|
|
667
|
+
}
|
|
607
668
|
function isHabitReturnRouteArray(value) {
|
|
608
669
|
return Array.isArray(value)
|
|
609
670
|
&& value.every((entry) => isPlainRecord(entry)
|
|
@@ -633,10 +694,11 @@ function isHabitToolPolicy(value) {
|
|
|
633
694
|
&& typeof value.outwardMessagingAllowed === "boolean";
|
|
634
695
|
}
|
|
635
696
|
function defaultHabitRunSummarySnapshot(receipt) {
|
|
697
|
+
const decisions = decisionsFromHabitRunTraceSteps(receipt.traceSteps);
|
|
636
698
|
if (receipt.errors.length > 0) {
|
|
637
699
|
return {
|
|
638
700
|
summary: `Habit ${receipt.habitName} finished with errors: ${receipt.errors.join("; ")}`,
|
|
639
|
-
decisions
|
|
701
|
+
decisions,
|
|
640
702
|
nextLikelyStep: null,
|
|
641
703
|
};
|
|
642
704
|
}
|
|
@@ -644,7 +706,7 @@ function defaultHabitRunSummarySnapshot(receipt) {
|
|
|
644
706
|
if (surface) {
|
|
645
707
|
return {
|
|
646
708
|
summary: `Habit ${receipt.habitName} surfaced via ${surface.recipient}/${surface.channel}.`,
|
|
647
|
-
decisions
|
|
709
|
+
decisions,
|
|
648
710
|
nextLikelyStep: null,
|
|
649
711
|
};
|
|
650
712
|
}
|
|
@@ -652,13 +714,13 @@ function defaultHabitRunSummarySnapshot(receipt) {
|
|
|
652
714
|
if (produced) {
|
|
653
715
|
return {
|
|
654
716
|
summary: `Habit ${receipt.habitName} produced ${produced.kind}: ${produced.locator}.`,
|
|
655
|
-
decisions
|
|
717
|
+
decisions,
|
|
656
718
|
nextLikelyStep: null,
|
|
657
719
|
};
|
|
658
720
|
}
|
|
659
721
|
return {
|
|
660
722
|
summary: `Habit ${receipt.habitName} finished with ${receipt.outcome}.`,
|
|
661
|
-
decisions
|
|
723
|
+
decisions,
|
|
662
724
|
nextLikelyStep: null,
|
|
663
725
|
};
|
|
664
726
|
}
|
|
@@ -674,7 +736,7 @@ function normalizeHabitRunSummarySnapshot(value, fallback) {
|
|
|
674
736
|
: fallback.nextLikelyStep;
|
|
675
737
|
return {
|
|
676
738
|
summary: (0, session_events_1.capStructuredRecordString)(summary),
|
|
677
|
-
decisions: cappedArray(isStringArray(snapshot.decisions) ? snapshot.decisions : fallback.decisions),
|
|
739
|
+
decisions: cappedArray(isStringArray(snapshot.decisions) && snapshot.decisions.length > 0 ? snapshot.decisions : fallback.decisions),
|
|
678
740
|
nextLikelyStep: nextLikelyStep === null ? null : (0, session_events_1.capStructuredRecordString)(nextLikelyStep),
|
|
679
741
|
};
|
|
680
742
|
}
|
|
@@ -711,6 +773,7 @@ function isHabitRunReceipt(value) {
|
|
|
711
773
|
&& (value.summarySnapshot === undefined || isPlainRecord(value.summarySnapshot))
|
|
712
774
|
&& isProducedRefArray(value.producedRefs)
|
|
713
775
|
&& isHabitSurfaceAttemptArray(value.surfaceAttempts)
|
|
776
|
+
&& (value.traceSteps === undefined || isHabitRunTraceStepArray(value.traceSteps))
|
|
714
777
|
&& isStringArray(value.errors);
|
|
715
778
|
}
|
|
716
779
|
function isLegacyHabitRunReceipt(value) {
|
|
@@ -780,11 +843,53 @@ function normalizeLegacyHabitRunReceipt(receipt) {
|
|
|
780
843
|
summarySnapshot: defaultHabitRunSummarySnapshot(receipt),
|
|
781
844
|
producedRefs: receipt.producedRefs,
|
|
782
845
|
surfaceAttempts: receipt.surfaceAttempts,
|
|
846
|
+
traceSteps: [],
|
|
783
847
|
errors: receipt.errors,
|
|
784
848
|
};
|
|
785
849
|
}
|
|
850
|
+
function capHabitRunTraceRefs(refs) {
|
|
851
|
+
if (!refs || refs.length === 0)
|
|
852
|
+
return undefined;
|
|
853
|
+
return refs.map((ref) => ({
|
|
854
|
+
kind: (0, session_events_1.capStructuredRecordString)(ref.kind),
|
|
855
|
+
locator: (0, session_events_1.capStructuredRecordString)(ref.locator),
|
|
856
|
+
...(ref.label ? { label: (0, session_events_1.capStructuredRecordString)(ref.label) } : {}),
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
function capHabitRunTraceStep(step) {
|
|
860
|
+
const refs = capHabitRunTraceRefs(step.refs);
|
|
861
|
+
const producedRefs = step.producedRefs?.map((ref) => ({ ...ref, locator: (0, session_events_1.capStructuredRecordString)(ref.locator) }));
|
|
862
|
+
const decisions = step.decisions ? cappedArray(step.decisions) : undefined;
|
|
863
|
+
const surfaceAttempt = step.surfaceAttempt
|
|
864
|
+
? {
|
|
865
|
+
...step.surfaceAttempt,
|
|
866
|
+
recipient: (0, session_events_1.capStructuredRecordString)(step.surfaceAttempt.recipient),
|
|
867
|
+
channel: (0, session_events_1.capStructuredRecordString)(step.surfaceAttempt.channel),
|
|
868
|
+
...(step.surfaceAttempt.rawStatus ? { rawStatus: (0, session_events_1.capStructuredRecordString)(step.surfaceAttempt.rawStatus) } : {}),
|
|
869
|
+
...(step.surfaceAttempt.error ? { error: (0, session_events_1.capStructuredRecordString)(step.surfaceAttempt.error) } : {}),
|
|
870
|
+
}
|
|
871
|
+
: undefined;
|
|
872
|
+
return {
|
|
873
|
+
schemaVersion: 1,
|
|
874
|
+
stepId: (0, session_events_1.capStructuredRecordString)(step.stepId),
|
|
875
|
+
kind: step.kind,
|
|
876
|
+
status: step.status,
|
|
877
|
+
at: (0, session_events_1.capStructuredRecordString)(step.at),
|
|
878
|
+
summary: (0, session_events_1.capStructuredRecordString)(step.summary),
|
|
879
|
+
...(refs ? { refs } : {}),
|
|
880
|
+
...(producedRefs && producedRefs.length > 0 ? { producedRefs } : {}),
|
|
881
|
+
...(decisions && decisions.length > 0 ? { decisions } : {}),
|
|
882
|
+
...(surfaceAttempt ? { surfaceAttempt } : {}),
|
|
883
|
+
...(step.error ? { error: (0, session_events_1.capStructuredRecordString)(step.error) } : {}),
|
|
884
|
+
...(step.meta ? { meta: (0, session_events_1.capStructuredRecordStringLeaves)(step.meta) } : {}),
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function normalizeHabitRunTraceSteps(traceSteps) {
|
|
888
|
+
return (traceSteps ?? []).map((step) => capHabitRunTraceStep(step));
|
|
889
|
+
}
|
|
786
890
|
function capHabitRunReceipt(receipt) {
|
|
787
|
-
const
|
|
891
|
+
const traceSteps = normalizeHabitRunTraceSteps(receipt.traceSteps);
|
|
892
|
+
const fallbackSnapshot = defaultHabitRunSummarySnapshot({ ...receipt, traceSteps });
|
|
788
893
|
return {
|
|
789
894
|
...receipt,
|
|
790
895
|
habitName: (0, session_events_1.capStructuredRecordString)(receipt.habitName),
|
|
@@ -822,6 +927,7 @@ function capHabitRunReceipt(receipt) {
|
|
|
822
927
|
...(attempt.rawStatus ? { rawStatus: (0, session_events_1.capStructuredRecordString)(attempt.rawStatus) } : {}),
|
|
823
928
|
...(attempt.error ? { error: (0, session_events_1.capStructuredRecordString)(attempt.error) } : {}),
|
|
824
929
|
})),
|
|
930
|
+
traceSteps,
|
|
825
931
|
errors: receipt.errors.map((error) => (0, session_events_1.capStructuredRecordString)(error)),
|
|
826
932
|
};
|
|
827
933
|
}
|
|
@@ -460,10 +460,11 @@ function computeNextRunAt(habit, endedAt) {
|
|
|
460
460
|
}
|
|
461
461
|
function defaultSummarySnapshot(input) {
|
|
462
462
|
const errors = input.errors ?? [];
|
|
463
|
+
const decisions = (0, flight_recorder_1.decisionsFromHabitRunTraceSteps)(input.traceSteps);
|
|
463
464
|
if (errors.length > 0) {
|
|
464
465
|
return {
|
|
465
466
|
summary: `Habit ${input.habit.name} finished with errors: ${errors.join("; ")}`,
|
|
466
|
-
decisions
|
|
467
|
+
decisions,
|
|
467
468
|
nextLikelyStep: null,
|
|
468
469
|
};
|
|
469
470
|
}
|
|
@@ -471,7 +472,7 @@ function defaultSummarySnapshot(input) {
|
|
|
471
472
|
if (surfaced) {
|
|
472
473
|
return {
|
|
473
474
|
summary: `Habit ${input.habit.name} surfaced via ${surfaced.recipient}/${surfaced.channel}.`,
|
|
474
|
-
decisions
|
|
475
|
+
decisions,
|
|
475
476
|
nextLikelyStep: null,
|
|
476
477
|
};
|
|
477
478
|
}
|
|
@@ -479,13 +480,13 @@ function defaultSummarySnapshot(input) {
|
|
|
479
480
|
if (produced) {
|
|
480
481
|
return {
|
|
481
482
|
summary: `Habit ${input.habit.name} produced ${produced.kind}: ${produced.locator}.`,
|
|
482
|
-
decisions
|
|
483
|
+
decisions,
|
|
483
484
|
nextLikelyStep: null,
|
|
484
485
|
};
|
|
485
486
|
}
|
|
486
487
|
return {
|
|
487
488
|
summary: `Habit ${input.habit.name} finished with ${input.outcome}.`,
|
|
488
|
-
decisions
|
|
489
|
+
decisions,
|
|
489
490
|
nextLikelyStep: null,
|
|
490
491
|
};
|
|
491
492
|
}
|
|
@@ -512,6 +513,7 @@ function buildHabitRunReceipt(input) {
|
|
|
512
513
|
summarySnapshot: input.summarySnapshot ?? defaultSummarySnapshot(input),
|
|
513
514
|
producedRefs: input.producedRefs ?? [],
|
|
514
515
|
surfaceAttempts: input.surfaceAttempts ?? [],
|
|
516
|
+
traceSteps: input.traceSteps ?? [],
|
|
515
517
|
errors: input.errors ?? [],
|
|
516
518
|
};
|
|
517
519
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -572,6 +574,7 @@ function completeHabitRun(input) {
|
|
|
572
574
|
toolPolicy: input.toolPolicy,
|
|
573
575
|
producedRefs,
|
|
574
576
|
surfaceAttempts: input.surfaceAttempts,
|
|
577
|
+
traceSteps: input.traceSteps,
|
|
575
578
|
errors: input.errors,
|
|
576
579
|
summarySnapshot: input.summarySnapshot,
|
|
577
580
|
});
|
|
@@ -86,6 +86,8 @@ function createMailboxHttpReadHooks(options) {
|
|
|
86
86
|
readAgentHabitRun: options.readAgentHabitRun ?? ((agentName, runId) => (0, mailbox_read_1.readHabitRunReceiptView)(agentRoot(agentName), runId)),
|
|
87
87
|
readAgentHabitRunSummaries: options.readAgentHabitRunSummaries ?? ((agentName, habitOptions) => (0, mailbox_read_1.readHabitSessionSummaryListView)(agentRoot(agentName), habitOptions)),
|
|
88
88
|
readAgentHabitRunSummary: options.readAgentHabitRunSummary ?? ((agentName, selector) => (0, mailbox_read_1.readHabitSessionSummaryView)(agentRoot(agentName), selector)),
|
|
89
|
+
readAgentContextPackets: options.readAgentContextPackets ?? ((agentName, packetOptions) => (0, mailbox_read_1.readContextPacketListView)(agentRoot(agentName), packetOptions)),
|
|
90
|
+
readAgentContextPacket: options.readAgentContextPacket ?? ((agentName, packetId) => (0, mailbox_read_1.readContextPacketView)(agentRoot(agentName), packetId)),
|
|
89
91
|
readAgentMail: options.readAgentMail ?? ((agentName) => (0, mailbox_read_1.readMailView)(agentName)),
|
|
90
92
|
readAgentMailMessage: options.readAgentMailMessage ?? ((agentName, messageId) => (0, mailbox_read_1.readMailMessageView)(agentName, messageId)),
|
|
91
93
|
readDaemonHealth: options.readDaemonHealth ?? (() => (0, mailbox_read_1.readDaemonHealthDeep)(options.healthPath)),
|
|
@@ -321,6 +321,29 @@ async function handleAgentRoute(request, response, context) {
|
|
|
321
321
|
(0, mailbox_http_response_1.writeJson)(response, 200, view);
|
|
322
322
|
return;
|
|
323
323
|
}
|
|
324
|
+
if (surface === "context-packets") {
|
|
325
|
+
const limit = parseHabitRunLimit(request.url);
|
|
326
|
+
if (limit === null) {
|
|
327
|
+
(0, mailbox_http_response_1.writeJson)(response, 400, { ok: false, error: "limit must be an integer between 1 and 100" });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const view = limit === undefined
|
|
331
|
+
? options.hooks.readAgentContextPackets(agent)
|
|
332
|
+
: options.hooks.readAgentContextPackets(agent, { limit });
|
|
333
|
+
(0, mailbox_http_response_1.writeJson)(response, 200, view);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (surface.startsWith("context-packets/")) {
|
|
337
|
+
const rawPacketId = surface.slice("context-packets/".length);
|
|
338
|
+
const packetId = decodePathSegment(rawPacketId);
|
|
339
|
+
const view = packetId ? options.hooks.readAgentContextPacket(agent, packetId) : null;
|
|
340
|
+
if (!view) {
|
|
341
|
+
(0, mailbox_http_response_1.writeJson)(response, 404, { ok: false, error: `context packet '${rawPacketId}' not found` });
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
(0, mailbox_http_response_1.writeJson)(response, 200, view);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
324
347
|
if (surface === "mail") {
|
|
325
348
|
(0, mailbox_http_response_1.writeJson)(response, 200, await options.hooks.readAgentMail(agent));
|
|
326
349
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readSelfFixView = exports.readMailboxContinuity = exports.readOrientationView = exports.readObligationDetailView = exports.readNoteDecisionView = exports.readSentinelView = exports.readContextLossGauntletView = exports.readChangesView = exports.readNeedsMeView = exports.readNotesView = exports.readLogView = exports.readHabitView = exports.readHabitRunView = exports.readHabitRunReceiptView = exports.readHabitSessionSummaryView = exports.readHabitSessionSummaryListView = exports.readFriendView = exports.readDeskPrefs = exports.readDaemonHealthDeep = exports.readCodingDeep = exports.readBridgeInventory = exports.readAttentionView = exports.readMailView = exports.readMailMessageView = exports.readSessionTranscript = exports.readSessionInventory = exports.readMailboxMachineState = exports.readMailboxAgentState = exports.readObligationSummary = void 0;
|
|
3
|
+
exports.readSelfFixView = exports.readMailboxContinuity = exports.readOrientationView = exports.readObligationDetailView = exports.readNoteDecisionView = exports.readSentinelView = exports.readContextLossGauntletView = exports.readChangesView = exports.readNeedsMeView = exports.readNotesView = exports.readLogView = exports.readContextPacketView = exports.readContextPacketListView = exports.readHabitView = exports.readHabitRunView = exports.readHabitRunReceiptView = exports.readHabitSessionSummaryView = exports.readHabitSessionSummaryListView = exports.readFriendView = exports.readDeskPrefs = exports.readDaemonHealthDeep = exports.readCodingDeep = exports.readBridgeInventory = exports.readAttentionView = exports.readMailView = exports.readMailMessageView = exports.readSessionTranscript = exports.readSessionInventory = exports.readMailboxMachineState = exports.readMailboxAgentState = exports.readObligationSummary = void 0;
|
|
4
4
|
var agent_machine_1 = require("./readers/agent-machine");
|
|
5
5
|
Object.defineProperty(exports, "readObligationSummary", { enumerable: true, get: function () { return agent_machine_1.readObligationSummary; } });
|
|
6
6
|
Object.defineProperty(exports, "readMailboxAgentState", { enumerable: true, get: function () { return agent_machine_1.readMailboxAgentState; } });
|
|
@@ -23,6 +23,8 @@ Object.defineProperty(exports, "readHabitSessionSummaryView", { enumerable: true
|
|
|
23
23
|
Object.defineProperty(exports, "readHabitRunReceiptView", { enumerable: true, get: function () { return runtime_readers_1.readHabitRunReceiptView; } });
|
|
24
24
|
Object.defineProperty(exports, "readHabitRunView", { enumerable: true, get: function () { return runtime_readers_1.readHabitRunView; } });
|
|
25
25
|
Object.defineProperty(exports, "readHabitView", { enumerable: true, get: function () { return runtime_readers_1.readHabitView; } });
|
|
26
|
+
Object.defineProperty(exports, "readContextPacketListView", { enumerable: true, get: function () { return runtime_readers_1.readContextPacketListView; } });
|
|
27
|
+
Object.defineProperty(exports, "readContextPacketView", { enumerable: true, get: function () { return runtime_readers_1.readContextPacketView; } });
|
|
26
28
|
Object.defineProperty(exports, "readLogView", { enumerable: true, get: function () { return runtime_readers_1.readLogView; } });
|
|
27
29
|
Object.defineProperty(exports, "readNotesView", { enumerable: true, get: function () { return runtime_readers_1.readNotesView; } });
|
|
28
30
|
Object.defineProperty(exports, "readNeedsMeView", { enumerable: true, get: function () { return runtime_readers_1.readNeedsMeView; } });
|
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.readCodingDeep = readCodingDeep;
|
|
37
37
|
exports.readAttentionView = readAttentionView;
|
|
38
|
+
exports.readContextPacketListView = readContextPacketListView;
|
|
39
|
+
exports.readContextPacketView = readContextPacketView;
|
|
38
40
|
exports.readBridgeInventory = readBridgeInventory;
|
|
39
41
|
exports.readDaemonHealthDeep = readDaemonHealthDeep;
|
|
40
42
|
exports.readNotesView = readNotesView;
|
|
@@ -56,6 +58,7 @@ const habit_session_summary_1 = require("../../habits/habit-session-summary");
|
|
|
56
58
|
const identity_1 = require("../../identity");
|
|
57
59
|
const daemon_health_1 = require("../../daemon/daemon-health");
|
|
58
60
|
const flight_recorder_1 = require("../../../arc/flight-recorder");
|
|
61
|
+
const context_packet_ledger_1 = require("../../../senses/context-packet-ledger");
|
|
59
62
|
const shared_1 = require("./shared");
|
|
60
63
|
const agent_machine_1 = require("./agent-machine");
|
|
61
64
|
const sessions_1 = require("./sessions");
|
|
@@ -217,6 +220,12 @@ function readAttentionView(agentName, options = {}) {
|
|
|
217
220
|
returnObligations,
|
|
218
221
|
};
|
|
219
222
|
}
|
|
223
|
+
function readContextPacketListView(agentRoot, options = {}) {
|
|
224
|
+
return (0, context_packet_ledger_1.listSenseContextPacketSummaries)(agentRoot, options);
|
|
225
|
+
}
|
|
226
|
+
function readContextPacketView(agentRoot, packetId) {
|
|
227
|
+
return (0, context_packet_ledger_1.readSenseContextPacketView)(agentRoot, packetId);
|
|
228
|
+
}
|
|
220
229
|
/* v8 ignore start — defensive parsing */
|
|
221
230
|
function readBridgeInventory(agentRoot) {
|
|
222
231
|
const bridgesDir = path.join(agentRoot, "state", "bridges");
|
|
@@ -44,6 +44,7 @@ const run_ledger_1 = require("../heart/run-ledger");
|
|
|
44
44
|
const spend_ledger_1 = require("./spend-ledger");
|
|
45
45
|
const habit_policy_1 = require("./habit-policy");
|
|
46
46
|
const runtime_1 = require("../nerves/runtime");
|
|
47
|
+
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
47
48
|
function sha256Hex(input) {
|
|
48
49
|
return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex");
|
|
49
50
|
}
|
|
@@ -127,13 +128,33 @@ function producedRefsFor(payload) {
|
|
|
127
128
|
const snapshotId = stringField(refreshRecord(payload) ?? {}, "snapshotId");
|
|
128
129
|
return snapshotId ? [{ kind: "none", locator: `state/rsvp/snapshots/${snapshotId}.json` }] : [];
|
|
129
130
|
}
|
|
131
|
+
function outboundAction(payload) {
|
|
132
|
+
const refresh = refreshRecord(payload);
|
|
133
|
+
const decision = refresh?.outboundDecision;
|
|
134
|
+
if (!decision || typeof decision !== "object" || Array.isArray(decision))
|
|
135
|
+
return "unknown";
|
|
136
|
+
return stringField(decision, "action") ?? "unknown";
|
|
137
|
+
}
|
|
130
138
|
function surfaceAttemptsFor(payload, requestedSend, errorMessage) {
|
|
131
139
|
if (payload.sendAllowed === true) {
|
|
140
|
+
const delivery = (refreshRecord(payload)?.delivery ?? {});
|
|
141
|
+
const rawStatus = stringField(delivery, "status") ?? stringField(delivery, "result");
|
|
142
|
+
if (rawStatus === "failed" || rawStatus === "error") {
|
|
143
|
+
return [{
|
|
144
|
+
recipient: "rsvp",
|
|
145
|
+
channel: "bluebubbles",
|
|
146
|
+
reason: "status",
|
|
147
|
+
result: "failed",
|
|
148
|
+
rawStatus,
|
|
149
|
+
error: stringField(delivery, "error") ?? stringField(delivery, "message") ?? rawStatus,
|
|
150
|
+
}];
|
|
151
|
+
}
|
|
132
152
|
return [{
|
|
133
153
|
recipient: "rsvp",
|
|
134
154
|
channel: "bluebubbles",
|
|
135
155
|
reason: "status",
|
|
136
156
|
result: "sent",
|
|
157
|
+
...(rawStatus ? { rawStatus } : {}),
|
|
137
158
|
}];
|
|
138
159
|
}
|
|
139
160
|
if (requestedSend && errorMessage) {
|
|
@@ -153,6 +174,140 @@ function payloadError(payload) {
|
|
|
153
174
|
}
|
|
154
175
|
return null;
|
|
155
176
|
}
|
|
177
|
+
function traceStatusForSurfaceAttempt(attempt) {
|
|
178
|
+
if (!attempt)
|
|
179
|
+
return "skipped";
|
|
180
|
+
if (attempt.result === "failed")
|
|
181
|
+
return "failed";
|
|
182
|
+
if (attempt.result === "blocked" || attempt.result === "unavailable")
|
|
183
|
+
return "blocked";
|
|
184
|
+
return "succeeded";
|
|
185
|
+
}
|
|
186
|
+
function nativeRsvpTraceSteps(input) {
|
|
187
|
+
const refresh = refreshRecord(input.payload);
|
|
188
|
+
const snapshotId = stringField(refresh ?? {}, "snapshotId");
|
|
189
|
+
const reportText = stringField(refresh ?? {}, "reportText");
|
|
190
|
+
const action = outboundAction(input.payload);
|
|
191
|
+
const firstAttempt = input.surfaceAttempts[0];
|
|
192
|
+
const snapshotLocator = snapshotId ? `state/rsvp/snapshots/${snapshotId}.json` : null;
|
|
193
|
+
const decisions = [
|
|
194
|
+
`mode=${input.mode}`,
|
|
195
|
+
`sendAllowed=${String(input.sendAllowed)}`,
|
|
196
|
+
`outboundAction=${action}`,
|
|
197
|
+
];
|
|
198
|
+
return [
|
|
199
|
+
{
|
|
200
|
+
schemaVersion: 1,
|
|
201
|
+
stepId: "trigger",
|
|
202
|
+
kind: "trigger",
|
|
203
|
+
status: "succeeded",
|
|
204
|
+
at: input.startedAt,
|
|
205
|
+
summary: `${input.trigger} triggered ${input.habitName}.`,
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
schemaVersion: 1,
|
|
209
|
+
stepId: "habit-definition",
|
|
210
|
+
kind: "habit_definition",
|
|
211
|
+
status: "succeeded",
|
|
212
|
+
at: input.startedAt,
|
|
213
|
+
summary: `Loaded habit definition for ${input.habitName}.`,
|
|
214
|
+
refs: [{ kind: "habit_definition", locator: `habits/${input.habitName}.md`, label: input.habitName }],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
schemaVersion: 1,
|
|
218
|
+
stepId: "fetch-refresh",
|
|
219
|
+
kind: "fetch",
|
|
220
|
+
status: input.errors.length > 0 ? "failed" : "succeeded",
|
|
221
|
+
at: input.endedAt,
|
|
222
|
+
summary: `Ran RSVP refresh in ${input.mode} mode.`,
|
|
223
|
+
refs: [{ kind: "source", locator: `rsvp/${input.source}` }],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
schemaVersion: 1,
|
|
227
|
+
stepId: "snapshot",
|
|
228
|
+
kind: "snapshot",
|
|
229
|
+
status: snapshotLocator ? "succeeded" : "skipped",
|
|
230
|
+
at: input.endedAt,
|
|
231
|
+
summary: snapshotLocator ? "Recorded the RSVP snapshot reference." : "No RSVP snapshot reference was returned.",
|
|
232
|
+
...(snapshotLocator ? { refs: [{ kind: "snapshot", locator: snapshotLocator }] } : {}),
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
schemaVersion: 1,
|
|
236
|
+
stepId: "render",
|
|
237
|
+
kind: "render",
|
|
238
|
+
status: reportText ? "succeeded" : "skipped",
|
|
239
|
+
at: input.endedAt,
|
|
240
|
+
summary: reportText ? "Rendered RSVP update text." : "No rendered RSVP update text was returned.",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
schemaVersion: 1,
|
|
244
|
+
stepId: "decision",
|
|
245
|
+
kind: "decision",
|
|
246
|
+
status: input.errors.length > 0 ? "blocked" : "succeeded",
|
|
247
|
+
at: input.endedAt,
|
|
248
|
+
summary: `RSVP outbound decision: ${action}.`,
|
|
249
|
+
decisions,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
schemaVersion: 1,
|
|
253
|
+
stepId: "produced-ref",
|
|
254
|
+
kind: "produced_ref",
|
|
255
|
+
status: input.producedRefs.length > 0 ? "succeeded" : "skipped",
|
|
256
|
+
at: input.endedAt,
|
|
257
|
+
summary: input.producedRefs.length > 0 ? "Recorded produced RSVP refs." : "No separate produced refs were recorded.",
|
|
258
|
+
...(input.producedRefs.length > 0 ? { producedRefs: input.producedRefs } : {}),
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
schemaVersion: 1,
|
|
262
|
+
stepId: "surface-attempt",
|
|
263
|
+
kind: "surface_attempt",
|
|
264
|
+
status: traceStatusForSurfaceAttempt(firstAttempt),
|
|
265
|
+
at: input.endedAt,
|
|
266
|
+
summary: firstAttempt ? `Surface attempt ${firstAttempt.result} via ${firstAttempt.channel}.` : "No surface attempt was needed.",
|
|
267
|
+
...(firstAttempt ? { surfaceAttempt: firstAttempt } : {}),
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
schemaVersion: 1,
|
|
271
|
+
stepId: "send",
|
|
272
|
+
kind: "send",
|
|
273
|
+
status: input.sendAllowed
|
|
274
|
+
? traceStatusForSurfaceAttempt(firstAttempt)
|
|
275
|
+
: "skipped",
|
|
276
|
+
at: input.endedAt,
|
|
277
|
+
summary: input.sendAllowed ? "Live send was allowed for this run." : "Live send was not allowed for this run.",
|
|
278
|
+
...(firstAttempt ? { surfaceAttempt: firstAttempt } : {}),
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
schemaVersion: 1,
|
|
282
|
+
stepId: "ledger",
|
|
283
|
+
kind: "ledger",
|
|
284
|
+
status: "succeeded",
|
|
285
|
+
at: input.endedAt,
|
|
286
|
+
summary: "Recorded native RSVP run ledger evidence.",
|
|
287
|
+
refs: [
|
|
288
|
+
{ kind: "ledger", locator: "state/run-ledger/runs.jsonl" },
|
|
289
|
+
{ kind: "ledger", locator: "state/rsvp/spend-ledger.json" },
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
schemaVersion: 1,
|
|
294
|
+
stepId: "error",
|
|
295
|
+
kind: "error",
|
|
296
|
+
status: input.errors.length > 0 ? "failed" : "skipped",
|
|
297
|
+
at: input.endedAt,
|
|
298
|
+
summary: input.errors.length > 0 ? "RSVP refresh returned an error." : "No RSVP error happened.",
|
|
299
|
+
...(input.errors[0] ? { error: input.errors[0] } : {}),
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
schemaVersion: 1,
|
|
303
|
+
stepId: "complete",
|
|
304
|
+
kind: "complete",
|
|
305
|
+
status: input.lifecycle === "completed" ? "succeeded" : "failed",
|
|
306
|
+
at: input.endedAt,
|
|
307
|
+
summary: `Native RSVP habit ${input.lifecycle}.`,
|
|
308
|
+
},
|
|
309
|
+
];
|
|
310
|
+
}
|
|
156
311
|
function recordNativeRunLedger(input) {
|
|
157
312
|
const target = {
|
|
158
313
|
habitName: input.habitName,
|
|
@@ -247,6 +402,7 @@ async function runNativeRsvpHabit(input) {
|
|
|
247
402
|
const lifecycle = errorMessage ? "error" : "completed";
|
|
248
403
|
const surfaceAttempts = surfaceAttemptsFor(payload, policy.sendAllowed, errorMessage);
|
|
249
404
|
const errors = errorMessage ? [errorMessage] : [];
|
|
405
|
+
const producedRefs = producedRefsFor(payload);
|
|
250
406
|
recordNativeRunLedger({
|
|
251
407
|
agentRoot,
|
|
252
408
|
agent: input.agent,
|
|
@@ -258,6 +414,20 @@ async function runNativeRsvpHabit(input) {
|
|
|
258
414
|
endedAt,
|
|
259
415
|
lifecycle,
|
|
260
416
|
});
|
|
417
|
+
const traceSteps = nativeRsvpTraceSteps({
|
|
418
|
+
habitName: input.habitName,
|
|
419
|
+
trigger: input.trigger,
|
|
420
|
+
mode: habit.rsvp.mode,
|
|
421
|
+
source: habit.rsvp.source,
|
|
422
|
+
sendAllowed: policy.sendAllowed,
|
|
423
|
+
startedAt,
|
|
424
|
+
endedAt,
|
|
425
|
+
payload,
|
|
426
|
+
producedRefs,
|
|
427
|
+
surfaceAttempts,
|
|
428
|
+
errors,
|
|
429
|
+
lifecycle,
|
|
430
|
+
});
|
|
261
431
|
const completion = (0, habit_session_1.completeHabitRun)({
|
|
262
432
|
agentRoot,
|
|
263
433
|
habit,
|
|
@@ -268,17 +438,15 @@ async function runNativeRsvpHabit(input) {
|
|
|
268
438
|
operationId: `rsvp-native:${input.trigger}:${input.occurrenceId ?? runId}`,
|
|
269
439
|
permissionEnvelope: permissionEnvelope(policy.sendAllowed),
|
|
270
440
|
toolPolicy: toolPolicy(policy.sendAllowed),
|
|
271
|
-
producedRefs
|
|
441
|
+
producedRefs,
|
|
272
442
|
surfaceAttempts,
|
|
443
|
+
traceSteps,
|
|
273
444
|
errors,
|
|
274
445
|
summarySnapshot: {
|
|
275
446
|
summary: errorMessage
|
|
276
447
|
? `Native RSVP habit failed: ${errorMessage}`
|
|
277
448
|
: "Native RSVP habit completed.",
|
|
278
|
-
decisions:
|
|
279
|
-
`mode=${habit.rsvp.mode}`,
|
|
280
|
-
`sendAllowed=${String(policy.sendAllowed)}`,
|
|
281
|
-
],
|
|
449
|
+
decisions: (0, flight_recorder_1.decisionsFromHabitRunTraceSteps)(traceSteps),
|
|
282
450
|
nextLikelyStep: null,
|
|
283
451
|
},
|
|
284
452
|
});
|
|
@@ -45,6 +45,23 @@ function messageToContextInput(event, chatGuidHash) {
|
|
|
45
45
|
},
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
function normalizeKnownMessageText(value) {
|
|
49
|
+
return value.replace(/\s+/g, " ").trim().toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
function hasKnownMessageText(candidate, knownTexts) {
|
|
52
|
+
if (knownTexts.size === 0)
|
|
53
|
+
return false;
|
|
54
|
+
const body = normalizeKnownMessageText(candidate.textForAgent || candidate.text);
|
|
55
|
+
if (!body)
|
|
56
|
+
return true;
|
|
57
|
+
if (knownTexts.has(body))
|
|
58
|
+
return true;
|
|
59
|
+
for (const known of knownTexts) {
|
|
60
|
+
if (body.length >= 12 && known.includes(body))
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
48
65
|
async function buildBlueBubblesContextPacket(input) {
|
|
49
66
|
if (!Number.isFinite(input.event.timestamp))
|
|
50
67
|
return null;
|
|
@@ -53,6 +70,9 @@ async function buildBlueBubblesContextPacket(input) {
|
|
|
53
70
|
const event = input.event;
|
|
54
71
|
const chatGuidHash = blueBubblesContextChatKeyHash(event);
|
|
55
72
|
const anchorTimestamp = new Date(event.timestamp).toISOString();
|
|
73
|
+
const knownTexts = new Set((input.knownMessageTexts ?? [])
|
|
74
|
+
.map(normalizeKnownMessageText)
|
|
75
|
+
.filter((value) => value.length > 0));
|
|
56
76
|
const candidates = await input.client.listRecentMessages({
|
|
57
77
|
beforeTimestamp: event.timestamp,
|
|
58
78
|
limit: exports.BLUEBUBBLES_CONTEXT_PACKET_LIMIT,
|
|
@@ -65,7 +85,8 @@ async function buildBlueBubblesContextPacket(input) {
|
|
|
65
85
|
.filter((candidate) => isSameBlueBubblesChat(candidate, event))
|
|
66
86
|
.filter((candidate) => candidate.messageGuid !== event.messageGuid)
|
|
67
87
|
.filter((candidate) => candidate.timestamp <= event.timestamp)
|
|
68
|
-
.filter((candidate) => event.timestamp - candidate.timestamp <= exports.BLUEBUBBLES_CONTEXT_PACKET_MAX_AGE_MS)
|
|
88
|
+
.filter((candidate) => event.timestamp - candidate.timestamp <= exports.BLUEBUBBLES_CONTEXT_PACKET_MAX_AGE_MS)
|
|
89
|
+
.filter((candidate) => !hasKnownMessageText(candidate, knownTexts));
|
|
69
90
|
if (history.length === 0)
|
|
70
91
|
return null;
|
|
71
92
|
const packet = (0, context_packets_1.buildSenseContextPacket)({
|
|
@@ -623,12 +623,18 @@ function insertEphemeralContextMessages(messages, contextMessages) {
|
|
|
623
623
|
...messages.slice(insertionIndex),
|
|
624
624
|
];
|
|
625
625
|
}
|
|
626
|
+
function knownProviderMessageTexts(messages) {
|
|
627
|
+
return messages
|
|
628
|
+
.map((message) => extractMessageText(message.content))
|
|
629
|
+
.map((text) => text.trim())
|
|
630
|
+
.filter((text) => text.length > 0);
|
|
631
|
+
}
|
|
626
632
|
async function buildBlueBubblesContextMessages(input) {
|
|
627
633
|
if (input.event.kind !== "message")
|
|
628
|
-
return [];
|
|
634
|
+
return { messages: [], contextPacketIds: [] };
|
|
629
635
|
const event = input.event;
|
|
630
636
|
if (!Number.isFinite(event.timestamp))
|
|
631
|
-
return [];
|
|
637
|
+
return { messages: [], contextPacketIds: [] };
|
|
632
638
|
const chatGuidHash = (0, context_packet_1.blueBubblesContextChatKeyHash)(event);
|
|
633
639
|
const anchorTimestamp = new Date(event.timestamp).toISOString();
|
|
634
640
|
try {
|
|
@@ -636,9 +642,10 @@ async function buildBlueBubblesContextMessages(input) {
|
|
|
636
642
|
agentName: input.agentName,
|
|
637
643
|
client: input.client,
|
|
638
644
|
event,
|
|
645
|
+
knownMessageTexts: knownProviderMessageTexts(input.knownMessages ?? []),
|
|
639
646
|
});
|
|
640
647
|
if (!result)
|
|
641
|
-
return [];
|
|
648
|
+
return { messages: [], contextPacketIds: [] };
|
|
642
649
|
const { packet, rendered, historyCount } = result;
|
|
643
650
|
(0, context_packet_ledger_1.writeSenseContextPacket)(input.agentRoot, packet);
|
|
644
651
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -651,7 +658,10 @@ async function buildBlueBubblesContextMessages(input) {
|
|
|
651
658
|
contextMessages: historyCount,
|
|
652
659
|
},
|
|
653
660
|
});
|
|
654
|
-
return
|
|
661
|
+
return {
|
|
662
|
+
messages: [{ role: "system", content: rendered.text }],
|
|
663
|
+
contextPacketIds: [packet.packetId],
|
|
664
|
+
};
|
|
655
665
|
}
|
|
656
666
|
catch (error) {
|
|
657
667
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -671,9 +681,12 @@ async function buildBlueBubblesContextMessages(input) {
|
|
|
671
681
|
maxAgeMs: 24 * 60 * 60 * 1000,
|
|
672
682
|
});
|
|
673
683
|
if (!fallback)
|
|
674
|
-
return [];
|
|
684
|
+
return { messages: [], contextPacketIds: [] };
|
|
675
685
|
const rendered = (0, context_packets_1.renderSenseContextPacketForPrompt)(fallback);
|
|
676
|
-
return
|
|
686
|
+
return {
|
|
687
|
+
messages: [{ role: "system", content: rendered.text }],
|
|
688
|
+
contextPacketIds: [fallback.packetId],
|
|
689
|
+
};
|
|
677
690
|
}
|
|
678
691
|
}
|
|
679
692
|
function createReplyTargetController(event) {
|
|
@@ -1468,6 +1481,10 @@ async function handleBlueBubblesNormalizedEvent(event, resolvedDeps, source, opt
|
|
|
1468
1481
|
if (typeof timeoutTimer.unref === "function") {
|
|
1469
1482
|
timeoutTimer.unref();
|
|
1470
1483
|
}
|
|
1484
|
+
let preparedBlueBubblesContext = {
|
|
1485
|
+
messages: [],
|
|
1486
|
+
contextPacketIds: [],
|
|
1487
|
+
};
|
|
1471
1488
|
const turnPromise = (0, pipeline_1.handleInboundTurn)({
|
|
1472
1489
|
channel: "bluebubbles",
|
|
1473
1490
|
sessionKey: event.chat.sessionKey,
|
|
@@ -1494,35 +1511,44 @@ async function handleBlueBubblesNormalizedEvent(event, resolvedDeps, source, opt
|
|
|
1494
1511
|
enforceTrustGate: trust_gate_1.enforceTrustGate,
|
|
1495
1512
|
drainPending: pending_1.drainPending,
|
|
1496
1513
|
drainDeferredReturns: (deferredFriendId) => (0, pending_1.drainDeferredReturns)(resolvedDeps.getAgentName(), deferredFriendId),
|
|
1497
|
-
|
|
1498
|
-
|
|
1514
|
+
prepareRunAgentOptions: async ({ messages, runAgentOptions }) => {
|
|
1515
|
+
preparedBlueBubblesContext = await buildBlueBubblesContextMessages({
|
|
1499
1516
|
agentName,
|
|
1500
1517
|
agentRoot: (0, identity_1.getAgentRoot)(),
|
|
1501
1518
|
client,
|
|
1502
1519
|
event,
|
|
1520
|
+
knownMessages: messages,
|
|
1503
1521
|
});
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
...
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
+
if (preparedBlueBubblesContext.contextPacketIds.length === 0)
|
|
1523
|
+
return undefined;
|
|
1524
|
+
return {
|
|
1525
|
+
contextPacketIds: [
|
|
1526
|
+
...(runAgentOptions.contextPacketIds ?? []),
|
|
1527
|
+
...preparedBlueBubblesContext.contextPacketIds,
|
|
1528
|
+
],
|
|
1529
|
+
};
|
|
1530
|
+
},
|
|
1531
|
+
runAgent: async (msgs, cb, channel, sig, opts) => resolvedDeps.runAgent(insertEphemeralContextMessages(msgs, preparedBlueBubblesContext.messages), cb, channel, sig, {
|
|
1532
|
+
...opts,
|
|
1533
|
+
toolContext: {
|
|
1534
|
+
/* v8 ignore next -- default no-op signin; pipeline provides the real one @preserve */
|
|
1535
|
+
signin: async () => undefined,
|
|
1536
|
+
...opts?.toolContext,
|
|
1537
|
+
summarize,
|
|
1538
|
+
bluebubblesReplyTarget: {
|
|
1539
|
+
setSelection: (selection) => replyTarget.setSelection(selection),
|
|
1540
|
+
},
|
|
1541
|
+
codingFeedback: {
|
|
1542
|
+
send: async (message) => {
|
|
1543
|
+
await client.sendText({
|
|
1544
|
+
chat: event.chat,
|
|
1545
|
+
text: message,
|
|
1546
|
+
replyToMessageGuid: replyTarget.getReplyToMessageGuid(),
|
|
1547
|
+
});
|
|
1522
1548
|
},
|
|
1523
1549
|
},
|
|
1524
|
-
}
|
|
1525
|
-
},
|
|
1550
|
+
},
|
|
1551
|
+
}),
|
|
1526
1552
|
postTurn: (turnMessages, sessionPathArg, usage, hooks, state) => {
|
|
1527
1553
|
const prepared = resolvedDeps.postTurnTrim(turnMessages, usage, hooks);
|
|
1528
1554
|
resolvedDeps.deferPostTurnPersist(sessionPathArg, prepared, usage, state);
|
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.writeSenseContextPacket = writeSenseContextPacket;
|
|
37
37
|
exports.readSenseContextLedger = readSenseContextLedger;
|
|
38
|
+
exports.listSenseContextPacketSummaries = listSenseContextPacketSummaries;
|
|
39
|
+
exports.readSenseContextPacketView = readSenseContextPacketView;
|
|
38
40
|
exports.readLatestVisibleSenseContextPacket = readLatestVisibleSenseContextPacket;
|
|
39
41
|
exports.compactSenseContextPacketReceipts = compactSenseContextPacketReceipts;
|
|
40
42
|
const fs = __importStar(require("node:fs"));
|
|
@@ -44,6 +46,9 @@ const context_packets_1 = require("./context-packets");
|
|
|
44
46
|
function contextPacketRoot(agentRoot, sense) {
|
|
45
47
|
return path.join(agentRoot, "state", "senses", "context-packets", sense);
|
|
46
48
|
}
|
|
49
|
+
function contextPacketBaseRoot(agentRoot) {
|
|
50
|
+
return path.join(agentRoot, "state", "senses", "context-packets");
|
|
51
|
+
}
|
|
47
52
|
function packetPath(agentRoot, packet) {
|
|
48
53
|
const month = packet.anchorTimestamp.slice(0, 7) || "unknown";
|
|
49
54
|
return path.join(contextPacketRoot(agentRoot, packet.sense), month, `${packet.packetId}.json`);
|
|
@@ -181,6 +186,127 @@ function readSenseContextLedger(agentRoot, sense) {
|
|
|
181
186
|
});
|
|
182
187
|
return rows;
|
|
183
188
|
}
|
|
189
|
+
function safeContextPacketLimit(limit) {
|
|
190
|
+
return Number.isInteger(limit) && typeof limit === "number" && limit >= 1 && limit <= 100 ? limit : 20;
|
|
191
|
+
}
|
|
192
|
+
function discoverContextPacketSenses(agentRoot) {
|
|
193
|
+
const root = contextPacketBaseRoot(agentRoot);
|
|
194
|
+
if (!fs.existsSync(root))
|
|
195
|
+
return [];
|
|
196
|
+
return fs.readdirSync(root)
|
|
197
|
+
.filter((entry) => {
|
|
198
|
+
try {
|
|
199
|
+
return fs.statSync(path.join(root, entry)).isDirectory();
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
.sort();
|
|
206
|
+
}
|
|
207
|
+
function summarizeLedgerRow(row) {
|
|
208
|
+
return {
|
|
209
|
+
packetId: row.packetId,
|
|
210
|
+
sense: row.sense,
|
|
211
|
+
agent: row.agent,
|
|
212
|
+
chatKeyHash: row.chatKeyHash,
|
|
213
|
+
anchorMessageGuid: row.anchorMessageGuid,
|
|
214
|
+
anchorTimestamp: row.anchorTimestamp,
|
|
215
|
+
createdAt: row.createdAt,
|
|
216
|
+
messageCount: row.messageCount,
|
|
217
|
+
sourceRefs: row.sourceRefs,
|
|
218
|
+
bodyHashes: row.bodyHashes,
|
|
219
|
+
rawBodyStored: row.rawBodyStored,
|
|
220
|
+
privacyClass: row.privacyClass,
|
|
221
|
+
omittedMessages: row.omittedMessages,
|
|
222
|
+
truncatedMessages: row.truncatedMessages,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function readAllContextPacketRows(agentRoot, sense) {
|
|
226
|
+
const senses = sense ? [sense] : discoverContextPacketSenses(agentRoot);
|
|
227
|
+
return senses.flatMap((entry) => readSenseContextLedger(agentRoot, entry));
|
|
228
|
+
}
|
|
229
|
+
function timestampSortValue(value) {
|
|
230
|
+
const parsed = Date.parse(value);
|
|
231
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
232
|
+
}
|
|
233
|
+
function listSenseContextPacketSummaries(agentRoot, options = {}) {
|
|
234
|
+
const limit = safeContextPacketLimit(options.limit);
|
|
235
|
+
const rows = readAllContextPacketRows(agentRoot, options.sense)
|
|
236
|
+
.sort((left, right) => timestampSortValue(right.createdAt || right.anchorTimestamp) - timestampSortValue(left.createdAt || left.anchorTimestamp));
|
|
237
|
+
return {
|
|
238
|
+
totalCount: rows.length,
|
|
239
|
+
limit,
|
|
240
|
+
items: rows.slice(0, limit).map(summarizeLedgerRow),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function isSafeContextPacketId(packetId) {
|
|
244
|
+
return /^scp_[A-Za-z0-9_-]+$/.test(packetId);
|
|
245
|
+
}
|
|
246
|
+
function pathInsideContextPacketRoot(agentRoot, sense, filePath) {
|
|
247
|
+
const root = path.resolve(contextPacketRoot(agentRoot, sense));
|
|
248
|
+
const resolved = path.resolve(filePath);
|
|
249
|
+
return resolved === root || resolved.startsWith(`${root}${path.sep}`);
|
|
250
|
+
}
|
|
251
|
+
function redactPreview(value) {
|
|
252
|
+
return value
|
|
253
|
+
.replace(/\bpassword=[^\s]+/gi, "password=[redacted]")
|
|
254
|
+
.replace(/\b(token|api[_-]?key|secret)=[^\s]+/gi, "$1=[redacted]");
|
|
255
|
+
}
|
|
256
|
+
function viewMessage(message) {
|
|
257
|
+
const { chatGuid: _chatGuid, ...sourceRef } = message.sourceRef;
|
|
258
|
+
return {
|
|
259
|
+
timestamp: message.timestamp,
|
|
260
|
+
authorLabel: message.authorLabel,
|
|
261
|
+
bodyHash: message.bodyHash,
|
|
262
|
+
bodyPreview: redactPreview(message.bodyPreview),
|
|
263
|
+
sourceRef,
|
|
264
|
+
renderedSourceRef: message.renderedSourceRef,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function emitContextPacketReadWarning(packetId, reason) {
|
|
268
|
+
(0, runtime_1.emitNervesEvent)({
|
|
269
|
+
level: "warn",
|
|
270
|
+
component: "senses",
|
|
271
|
+
event: "senses.context_packet_read_error",
|
|
272
|
+
message: "failed to read sense context packet view",
|
|
273
|
+
meta: { packetId, reason },
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function readSenseContextPacketView(agentRoot, packetId) {
|
|
277
|
+
if (!isSafeContextPacketId(packetId))
|
|
278
|
+
return null;
|
|
279
|
+
const row = readAllContextPacketRows(agentRoot).find((entry) => entry.packetId === packetId);
|
|
280
|
+
if (!row)
|
|
281
|
+
return null;
|
|
282
|
+
if (!pathInsideContextPacketRoot(agentRoot, row.sense, row.packetPath)) {
|
|
283
|
+
emitContextPacketReadWarning(packetId, "packet path escaped context-packet root");
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
if (!fs.existsSync(row.packetPath))
|
|
287
|
+
return null;
|
|
288
|
+
try {
|
|
289
|
+
const packet = JSON.parse(fs.readFileSync(row.packetPath, "utf-8"));
|
|
290
|
+
if (packet.packetId !== packetId || !Array.isArray(packet.messages))
|
|
291
|
+
return null;
|
|
292
|
+
return {
|
|
293
|
+
row: summarizeLedgerRow(row),
|
|
294
|
+
packet: {
|
|
295
|
+
packetId,
|
|
296
|
+
sense: typeof packet.sense === "string" ? packet.sense : row.sense,
|
|
297
|
+
agent: typeof packet.agent === "string" ? packet.agent : row.agent,
|
|
298
|
+
privacyClass: packet.privacyClass === "private-runtime" ? packet.privacyClass : "private-runtime",
|
|
299
|
+
messages: packet.messages.map((message) => viewMessage(message)),
|
|
300
|
+
omittedMessages: typeof packet.omittedMessages === "number" ? packet.omittedMessages : row.omittedMessages,
|
|
301
|
+
truncatedMessages: typeof packet.truncatedMessages === "number" ? packet.truncatedMessages : row.truncatedMessages,
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
emitContextPacketReadWarning(packetId, error instanceof Error ? error.message : String(error));
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
184
310
|
function timestampMs(value) {
|
|
185
311
|
return Date.parse(value);
|
|
186
312
|
}
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -369,6 +369,36 @@ let _lastSessionKey = null;
|
|
|
369
369
|
function runAgentOptionContextPacketIds(options) {
|
|
370
370
|
return Array.isArray(options.contextPacketIds) ? options.contextPacketIds : [];
|
|
371
371
|
}
|
|
372
|
+
function mergeRunAgentContextPacketIds(left, right) {
|
|
373
|
+
const merged = [
|
|
374
|
+
...(Array.isArray(left) ? left : []),
|
|
375
|
+
...(Array.isArray(right) ? right : []),
|
|
376
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
377
|
+
return merged.length > 0 ? [...new Set(merged)] : undefined;
|
|
378
|
+
}
|
|
379
|
+
function mergePreparedRunAgentOptions(base, prepared) {
|
|
380
|
+
if (!prepared)
|
|
381
|
+
return base;
|
|
382
|
+
const contextPacketIds = mergeRunAgentContextPacketIds(base.contextPacketIds, prepared.contextPacketIds);
|
|
383
|
+
const { contextPacketIds: _baseContextPacketIds, ...baseOptions } = base;
|
|
384
|
+
const { contextPacketIds: _preparedContextPacketIds, ...preparedOptions } = prepared;
|
|
385
|
+
const merged = {
|
|
386
|
+
...baseOptions,
|
|
387
|
+
...preparedOptions,
|
|
388
|
+
...(contextPacketIds ? { contextPacketIds } : {}),
|
|
389
|
+
};
|
|
390
|
+
if (prepared.toolContext) {
|
|
391
|
+
const toolContext = {
|
|
392
|
+
...base.toolContext,
|
|
393
|
+
...prepared.toolContext,
|
|
394
|
+
};
|
|
395
|
+
merged.toolContext = {
|
|
396
|
+
...toolContext,
|
|
397
|
+
signin: toolContext.signin ?? (async () => undefined),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
return merged;
|
|
401
|
+
}
|
|
372
402
|
function buildInboundRunLedgerInput(input) {
|
|
373
403
|
const target = {
|
|
374
404
|
channel: input.channel,
|
|
@@ -822,7 +852,7 @@ async function handleInboundTurn(input) {
|
|
|
822
852
|
const existingToolContext = input.runAgentOptions?.toolContext;
|
|
823
853
|
const currentUserMessage = existingToolContext?.currentUserMessage
|
|
824
854
|
?? latestUserAuthoredText(input.messages, input.continuityIngressTexts);
|
|
825
|
-
|
|
855
|
+
let runAgentOptions = {
|
|
826
856
|
...input.runAgentOptions,
|
|
827
857
|
...(orientationFrame ? { orientationFrame } : {}),
|
|
828
858
|
...(liveLatencyMode ? { skipKeptNotes: true } : {}),
|
|
@@ -856,6 +886,12 @@ async function handleInboundTurn(input) {
|
|
|
856
886
|
...(orientationFrame ? { orientationFrame } : {}),
|
|
857
887
|
},
|
|
858
888
|
};
|
|
889
|
+
runAgentOptions = mergePreparedRunAgentOptions(runAgentOptions, await input.prepareRunAgentOptions?.({
|
|
890
|
+
messages: sessionMessages,
|
|
891
|
+
currentUserMessages,
|
|
892
|
+
resolvedContext,
|
|
893
|
+
runAgentOptions,
|
|
894
|
+
}));
|
|
859
895
|
const runLedger = prepareInboundRunLedger({
|
|
860
896
|
channel: input.channel,
|
|
861
897
|
senseType: input.capabilities.senseType,
|