@openclawbrain/openclaw 0.2.2 → 0.3.0
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/LICENSE +201 -0
- package/README.md +10 -0
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +73 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/extension/runtime-guard.d.ts +61 -0
- package/dist/extension/runtime-guard.js +230 -0
- package/dist/extension/runtime-guard.js.map +1 -0
- package/dist/src/cli.d.ts +66 -4
- package/dist/src/cli.js +1845 -241
- package/dist/src/cli.js.map +1 -1
- package/dist/src/daemon.d.ts +7 -4
- package/dist/src/daemon.js +311 -28
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/index.d.ts +213 -4
- package/dist/src/index.js +1151 -157
- package/dist/src/index.js.map +1 -1
- package/dist/src/learning-spine.d.ts +2 -1
- package/dist/src/learning-spine.js +8 -0
- package/dist/src/learning-spine.js.map +1 -1
- package/dist/src/local-session-passive-learning.d.ts +1 -0
- package/dist/src/local-session-passive-learning.js +97 -7
- package/dist/src/local-session-passive-learning.js.map +1 -1
- package/dist/src/ollama-client.d.ts +46 -0
- package/dist/src/ollama-client.js +231 -0
- package/dist/src/ollama-client.js.map +1 -0
- package/dist/src/provider-config.d.ts +28 -0
- package/dist/src/provider-config.js +150 -0
- package/dist/src/provider-config.js.map +1 -0
- package/dist/src/resolve-activation-root.d.ts +3 -3
- package/dist/src/resolve-activation-root.js +105 -35
- package/dist/src/resolve-activation-root.js.map +1 -1
- package/dist/src/session-store.d.ts +18 -0
- package/dist/src/session-store.js +40 -0
- package/dist/src/session-store.js.map +1 -1
- package/dist/src/session-tail.d.ts +6 -3
- package/dist/src/session-tail.js +35 -4
- package/dist/src/session-tail.js.map +1 -1
- package/dist/src/shadow-extension-proof.d.ts +40 -0
- package/dist/src/shadow-extension-proof.js +214 -0
- package/dist/src/shadow-extension-proof.js.map +1 -0
- package/dist/src/teacher-labeler.d.ts +50 -0
- package/dist/src/teacher-labeler.js +424 -0
- package/dist/src/teacher-labeler.js.map +1 -0
- package/extension/index.ts +74 -35
- package/extension/runtime-guard.ts +353 -0
- package/package.json +13 -13
package/dist/src/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import { classifyFeedbackSignalContent, describeNormalizedEventExportObservabili
|
|
|
8
8
|
import { DEFAULT_TEACHER_SUPERVISION_STALE_AFTER_MS, advanceAlwaysOnLearningRuntime, buildTeacherSupervisionArtifactsFromNormalizedEventExport, createAlwaysOnLearningRuntimeState, describeAlwaysOnLearningRuntimeState, materializeAlwaysOnLearningCandidatePack, materializeCandidatePackFromNormalizedEventExport } from "@openclawbrain/learner";
|
|
9
9
|
import { LEARNING_SPINE_LOG_LAYOUT, activatePack, describeActivationObservability, describeActivationTarget, describePackCompileTarget, inspectActivationState, loadPackFromActivation, promoteCandidatePack, readLearningSpineLogEntries, rollbackActivePack, stageCandidatePack } from "@openclawbrain/pack-format";
|
|
10
10
|
import { appendLearningUpdateLogs, appendServeTimeRouteDecisionLog } from "./learning-spine.js";
|
|
11
|
+
import { createTeacherLabeler } from "./teacher-labeler.js";
|
|
12
|
+
export { createHttpOllamaTeacherLabelerClient, createOllamaTeacherLabeler, createTeacherLabeler } from "./teacher-labeler.js";
|
|
11
13
|
const DEFAULT_AGENT_ID = "openclaw-runtime";
|
|
12
14
|
const FEEDBACK_KINDS = new Set(["correction", "teaching", "approval", "suppression"]);
|
|
13
15
|
export const DEFAULT_ASYNC_TEACHER_QUEUE_CAPACITY = 8;
|
|
@@ -220,6 +222,8 @@ function buildAsyncTeacherLoopNotes(input) {
|
|
|
220
222
|
`teacher_feedback_budgeted_out=${input.sparseFeedback.budgetedOutFeedbackCount}`,
|
|
221
223
|
`teacher_background_amplified=${input.sparseFeedback.amplifiedBackgroundLabelCount}`,
|
|
222
224
|
`teacher_noop=${input.noOpReason}`,
|
|
225
|
+
`teacher_labeler=${input.teacherLabeler?.status ?? "disabled"}`,
|
|
226
|
+
`teacher_labeler_detail=${input.teacherLabeler?.detail ?? "disabled"}`,
|
|
223
227
|
input.materialization === null ? "teacher_materialization=noop" : `teacher_materialized_pack=${input.materialization.candidate.summary.packId}`
|
|
224
228
|
];
|
|
225
229
|
}
|
|
@@ -229,6 +233,22 @@ function cloneAlwaysOnLearningMaterializationJobOrNull(value) {
|
|
|
229
233
|
function cloneTeacherSupervisionArtifacts(value) {
|
|
230
234
|
return [...structuredClone(value)];
|
|
231
235
|
}
|
|
236
|
+
function cloneAsyncTeacherSnapshotState(value) {
|
|
237
|
+
if (value === undefined) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
const interactionEvents = Array.isArray(value.interactionEvents) ? value.interactionEvents : [];
|
|
241
|
+
const feedbackEvents = Array.isArray(value.feedbackEvents) ? value.feedbackEvents : [];
|
|
242
|
+
const seenExportDigests = Array.isArray(value.seenExportDigests) ? value.seenExportDigests : [];
|
|
243
|
+
return {
|
|
244
|
+
interactionEvents: [...structuredClone(interactionEvents)],
|
|
245
|
+
feedbackEvents: [...structuredClone(feedbackEvents)],
|
|
246
|
+
seenExportDigests: [...seenExportDigests]
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function cloneAsyncTeacherSnapshotRuntime(value) {
|
|
250
|
+
return value === undefined ? undefined : { ...value };
|
|
251
|
+
}
|
|
232
252
|
function cloneCanonicalSupervision(value) {
|
|
233
253
|
return structuredClone(value);
|
|
234
254
|
}
|
|
@@ -508,6 +528,7 @@ export class AsyncTeacherLiveLoop {
|
|
|
508
528
|
input;
|
|
509
529
|
queueCapacity;
|
|
510
530
|
staleAfterMs;
|
|
531
|
+
teacherLabeler;
|
|
511
532
|
queuedExportDigests = new Set();
|
|
512
533
|
seenExportDigests = new Set();
|
|
513
534
|
queue = [];
|
|
@@ -517,6 +538,7 @@ export class AsyncTeacherLiveLoop {
|
|
|
517
538
|
teacherArtifacts = [];
|
|
518
539
|
learnerState = createAlwaysOnLearningRuntimeState();
|
|
519
540
|
lastMaterialization = null;
|
|
541
|
+
lastTeacherLabelerResult = null;
|
|
520
542
|
diagnostics = {
|
|
521
543
|
acceptedExportCount: 0,
|
|
522
544
|
processedExportCount: 0,
|
|
@@ -535,19 +557,40 @@ export class AsyncTeacherLiveLoop {
|
|
|
535
557
|
dedupedArtifactCount: 0,
|
|
536
558
|
sparseFeedback: this.learnerState.sparseFeedback,
|
|
537
559
|
noOpReason: "none",
|
|
538
|
-
materialization: null
|
|
560
|
+
materialization: null,
|
|
561
|
+
teacherLabeler: null
|
|
539
562
|
})
|
|
540
563
|
};
|
|
541
564
|
constructor(input) {
|
|
542
565
|
this.input = input;
|
|
543
566
|
this.queueCapacity = input.maxQueuedExports ?? DEFAULT_ASYNC_TEACHER_QUEUE_CAPACITY;
|
|
544
567
|
this.staleAfterMs = input.staleAfterMs ?? DEFAULT_TEACHER_SUPERVISION_STALE_AFTER_MS;
|
|
568
|
+
this.teacherLabeler = createTeacherLabeler(input.teacherLabeler);
|
|
545
569
|
if (!Number.isInteger(this.queueCapacity) || this.queueCapacity <= 0) {
|
|
546
570
|
throw new Error("maxQueuedExports must be a positive integer");
|
|
547
571
|
}
|
|
548
572
|
if (!Number.isInteger(this.staleAfterMs) || this.staleAfterMs <= 0) {
|
|
549
573
|
throw new Error("staleAfterMs must be a positive integer");
|
|
550
574
|
}
|
|
575
|
+
const resumedSnapshot = input.resumeFromSnapshot;
|
|
576
|
+
if (resumedSnapshot !== undefined && resumedSnapshot !== null) {
|
|
577
|
+
if (resumedSnapshot.runtimeOwner !== "openclaw") {
|
|
578
|
+
throw new Error("async teacher resume snapshot runtimeOwner must be openclaw");
|
|
579
|
+
}
|
|
580
|
+
this.interactionEvents = [...structuredClone(resumedSnapshot.state?.interactionEvents ?? [])];
|
|
581
|
+
this.feedbackEvents = [...structuredClone(resumedSnapshot.state?.feedbackEvents ?? [])];
|
|
582
|
+
this.teacherArtifacts = cloneTeacherSupervisionArtifacts(resumedSnapshot.teacher.artifacts);
|
|
583
|
+
this.learnerState = structuredClone(resumedSnapshot.learner.state);
|
|
584
|
+
this.lastMaterialization = cloneAlwaysOnLearningMaterializationJobOrNull(resumedSnapshot.learner.lastMaterialization);
|
|
585
|
+
this.diagnostics = {
|
|
586
|
+
...structuredClone(resumedSnapshot.diagnostics),
|
|
587
|
+
notes: [...resumedSnapshot.diagnostics.notes]
|
|
588
|
+
};
|
|
589
|
+
for (const exportDigest of resumedSnapshot.state?.seenExportDigests ?? []) {
|
|
590
|
+
this.seenExportDigests.add(exportDigest);
|
|
591
|
+
}
|
|
592
|
+
this.refreshNotes();
|
|
593
|
+
}
|
|
551
594
|
}
|
|
552
595
|
enqueueNormalizedEventExport(normalizedEventExport, options = {}) {
|
|
553
596
|
const validationErrors = validateNormalizedEventExport(normalizedEventExport);
|
|
@@ -589,7 +632,9 @@ export class AsyncTeacherLiveLoop {
|
|
|
589
632
|
this.queuedExportDigests.add(exportDigest);
|
|
590
633
|
this.diagnostics.acceptedExportCount += 1;
|
|
591
634
|
this.refreshNotes();
|
|
592
|
-
void this.ensureDrain()
|
|
635
|
+
void this.ensureDrain().catch(() => {
|
|
636
|
+
// Explicit flush()/ingest callers observe the failure; the background kickoff must not leak an unhandled rejection.
|
|
637
|
+
});
|
|
593
638
|
return {
|
|
594
639
|
accepted: true,
|
|
595
640
|
exportDigest,
|
|
@@ -745,6 +790,11 @@ export class AsyncTeacherLiveLoop {
|
|
|
745
790
|
diagnostics: {
|
|
746
791
|
...this.diagnostics,
|
|
747
792
|
notes: [...this.diagnostics.notes]
|
|
793
|
+
},
|
|
794
|
+
state: {
|
|
795
|
+
interactionEvents: [...structuredClone(this.interactionEvents)],
|
|
796
|
+
feedbackEvents: [...structuredClone(this.feedbackEvents)],
|
|
797
|
+
seenExportDigests: [...this.seenExportDigests].sort()
|
|
748
798
|
}
|
|
749
799
|
};
|
|
750
800
|
}
|
|
@@ -763,49 +813,106 @@ export class AsyncTeacherLiveLoop {
|
|
|
763
813
|
while (this.queue.length > 0) {
|
|
764
814
|
const job = this.queue.shift();
|
|
765
815
|
this.queuedExportDigests.delete(job.exportDigest);
|
|
766
|
-
this.
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
816
|
+
const previousInteractionEvents = [...structuredClone(this.interactionEvents)];
|
|
817
|
+
const previousFeedbackEvents = [...structuredClone(this.feedbackEvents)];
|
|
818
|
+
const previousTeacherArtifacts = cloneTeacherSupervisionArtifacts(this.teacherArtifacts);
|
|
819
|
+
const previousLearnerState = structuredClone(this.learnerState);
|
|
820
|
+
const previousLastMaterialization = cloneAlwaysOnLearningMaterializationJobOrNull(this.lastMaterialization);
|
|
821
|
+
const previousDiagnostics = {
|
|
822
|
+
...structuredClone(this.diagnostics),
|
|
823
|
+
notes: [...this.diagnostics.notes]
|
|
824
|
+
};
|
|
825
|
+
const previousSeenExportDigests = [...this.seenExportDigests];
|
|
826
|
+
try {
|
|
827
|
+
this.seenExportDigests.add(job.exportDigest);
|
|
828
|
+
this.interactionEvents = mergeUniqueEvents(this.interactionEvents, job.normalizedEventExport.interactionEvents);
|
|
829
|
+
this.feedbackEvents = mergeUniqueEvents(this.feedbackEvents, job.normalizedEventExport.feedbackEvents);
|
|
830
|
+
const mergedNormalizedEventExport = buildNormalizedEventExport({
|
|
831
|
+
interactionEvents: this.interactionEvents,
|
|
832
|
+
feedbackEvents: this.feedbackEvents
|
|
833
|
+
});
|
|
834
|
+
const learnedRoutingState = this.input.resolveLearnedRoutingState?.() ?? {};
|
|
835
|
+
const builtArtifacts = buildTeacherSupervisionArtifactsFromNormalizedEventExport({
|
|
836
|
+
normalizedEventExport: mergedNormalizedEventExport,
|
|
837
|
+
observedAt: job.observedAt,
|
|
838
|
+
staleAfterMs: this.staleAfterMs,
|
|
839
|
+
...(this.input.sparseFeedback !== undefined ? { sparseFeedback: this.input.sparseFeedback } : {})
|
|
840
|
+
});
|
|
841
|
+
let generatedTeacherArtifacts = [];
|
|
842
|
+
if (this.teacherLabeler !== null) {
|
|
843
|
+
try {
|
|
844
|
+
this.lastTeacherLabelerResult = await this.teacherLabeler.label({
|
|
845
|
+
normalizedEventExport: mergedNormalizedEventExport,
|
|
846
|
+
observedAt: job.observedAt,
|
|
847
|
+
staleAfterMs: this.staleAfterMs,
|
|
848
|
+
existingArtifacts: [...this.teacherArtifacts, ...builtArtifacts],
|
|
849
|
+
...(learnedRoutingState.serveTimeDecisions !== undefined
|
|
850
|
+
? { serveTimeDecisions: learnedRoutingState.serveTimeDecisions }
|
|
851
|
+
: {})
|
|
852
|
+
});
|
|
853
|
+
generatedTeacherArtifacts = this.lastTeacherLabelerResult.artifacts;
|
|
854
|
+
}
|
|
855
|
+
catch (error) {
|
|
856
|
+
this.lastTeacherLabelerResult = {
|
|
857
|
+
artifacts: [],
|
|
858
|
+
status: "fail_open",
|
|
859
|
+
detail: toErrorMessage(error)
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const nextBuiltArtifacts = mergeTeacherArtifacts([], [...builtArtifacts, ...generatedTeacherArtifacts]);
|
|
864
|
+
const currentDedupIds = new Set(this.teacherArtifacts.map((artifact) => artifact.dedupId));
|
|
865
|
+
const nextTeacherArtifacts = mergeTeacherArtifacts(this.teacherArtifacts, nextBuiltArtifacts);
|
|
866
|
+
const emittedArtifactCount = nextBuiltArtifacts.filter((artifact) => !currentDedupIds.has(artifact.dedupId)).length;
|
|
867
|
+
const dedupedArtifactCount = nextBuiltArtifacts.length - emittedArtifactCount;
|
|
868
|
+
this.teacherArtifacts = nextTeacherArtifacts;
|
|
869
|
+
const learnerResult = advanceAlwaysOnLearningRuntime({
|
|
870
|
+
packLabel: this.input.packLabel,
|
|
871
|
+
workspace: this.input.workspace,
|
|
872
|
+
interactionEvents: this.interactionEvents,
|
|
873
|
+
feedbackEvents: this.feedbackEvents,
|
|
874
|
+
teacherSupervisionArtifacts: this.teacherArtifacts,
|
|
875
|
+
learnedRouting: this.input.learnedRouting,
|
|
876
|
+
state: this.learnerState,
|
|
877
|
+
builtAt: this.input.builtAt ?? job.observedAt,
|
|
878
|
+
...(this.input.offlineArtifacts !== undefined ? { offlineArtifacts: this.input.offlineArtifacts } : {}),
|
|
879
|
+
...(this.input.structuralOps !== undefined ? { structuralOps: this.input.structuralOps } : {}),
|
|
880
|
+
...(this.input.sparseFeedback !== undefined ? { sparseFeedback: this.input.sparseFeedback } : {}),
|
|
881
|
+
...(this.input.liveSliceSize !== undefined ? { liveSliceSize: this.input.liveSliceSize } : {}),
|
|
882
|
+
...(this.input.backfillSliceSize !== undefined ? { backfillSliceSize: this.input.backfillSliceSize } : {}),
|
|
883
|
+
...(this.input.cadence !== undefined ? { cadence: this.input.cadence } : {}),
|
|
884
|
+
...(learnedRoutingState.pgVersion !== undefined ? { pgVersion: learnedRoutingState.pgVersion } : {}),
|
|
885
|
+
...(learnedRoutingState.serveTimeDecisions !== undefined ? { serveTimeDecisions: learnedRoutingState.serveTimeDecisions } : {}),
|
|
886
|
+
...(learnedRoutingState.baselineState !== undefined ? { baselineState: learnedRoutingState.baselineState } : {})
|
|
887
|
+
});
|
|
888
|
+
this.learnerState = structuredClone(learnerResult.state);
|
|
889
|
+
this.lastMaterialization = cloneAlwaysOnLearningMaterializationJobOrNull(learnerResult.materialization);
|
|
890
|
+
const updatedBaseline = learnerResult.materialization?.candidate.routingBuild.updatedBaseline ?? null;
|
|
891
|
+
if (updatedBaseline !== null) {
|
|
892
|
+
this.input.persistUpdatedBaseline?.(structuredClone(updatedBaseline));
|
|
893
|
+
}
|
|
894
|
+
this.diagnostics.processedExportCount += 1;
|
|
895
|
+
this.diagnostics.emittedArtifactCount += emittedArtifactCount;
|
|
896
|
+
this.diagnostics.dedupedArtifactCount += dedupedArtifactCount;
|
|
897
|
+
this.diagnostics.lastProcessedAt = job.observedAt;
|
|
898
|
+
this.diagnostics.latestFreshness = latestTeacherFreshness(this.teacherArtifacts);
|
|
899
|
+
this.diagnostics.lastNoOpReason = emittedArtifactCount === 0 ? "no_teacher_artifacts" : "none";
|
|
900
|
+
this.refreshNotes();
|
|
901
|
+
}
|
|
902
|
+
catch (error) {
|
|
903
|
+
this.interactionEvents = previousInteractionEvents;
|
|
904
|
+
this.feedbackEvents = previousFeedbackEvents;
|
|
905
|
+
this.teacherArtifacts = previousTeacherArtifacts;
|
|
906
|
+
this.learnerState = previousLearnerState;
|
|
907
|
+
this.lastMaterialization = previousLastMaterialization;
|
|
908
|
+
this.diagnostics = previousDiagnostics;
|
|
909
|
+
this.seenExportDigests.clear();
|
|
910
|
+
for (const exportDigest of previousSeenExportDigests) {
|
|
911
|
+
this.seenExportDigests.add(exportDigest);
|
|
912
|
+
}
|
|
913
|
+
this.refreshNotes();
|
|
914
|
+
throw error;
|
|
915
|
+
}
|
|
809
916
|
}
|
|
810
917
|
}
|
|
811
918
|
refreshNotes() {
|
|
@@ -817,7 +924,8 @@ export class AsyncTeacherLiveLoop {
|
|
|
817
924
|
dedupedArtifactCount: this.diagnostics.dedupedArtifactCount,
|
|
818
925
|
sparseFeedback: this.learnerState.sparseFeedback,
|
|
819
926
|
noOpReason: this.diagnostics.lastNoOpReason,
|
|
820
|
-
materialization: this.lastMaterialization
|
|
927
|
+
materialization: this.lastMaterialization,
|
|
928
|
+
teacherLabeler: this.lastTeacherLabelerResult
|
|
821
929
|
});
|
|
822
930
|
}
|
|
823
931
|
}
|
|
@@ -923,22 +1031,331 @@ export function scanLiveEventExport(input) {
|
|
|
923
1031
|
dedupedArtifactCount: 0,
|
|
924
1032
|
sparseFeedback: learnerResult.state.sparseFeedback,
|
|
925
1033
|
noOpReason: lastNoOpReason,
|
|
926
|
-
materialization: learnerResult.materialization
|
|
1034
|
+
materialization: learnerResult.materialization,
|
|
1035
|
+
teacherLabeler: null
|
|
927
1036
|
})
|
|
928
1037
|
}
|
|
929
1038
|
};
|
|
1039
|
+
const labelFlow = summarizeNormalizedEventExportLabelFlow(normalizedEventExport, teacherArtifacts.length);
|
|
1040
|
+
const learningPath = summarizeLearningPathFromMaterialization(learnerResult.materialization);
|
|
930
1041
|
return {
|
|
931
1042
|
runtimeOwner: "openclaw",
|
|
932
1043
|
scanMode: "live",
|
|
933
1044
|
observedAt,
|
|
934
1045
|
packLabel,
|
|
935
1046
|
supervision: buildCanonicalSupervision(normalizedEventExport),
|
|
936
|
-
snapshot
|
|
1047
|
+
snapshot,
|
|
1048
|
+
labelFlow,
|
|
1049
|
+
learningPath
|
|
937
1050
|
};
|
|
938
1051
|
}
|
|
939
1052
|
function readJsonFile(filePath) {
|
|
940
1053
|
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
941
1054
|
}
|
|
1055
|
+
export function resolveAsyncTeacherLiveLoopSnapshotPath(activationRoot) {
|
|
1056
|
+
return path.join(path.resolve(normalizeNonEmptyString(activationRoot, "activationRoot")), "async-teacher-live-loop.snapshot.json");
|
|
1057
|
+
}
|
|
1058
|
+
export const WATCH_STATE_DIRNAME = "watch";
|
|
1059
|
+
export const WATCH_SESSION_TAIL_CURSOR_BASENAME = "session-tail-cursor.json";
|
|
1060
|
+
export const WATCH_TEACHER_SNAPSHOT_BASENAME = "teacher-snapshot.json";
|
|
1061
|
+
function isAsyncTeacherLiveLoopSnapshot(value) {
|
|
1062
|
+
if (value === null || typeof value !== "object") {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
const candidate = value;
|
|
1066
|
+
return (candidate.runtimeOwner === "openclaw" &&
|
|
1067
|
+
candidate.queue !== undefined &&
|
|
1068
|
+
candidate.teacher !== undefined &&
|
|
1069
|
+
candidate.learner !== undefined &&
|
|
1070
|
+
candidate.diagnostics !== undefined);
|
|
1071
|
+
}
|
|
1072
|
+
function isWatchTeacherSnapshot(value) {
|
|
1073
|
+
if (value === null || typeof value !== "object") {
|
|
1074
|
+
return false;
|
|
1075
|
+
}
|
|
1076
|
+
const candidate = value;
|
|
1077
|
+
return (candidate.contract === "openclaw_watch_teacher_snapshot.v1" &&
|
|
1078
|
+
candidate.runtimeOwner === "openclaw" &&
|
|
1079
|
+
isAsyncTeacherLiveLoopSnapshot(candidate.snapshot));
|
|
1080
|
+
}
|
|
1081
|
+
function cloneWatchTeacherSnapshotFailure(value) {
|
|
1082
|
+
if (value === null ||
|
|
1083
|
+
value === undefined ||
|
|
1084
|
+
!["materialization_failed", "teacher_fail_open"].includes(value.mode) ||
|
|
1085
|
+
typeof value.detail !== "string" ||
|
|
1086
|
+
typeof value.at !== "string") {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
return {
|
|
1090
|
+
mode: value.mode,
|
|
1091
|
+
detail: value.detail,
|
|
1092
|
+
at: value.at
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
function cloneRuntimeEventExportScannerCheckpoint(value) {
|
|
1096
|
+
return structuredClone(value);
|
|
1097
|
+
}
|
|
1098
|
+
function buildWatchTeacherSnapshotTeacherSummary(snapshot) {
|
|
1099
|
+
return {
|
|
1100
|
+
artifactCount: snapshot.teacher.artifactCount,
|
|
1101
|
+
latestFreshness: snapshot.teacher.latestFreshness,
|
|
1102
|
+
acceptedExportCount: snapshot.diagnostics.acceptedExportCount,
|
|
1103
|
+
processedExportCount: snapshot.diagnostics.processedExportCount,
|
|
1104
|
+
duplicateExportCount: snapshot.diagnostics.duplicateExportCount,
|
|
1105
|
+
droppedExportCount: snapshot.diagnostics.droppedExportCount,
|
|
1106
|
+
emittedArtifactCount: snapshot.diagnostics.emittedArtifactCount,
|
|
1107
|
+
dedupedArtifactCount: snapshot.diagnostics.dedupedArtifactCount,
|
|
1108
|
+
lastProcessedAt: snapshot.diagnostics.lastProcessedAt,
|
|
1109
|
+
lastNoOpReason: snapshot.diagnostics.lastNoOpReason,
|
|
1110
|
+
queueDepth: snapshot.queue.depth,
|
|
1111
|
+
queueCapacity: snapshot.queue.capacity,
|
|
1112
|
+
running: snapshot.queue.running,
|
|
1113
|
+
lastAppliedMaterializationJobId: snapshot.runtime?.lastAppliedMaterializationJobId ?? snapshot.learner.lastMaterialization?.jobId ?? null,
|
|
1114
|
+
lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
function buildWatchTeacherSnapshotLearningSummary(snapshot, lastHandledMaterializationPackId) {
|
|
1118
|
+
const plan = describeAlwaysOnLearningRuntimeState(snapshot.learner.state, snapshot.learner.lastMaterialization);
|
|
1119
|
+
return {
|
|
1120
|
+
bootstrapped: plan.bootstrapped,
|
|
1121
|
+
mode: plan.mode,
|
|
1122
|
+
nextPriorityLane: plan.nextPriorityLane,
|
|
1123
|
+
nextPriorityBucket: plan.nextPriorityBucket,
|
|
1124
|
+
pendingLive: plan.pending.live,
|
|
1125
|
+
pendingBackfill: plan.pending.backfill,
|
|
1126
|
+
pendingTotal: plan.pending.total,
|
|
1127
|
+
pendingByBucket: { ...plan.pending.byBucket },
|
|
1128
|
+
materializationCount: plan.materialization.count,
|
|
1129
|
+
lastMaterializedAt: plan.materialization.lastMaterializedAt,
|
|
1130
|
+
lastMaterializationReason: plan.materialization.lastReason,
|
|
1131
|
+
lastMaterializationLane: plan.materialization.lastLane,
|
|
1132
|
+
lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null,
|
|
1133
|
+
lastHandledMaterializationPackId
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
function buildWatchTeacherSnapshotLabelingSummary(snapshot) {
|
|
1137
|
+
const learningSurface = snapshot.learner.lastMaterialization?.candidate.summary.learningSurface ??
|
|
1138
|
+
snapshot.learner.state.learnedEventExport?.provenance.learningSurface ??
|
|
1139
|
+
null;
|
|
1140
|
+
return {
|
|
1141
|
+
learningCadence: learningSurface?.learningCadence ?? "passive_background",
|
|
1142
|
+
scanPolicy: learningSurface?.scanPolicy ?? "always_on",
|
|
1143
|
+
liveSlicesPerCycle: 1,
|
|
1144
|
+
backfillSlicesPerCycle: 1,
|
|
1145
|
+
teacherBudget: snapshot.learner.state.sparseFeedback.teacherBudget,
|
|
1146
|
+
teacherDelayMs: snapshot.learner.state.sparseFeedback.teacherDelayMs,
|
|
1147
|
+
backgroundLabelAmplification: snapshot.learner.state.sparseFeedback.backgroundLabelAmplification
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
function normalizeWatchTeacherSnapshotFromValue(value, snapshot, sourcePath) {
|
|
1151
|
+
const activationRoot = path.dirname(path.dirname(sourcePath));
|
|
1152
|
+
const defaultScanRoot = path.join(activationRoot, "event-exports");
|
|
1153
|
+
return {
|
|
1154
|
+
contract: "openclaw_watch_teacher_snapshot.v1",
|
|
1155
|
+
runtimeOwner: "openclaw",
|
|
1156
|
+
updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : new Date(0).toISOString(),
|
|
1157
|
+
lastRunAt: typeof value.lastRunAt === "string"
|
|
1158
|
+
? value.lastRunAt
|
|
1159
|
+
: typeof value.updatedAt === "string"
|
|
1160
|
+
? value.updatedAt
|
|
1161
|
+
: snapshot.diagnostics.lastProcessedAt ?? new Date(0).toISOString(),
|
|
1162
|
+
scanRoot: typeof value.scanRoot === "string" ? value.scanRoot : defaultScanRoot,
|
|
1163
|
+
sessionTailCursorPath: typeof value.sessionTailCursorPath === "string"
|
|
1164
|
+
? value.sessionTailCursorPath
|
|
1165
|
+
: resolveWatchSessionTailCursorPath(activationRoot),
|
|
1166
|
+
sessionTailCursorUpdatedAt: typeof value.sessionTailCursorUpdatedAt === "string"
|
|
1167
|
+
? value.sessionTailCursorUpdatedAt
|
|
1168
|
+
: typeof value.updatedAt === "string"
|
|
1169
|
+
? value.updatedAt
|
|
1170
|
+
: new Date(0).toISOString(),
|
|
1171
|
+
sessionTailSessionsTracked: typeof value.sessionTailSessionsTracked === "number" ? value.sessionTailSessionsTracked : 0,
|
|
1172
|
+
sessionTailBridgedEventCount: typeof value.sessionTailBridgedEventCount === "number" ? value.sessionTailBridgedEventCount : 0,
|
|
1173
|
+
scannerCheckpointPath: typeof value.scannerCheckpointPath === "string"
|
|
1174
|
+
? value.scannerCheckpointPath
|
|
1175
|
+
: path.join(typeof value.scanRoot === "string" ? value.scanRoot : defaultScanRoot, ".openclawbrain-scanner-checkpoint.json"),
|
|
1176
|
+
scannerCheckpoint: value.scannerCheckpoint !== undefined
|
|
1177
|
+
? cloneRuntimeEventExportScannerCheckpoint(value.scannerCheckpoint)
|
|
1178
|
+
: createRuntimeEventExportScannerCheckpoint({
|
|
1179
|
+
scanRoot: typeof value.scanRoot === "string" ? value.scanRoot : defaultScanRoot
|
|
1180
|
+
}),
|
|
1181
|
+
replayedBundleCount: typeof value.replayedBundleCount === "number" ? value.replayedBundleCount : 0,
|
|
1182
|
+
replayedEventCount: typeof value.replayedEventCount === "number" ? value.replayedEventCount : 0,
|
|
1183
|
+
exportedBundleCount: typeof value.exportedBundleCount === "number" ? value.exportedBundleCount : 0,
|
|
1184
|
+
exportedEventCount: typeof value.exportedEventCount === "number" ? value.exportedEventCount : 0,
|
|
1185
|
+
startupWarnings: Array.isArray(value.startupWarnings)
|
|
1186
|
+
? value.startupWarnings.filter((warning) => typeof warning === "string")
|
|
1187
|
+
: [],
|
|
1188
|
+
lastTeacherError: typeof value.lastTeacherError === "string"
|
|
1189
|
+
? value.lastTeacherError
|
|
1190
|
+
: null,
|
|
1191
|
+
localSessionTailNoopReason: typeof value.localSessionTailNoopReason === "string" ? value.localSessionTailNoopReason : null,
|
|
1192
|
+
lastHandledMaterializationPackId: typeof value.lastHandledMaterializationPackId === "string" ? value.lastHandledMaterializationPackId : null,
|
|
1193
|
+
teacher: value.teacher ?? buildWatchTeacherSnapshotTeacherSummary(snapshot),
|
|
1194
|
+
learning: value.learning ?? buildWatchTeacherSnapshotLearningSummary(snapshot, typeof value.lastHandledMaterializationPackId === "string" ? value.lastHandledMaterializationPackId : null),
|
|
1195
|
+
labeling: value.labeling ?? buildWatchTeacherSnapshotLabelingSummary(snapshot),
|
|
1196
|
+
failure: cloneWatchTeacherSnapshotFailure(value.failure),
|
|
1197
|
+
snapshot
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
export function resolveWatchStateRoot(activationRoot) {
|
|
1201
|
+
return path.resolve(normalizeNonEmptyString(activationRoot, "activationRoot"), WATCH_STATE_DIRNAME);
|
|
1202
|
+
}
|
|
1203
|
+
export function resolveWatchSessionTailCursorPath(activationRoot) {
|
|
1204
|
+
return path.join(resolveWatchStateRoot(activationRoot), WATCH_SESSION_TAIL_CURSOR_BASENAME);
|
|
1205
|
+
}
|
|
1206
|
+
export function resolveWatchTeacherSnapshotPath(activationRoot) {
|
|
1207
|
+
return path.join(resolveWatchStateRoot(activationRoot), WATCH_TEACHER_SNAPSHOT_BASENAME);
|
|
1208
|
+
}
|
|
1209
|
+
export function resolveOperatorTeacherSnapshotPath(activationRoot, explicitPath) {
|
|
1210
|
+
if (explicitPath !== null && explicitPath !== undefined) {
|
|
1211
|
+
return explicitPath;
|
|
1212
|
+
}
|
|
1213
|
+
const canonicalWatchSnapshotPath = resolveWatchTeacherSnapshotPath(activationRoot);
|
|
1214
|
+
if (existsSync(canonicalWatchSnapshotPath)) {
|
|
1215
|
+
return canonicalWatchSnapshotPath;
|
|
1216
|
+
}
|
|
1217
|
+
const asyncSnapshotPath = resolveAsyncTeacherLiveLoopSnapshotPath(activationRoot);
|
|
1218
|
+
return existsSync(asyncSnapshotPath) ? asyncSnapshotPath : null;
|
|
1219
|
+
}
|
|
1220
|
+
export function loadTeacherSurface(snapshotPath) {
|
|
1221
|
+
const resolvedPath = path.resolve(snapshotPath);
|
|
1222
|
+
let parsed;
|
|
1223
|
+
try {
|
|
1224
|
+
parsed = readJsonFile(resolvedPath);
|
|
1225
|
+
}
|
|
1226
|
+
catch {
|
|
1227
|
+
return null;
|
|
1228
|
+
}
|
|
1229
|
+
if (isWatchTeacherSnapshot(parsed)) {
|
|
1230
|
+
const snapshot = loadAsyncTeacherLiveLoopSnapshotFromValue(parsed.snapshot);
|
|
1231
|
+
return {
|
|
1232
|
+
sourcePath: resolvedPath,
|
|
1233
|
+
sourceKind: "watch_snapshot",
|
|
1234
|
+
snapshot,
|
|
1235
|
+
watchSnapshot: normalizeWatchTeacherSnapshotFromValue(parsed, snapshot, resolvedPath)
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (isAsyncTeacherLiveLoopSnapshot(parsed)) {
|
|
1239
|
+
return {
|
|
1240
|
+
sourcePath: resolvedPath,
|
|
1241
|
+
sourceKind: "async_snapshot",
|
|
1242
|
+
snapshot: loadAsyncTeacherLiveLoopSnapshotFromValue(parsed),
|
|
1243
|
+
watchSnapshot: null
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
return null;
|
|
1247
|
+
}
|
|
1248
|
+
export function loadWatchTeacherSnapshotState(snapshotPath) {
|
|
1249
|
+
const resolvedPath = path.resolve(snapshotPath);
|
|
1250
|
+
if (!existsSync(resolvedPath)) {
|
|
1251
|
+
return {
|
|
1252
|
+
lastHandledMaterializationPackId: null,
|
|
1253
|
+
snapshot: null,
|
|
1254
|
+
error: null
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
let parsed;
|
|
1258
|
+
try {
|
|
1259
|
+
parsed = readJsonFile(resolvedPath);
|
|
1260
|
+
}
|
|
1261
|
+
catch (error) {
|
|
1262
|
+
return {
|
|
1263
|
+
lastHandledMaterializationPackId: null,
|
|
1264
|
+
snapshot: null,
|
|
1265
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
if (isWatchTeacherSnapshot(parsed)) {
|
|
1269
|
+
return {
|
|
1270
|
+
lastHandledMaterializationPackId: parsed.lastHandledMaterializationPackId,
|
|
1271
|
+
snapshot: loadAsyncTeacherLiveLoopSnapshotFromValue(parsed.snapshot),
|
|
1272
|
+
error: null
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
if (isAsyncTeacherLiveLoopSnapshot(parsed)) {
|
|
1276
|
+
return {
|
|
1277
|
+
lastHandledMaterializationPackId: null,
|
|
1278
|
+
snapshot: loadAsyncTeacherLiveLoopSnapshotFromValue(parsed),
|
|
1279
|
+
error: null
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
lastHandledMaterializationPackId: null,
|
|
1284
|
+
snapshot: null,
|
|
1285
|
+
error: `watch teacher snapshot is invalid: ${resolvedPath}`
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
export function persistWatchTeacherSnapshot(snapshotPath, input) {
|
|
1289
|
+
const persistedAt = new Date().toISOString();
|
|
1290
|
+
const canonicalSnapshot = loadAsyncTeacherLiveLoopSnapshotFromValue(input.snapshot);
|
|
1291
|
+
const payload = {
|
|
1292
|
+
contract: "openclaw_watch_teacher_snapshot.v1",
|
|
1293
|
+
runtimeOwner: "openclaw",
|
|
1294
|
+
updatedAt: persistedAt,
|
|
1295
|
+
lastRunAt: input.lastRunAt,
|
|
1296
|
+
scanRoot: path.resolve(input.scanRoot),
|
|
1297
|
+
sessionTailCursorPath: path.resolve(input.sessionTailCursorPath),
|
|
1298
|
+
sessionTailCursorUpdatedAt: input.sessionTailCursorUpdatedAt,
|
|
1299
|
+
sessionTailSessionsTracked: input.sessionTailSessionsTracked,
|
|
1300
|
+
sessionTailBridgedEventCount: input.sessionTailBridgedEventCount,
|
|
1301
|
+
scannerCheckpointPath: path.resolve(input.scannerCheckpointPath),
|
|
1302
|
+
scannerCheckpoint: cloneRuntimeEventExportScannerCheckpoint(input.scannerCheckpoint),
|
|
1303
|
+
replayedBundleCount: input.replayedBundleCount,
|
|
1304
|
+
replayedEventCount: input.replayedEventCount,
|
|
1305
|
+
exportedBundleCount: input.exportedBundleCount,
|
|
1306
|
+
exportedEventCount: input.exportedEventCount,
|
|
1307
|
+
startupWarnings: [...input.startupWarnings],
|
|
1308
|
+
lastTeacherError: input.lastTeacherError,
|
|
1309
|
+
localSessionTailNoopReason: input.localSessionTailNoopReason,
|
|
1310
|
+
lastHandledMaterializationPackId: input.lastHandledMaterializationPackId,
|
|
1311
|
+
teacher: buildWatchTeacherSnapshotTeacherSummary(canonicalSnapshot),
|
|
1312
|
+
learning: buildWatchTeacherSnapshotLearningSummary(canonicalSnapshot, input.lastHandledMaterializationPackId),
|
|
1313
|
+
labeling: buildWatchTeacherSnapshotLabelingSummary(canonicalSnapshot),
|
|
1314
|
+
failure: cloneWatchTeacherSnapshotFailure(input.failure),
|
|
1315
|
+
snapshot: canonicalSnapshot
|
|
1316
|
+
};
|
|
1317
|
+
mkdirSync(path.dirname(snapshotPath), { recursive: true });
|
|
1318
|
+
writeFileSync(snapshotPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
1319
|
+
return payload;
|
|
1320
|
+
}
|
|
1321
|
+
function loadAsyncTeacherLiveLoopSnapshotFromValue(snapshot) {
|
|
1322
|
+
if (snapshot.runtimeOwner !== "openclaw") {
|
|
1323
|
+
throw new Error("async teacher snapshot runtimeOwner must be openclaw");
|
|
1324
|
+
}
|
|
1325
|
+
const cloned = {
|
|
1326
|
+
...snapshot,
|
|
1327
|
+
diagnostics: {
|
|
1328
|
+
...snapshot.diagnostics,
|
|
1329
|
+
notes: [...snapshot.diagnostics.notes]
|
|
1330
|
+
},
|
|
1331
|
+
teacher: {
|
|
1332
|
+
...snapshot.teacher,
|
|
1333
|
+
artifacts: cloneTeacherSupervisionArtifacts(snapshot.teacher.artifacts)
|
|
1334
|
+
},
|
|
1335
|
+
learner: {
|
|
1336
|
+
state: structuredClone(snapshot.learner.state),
|
|
1337
|
+
lastMaterialization: cloneAlwaysOnLearningMaterializationJobOrNull(snapshot.learner.lastMaterialization)
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
if (snapshot.state !== undefined) {
|
|
1341
|
+
cloned.state = cloneAsyncTeacherSnapshotState(snapshot.state);
|
|
1342
|
+
}
|
|
1343
|
+
if (snapshot.runtime !== undefined) {
|
|
1344
|
+
cloned.runtime = cloneAsyncTeacherSnapshotRuntime(snapshot.runtime);
|
|
1345
|
+
}
|
|
1346
|
+
return cloned;
|
|
1347
|
+
}
|
|
1348
|
+
export function loadAsyncTeacherLiveLoopSnapshot(snapshotPath) {
|
|
1349
|
+
const resolvedPath = path.resolve(snapshotPath);
|
|
1350
|
+
const parsed = readJsonFile(resolvedPath);
|
|
1351
|
+
if (isWatchTeacherSnapshot(parsed)) {
|
|
1352
|
+
return loadAsyncTeacherLiveLoopSnapshotFromValue(parsed.snapshot);
|
|
1353
|
+
}
|
|
1354
|
+
if (isAsyncTeacherLiveLoopSnapshot(parsed)) {
|
|
1355
|
+
return loadAsyncTeacherLiveLoopSnapshotFromValue(parsed);
|
|
1356
|
+
}
|
|
1357
|
+
throw new Error(`async teacher snapshot is invalid: ${resolvedPath}`);
|
|
1358
|
+
}
|
|
942
1359
|
function resolveBundlePayloadPath(rootDir, payloadPath) {
|
|
943
1360
|
const resolved = path.resolve(rootDir, payloadPath);
|
|
944
1361
|
const relative = path.relative(rootDir, resolved);
|
|
@@ -1573,6 +1990,18 @@ export class RuntimeEventExportScanner {
|
|
|
1573
1990
|
snapshot() {
|
|
1574
1991
|
return structuredClone(this.checkpoint);
|
|
1575
1992
|
}
|
|
1993
|
+
restoreCheckpoint(checkpoint) {
|
|
1994
|
+
const restored = structuredClone(checkpoint);
|
|
1995
|
+
const errors = validateRuntimeEventExportScannerCheckpoint(restored);
|
|
1996
|
+
if (errors.length > 0) {
|
|
1997
|
+
throw new Error(`runtime event export scanner checkpoint is invalid: ${errors.join("; ")}`);
|
|
1998
|
+
}
|
|
1999
|
+
if (restored.scanRoot !== this.scanRoot) {
|
|
2000
|
+
throw new Error(`runtime event export scanner checkpoint scanRoot mismatch: checkpoint=${restored.scanRoot} scanner=${this.scanRoot}`);
|
|
2001
|
+
}
|
|
2002
|
+
this.checkpoint = restored;
|
|
2003
|
+
writeRuntimeEventExportScannerCheckpoint(this.checkpointPath, this.checkpoint);
|
|
2004
|
+
}
|
|
1576
2005
|
scanOnce(options = {}) {
|
|
1577
2006
|
const scannedAt = normalizeIsoTimestamp(options.scannedAt, "scannedAt", new Date().toISOString());
|
|
1578
2007
|
const discovered = discoverRuntimeEventExportBundles(this.scanRoot);
|
|
@@ -1770,6 +2199,15 @@ function normalizeIsoTimestamp(value, fieldName, fallbackValue) {
|
|
|
1770
2199
|
function normalizeMode(value) {
|
|
1771
2200
|
return value ?? "heuristic";
|
|
1772
2201
|
}
|
|
2202
|
+
function normalizeCompileSelectionMode(value) {
|
|
2203
|
+
if (value === undefined) {
|
|
2204
|
+
return undefined;
|
|
2205
|
+
}
|
|
2206
|
+
if (value === "flat_rank_v1" || value === "graph_walk_v1") {
|
|
2207
|
+
return value;
|
|
2208
|
+
}
|
|
2209
|
+
throw new Error(`selectionMode must be flat_rank_v1 or graph_walk_v1, received ${String(value)}`);
|
|
2210
|
+
}
|
|
1773
2211
|
function normalizeRuntimeHints(value) {
|
|
1774
2212
|
if (value === undefined) {
|
|
1775
2213
|
return [];
|
|
@@ -1955,6 +2393,9 @@ export function formatPromptContext(compileResponse) {
|
|
|
1955
2393
|
lines.push("[/BRAIN_CONTEXT]");
|
|
1956
2394
|
return `${lines.join("\n")}\n`;
|
|
1957
2395
|
}
|
|
2396
|
+
function resolveActivationRootForFailure(value) {
|
|
2397
|
+
return path.resolve(normalizeOptionalString(value) ?? ".");
|
|
2398
|
+
}
|
|
1958
2399
|
function failOpenCompileResult(error, activationRoot) {
|
|
1959
2400
|
return {
|
|
1960
2401
|
ok: false,
|
|
@@ -1990,6 +2431,96 @@ function classifyCompileFailure(error, activationRoot) {
|
|
|
1990
2431
|
function uniqueNotes(notes) {
|
|
1991
2432
|
return [...new Set(notes.filter((note) => note.length > 0))];
|
|
1992
2433
|
}
|
|
2434
|
+
function buildServeRouteLogFailOpenWarning(scope, error) {
|
|
2435
|
+
return `learning spine serve route log failed open (${scope}): ${toErrorMessage(error)}`;
|
|
2436
|
+
}
|
|
2437
|
+
function buildServeRouteLogFailOpenNotes(scope, error) {
|
|
2438
|
+
return [
|
|
2439
|
+
"serve_route_log_status=fail_open",
|
|
2440
|
+
`serve_route_log_scope=${scope}`,
|
|
2441
|
+
`serve_route_log_error=${toErrorMessage(error)}`
|
|
2442
|
+
];
|
|
2443
|
+
}
|
|
2444
|
+
function normalizeServeRouteChannel(value) {
|
|
2445
|
+
if (typeof value !== "string") {
|
|
2446
|
+
return undefined;
|
|
2447
|
+
}
|
|
2448
|
+
const trimmed = value.trim();
|
|
2449
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
2450
|
+
}
|
|
2451
|
+
function normalizeServeRouteMessage(value) {
|
|
2452
|
+
return typeof value === "string" ? value.trim() : "";
|
|
2453
|
+
}
|
|
2454
|
+
function normalizeServeRouteInstalledEntryPath(value) {
|
|
2455
|
+
if (typeof value !== "string") {
|
|
2456
|
+
return null;
|
|
2457
|
+
}
|
|
2458
|
+
const trimmed = value.trim();
|
|
2459
|
+
return trimmed.length === 0 ? null : path.resolve(trimmed);
|
|
2460
|
+
}
|
|
2461
|
+
function buildCompileServeRouteBreadcrumbs(input) {
|
|
2462
|
+
return {
|
|
2463
|
+
entrypoint: "compileRuntimeContext",
|
|
2464
|
+
invocationSurface: input._serveRouteBreadcrumbs?.invocationSurface ?? "direct_compile_call",
|
|
2465
|
+
hostEvent: input._serveRouteBreadcrumbs?.hostEvent ?? null,
|
|
2466
|
+
installedEntryPath: normalizeServeRouteInstalledEntryPath(input._serveRouteBreadcrumbs?.installedEntryPath),
|
|
2467
|
+
syntheticTurn: true
|
|
2468
|
+
};
|
|
2469
|
+
}
|
|
2470
|
+
function buildRunRuntimeTurnServeRouteBreadcrumbs() {
|
|
2471
|
+
return {
|
|
2472
|
+
entrypoint: "runRuntimeTurn",
|
|
2473
|
+
invocationSurface: "runtime_turn_helper",
|
|
2474
|
+
hostEvent: null,
|
|
2475
|
+
installedEntryPath: null,
|
|
2476
|
+
syntheticTurn: false
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
function appendCompileServeRouteDecisionLog(input) {
|
|
2480
|
+
if (input.compileInput._suppressServeLog) {
|
|
2481
|
+
return;
|
|
2482
|
+
}
|
|
2483
|
+
const recordedAt = new Date().toISOString();
|
|
2484
|
+
const sessionId = normalizeServeRouteChannel(input.compileInput.sessionId) ?? `ext-compile-${Date.now()}`;
|
|
2485
|
+
const channel = normalizeServeRouteChannel(input.compileInput.channel) ?? "extension";
|
|
2486
|
+
const syntheticTurn = {
|
|
2487
|
+
sessionId,
|
|
2488
|
+
channel,
|
|
2489
|
+
userMessage: input.userMessage,
|
|
2490
|
+
createdAt: recordedAt
|
|
2491
|
+
};
|
|
2492
|
+
if (input.compileInput.maxContextBlocks !== undefined) {
|
|
2493
|
+
syntheticTurn.maxContextBlocks = input.compileInput.maxContextBlocks;
|
|
2494
|
+
}
|
|
2495
|
+
if (input.compileInput.budgetStrategy === "fixed_v1" || input.compileInput.budgetStrategy === "empirical_v1") {
|
|
2496
|
+
syntheticTurn.budgetStrategy = input.compileInput.budgetStrategy;
|
|
2497
|
+
}
|
|
2498
|
+
if (input.compileInput.mode === "heuristic" || input.compileInput.mode === "learned") {
|
|
2499
|
+
syntheticTurn.mode = input.compileInput.mode;
|
|
2500
|
+
}
|
|
2501
|
+
if (input.compileInput.runtimeHints !== undefined) {
|
|
2502
|
+
syntheticTurn.runtimeHints = input.compileInput.runtimeHints;
|
|
2503
|
+
}
|
|
2504
|
+
try {
|
|
2505
|
+
appendServeTimeRouteDecisionLog({
|
|
2506
|
+
activationRoot: input.activationRoot,
|
|
2507
|
+
turn: syntheticTurn,
|
|
2508
|
+
compileResult: input.compileResult,
|
|
2509
|
+
recordedAt,
|
|
2510
|
+
breadcrumbs: buildCompileServeRouteBreadcrumbs(input.compileInput)
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
catch (error) {
|
|
2514
|
+
if (input.compileResult.ok) {
|
|
2515
|
+
input.compileResult.compileResponse.diagnostics.notes = uniqueNotes([
|
|
2516
|
+
...input.compileResult.compileResponse.diagnostics.notes,
|
|
2517
|
+
...buildServeRouteLogFailOpenNotes("compileRuntimeContext", error)
|
|
2518
|
+
]);
|
|
2519
|
+
}
|
|
2520
|
+
console.warn(`[openclawbrain] ${buildServeRouteLogFailOpenWarning("compileRuntimeContext", error)} ` +
|
|
2521
|
+
`(activationRoot=${input.activationRoot}, sessionId=${sessionId}, channel=${channel})`);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
1993
2524
|
function roundMetric(value) {
|
|
1994
2525
|
return Math.round(value * 100) / 100;
|
|
1995
2526
|
}
|
|
@@ -2220,24 +2751,52 @@ export function resolveActivePackForCompile(activationRoot) {
|
|
|
2220
2751
|
};
|
|
2221
2752
|
}
|
|
2222
2753
|
export function compileRuntimeContext(input) {
|
|
2223
|
-
const
|
|
2224
|
-
|
|
2225
|
-
|
|
2754
|
+
const fallbackActivationRoot = resolveActivationRootForFailure(input.activationRoot);
|
|
2755
|
+
let activationRoot = fallbackActivationRoot;
|
|
2756
|
+
let agentId = process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
|
|
2757
|
+
let runtimeHints = [];
|
|
2758
|
+
let selectionMode;
|
|
2759
|
+
let userMessage = "";
|
|
2760
|
+
let maxContextChars;
|
|
2761
|
+
let mode = "heuristic";
|
|
2762
|
+
let result;
|
|
2763
|
+
try {
|
|
2764
|
+
activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
|
|
2765
|
+
agentId = normalizeOptionalString(input.agentId) ?? process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
|
|
2766
|
+
runtimeHints = normalizeRuntimeHints(input.runtimeHints);
|
|
2767
|
+
selectionMode = normalizeCompileSelectionMode(input.selectionMode);
|
|
2768
|
+
userMessage = normalizeNonEmptyString(input.message, "message");
|
|
2769
|
+
maxContextChars =
|
|
2770
|
+
input.maxContextChars !== undefined
|
|
2771
|
+
? normalizeNonNegativeInteger(input.maxContextChars, "maxContextChars", input.maxContextChars)
|
|
2772
|
+
: undefined;
|
|
2773
|
+
mode = normalizeMode(input.mode);
|
|
2774
|
+
}
|
|
2775
|
+
catch (error) {
|
|
2776
|
+
result = failOpenCompileResult(error, fallbackActivationRoot);
|
|
2777
|
+
appendCompileServeRouteDecisionLog({
|
|
2778
|
+
compileInput: input,
|
|
2779
|
+
activationRoot: result.activationRoot,
|
|
2780
|
+
compileResult: result,
|
|
2781
|
+
userMessage: normalizeServeRouteMessage(input.message)
|
|
2782
|
+
});
|
|
2783
|
+
return result;
|
|
2784
|
+
}
|
|
2226
2785
|
try {
|
|
2227
2786
|
const target = resolveActivePackForCompile(activationRoot);
|
|
2228
2787
|
const resolvedBudget = resolveCompileBudget(target, input);
|
|
2229
2788
|
const compile = compileRuntimeFromActivation(activationRoot, {
|
|
2230
2789
|
contract: CONTRACT_IDS.runtimeCompile,
|
|
2231
2790
|
agentId,
|
|
2232
|
-
userMessage
|
|
2791
|
+
userMessage,
|
|
2233
2792
|
maxContextBlocks: resolvedBudget.maxContextBlocks,
|
|
2234
|
-
...(
|
|
2235
|
-
|
|
2236
|
-
: {}),
|
|
2237
|
-
modeRequested: normalizeMode(input.mode),
|
|
2793
|
+
...(maxContextChars !== undefined ? { maxContextChars } : {}),
|
|
2794
|
+
modeRequested: mode,
|
|
2238
2795
|
activePackId: target.activePointer.packId,
|
|
2239
2796
|
...(input.compactionMode !== undefined ? { compactionMode: input.compactionMode } : {}),
|
|
2240
2797
|
...(runtimeHints.length > 0 ? { runtimeHints } : {})
|
|
2798
|
+
}, {
|
|
2799
|
+
...(selectionMode !== undefined ? { selectionMode } : {})
|
|
2241
2800
|
});
|
|
2242
2801
|
const compileResponse = {
|
|
2243
2802
|
...compile.response,
|
|
@@ -2246,7 +2805,7 @@ export function compileRuntimeContext(input) {
|
|
|
2246
2805
|
notes: uniqueNotes([...compile.response.diagnostics.notes, ...resolvedBudget.notes, "OpenClaw remains the runtime owner"])
|
|
2247
2806
|
}
|
|
2248
2807
|
};
|
|
2249
|
-
|
|
2808
|
+
result = {
|
|
2250
2809
|
ok: true,
|
|
2251
2810
|
fallbackToStaticContext: false,
|
|
2252
2811
|
hardRequirementViolated: false,
|
|
@@ -2258,8 +2817,15 @@ export function compileRuntimeContext(input) {
|
|
|
2258
2817
|
};
|
|
2259
2818
|
}
|
|
2260
2819
|
catch (error) {
|
|
2261
|
-
|
|
2820
|
+
result = classifyCompileFailure(error, activationRoot);
|
|
2262
2821
|
}
|
|
2822
|
+
appendCompileServeRouteDecisionLog({
|
|
2823
|
+
compileInput: input,
|
|
2824
|
+
activationRoot: result.activationRoot,
|
|
2825
|
+
compileResult: result,
|
|
2826
|
+
userMessage
|
|
2827
|
+
});
|
|
2828
|
+
return result;
|
|
2263
2829
|
}
|
|
2264
2830
|
function readDiagnosticNoteValue(notes, prefix) {
|
|
2265
2831
|
const note = notes.find((entry) => entry.startsWith(prefix));
|
|
@@ -3082,29 +3648,35 @@ export function writeScannedEventExportBundle(input) {
|
|
|
3082
3648
|
});
|
|
3083
3649
|
}
|
|
3084
3650
|
export function runRuntimeTurn(turn, options = {}) {
|
|
3651
|
+
const warnings = [];
|
|
3652
|
+
const serveRouteBreadcrumbs = buildRunRuntimeTurnServeRouteBreadcrumbs();
|
|
3085
3653
|
const agentId = normalizeOptionalString(turn.agentId);
|
|
3086
3654
|
const compileInput = {
|
|
3087
|
-
activationRoot: options.activationRoot ??
|
|
3088
|
-
message:
|
|
3655
|
+
activationRoot: (options.activationRoot ?? turn.activationRoot),
|
|
3656
|
+
message: turn.userMessage,
|
|
3089
3657
|
...(agentId !== undefined ? { agentId } : {}),
|
|
3090
3658
|
...(turn.maxContextBlocks !== undefined ? { maxContextBlocks: turn.maxContextBlocks } : {}),
|
|
3091
3659
|
...(turn.budgetStrategy !== undefined ? { budgetStrategy: turn.budgetStrategy } : {}),
|
|
3092
3660
|
...(turn.mode !== undefined ? { mode: turn.mode } : {}),
|
|
3093
|
-
...(turn.
|
|
3661
|
+
...(turn.selectionMode !== undefined ? { selectionMode: turn.selectionMode } : {}),
|
|
3662
|
+
...(turn.runtimeHints !== undefined ? { runtimeHints: turn.runtimeHints } : {}),
|
|
3663
|
+
_suppressServeLog: true
|
|
3094
3664
|
};
|
|
3095
3665
|
const compileResult = compileRuntimeContext(compileInput);
|
|
3096
|
-
const warnings = [];
|
|
3097
3666
|
const serveLoggedAt = turn.compile?.createdAt ?? turn.createdAt ?? new Date().toISOString();
|
|
3098
3667
|
if (!compileResult.ok && compileResult.hardRequirementViolated) {
|
|
3099
3668
|
try {
|
|
3100
3669
|
appendServeTimeRouteDecisionLog({
|
|
3101
|
-
activationRoot:
|
|
3670
|
+
activationRoot: compileResult.activationRoot,
|
|
3102
3671
|
turn,
|
|
3103
3672
|
compileResult,
|
|
3104
|
-
recordedAt: serveLoggedAt
|
|
3673
|
+
recordedAt: serveLoggedAt,
|
|
3674
|
+
breadcrumbs: serveRouteBreadcrumbs
|
|
3105
3675
|
});
|
|
3106
3676
|
}
|
|
3107
|
-
catch {
|
|
3677
|
+
catch (error) {
|
|
3678
|
+
console.warn(`[openclawbrain] serve-time route decision log failed before hard-fail throw: ${toErrorMessage(error)} ` +
|
|
3679
|
+
`(activationRoot=${compileResult.activationRoot}, sessionId=${turn.sessionId}, channel=${turn.channel})`);
|
|
3108
3680
|
}
|
|
3109
3681
|
throw new Error(compileResult.error);
|
|
3110
3682
|
}
|
|
@@ -3113,27 +3685,48 @@ export function runRuntimeTurn(turn, options = {}) {
|
|
|
3113
3685
|
try {
|
|
3114
3686
|
const compileEvent = normalizedEventExport.interactionEvents.find((event) => event.kind === "memory_compiled");
|
|
3115
3687
|
appendServeTimeRouteDecisionLog({
|
|
3116
|
-
activationRoot:
|
|
3688
|
+
activationRoot: compileResult.activationRoot,
|
|
3117
3689
|
turn,
|
|
3118
3690
|
compileResult,
|
|
3119
3691
|
normalizedEventExport,
|
|
3120
|
-
recordedAt: compileEvent?.createdAt ?? serveLoggedAt
|
|
3692
|
+
recordedAt: compileEvent?.createdAt ?? serveLoggedAt,
|
|
3693
|
+
breadcrumbs: serveRouteBreadcrumbs
|
|
3121
3694
|
});
|
|
3122
3695
|
}
|
|
3123
3696
|
catch (error) {
|
|
3124
|
-
warnings.push(
|
|
3697
|
+
warnings.push(buildServeRouteLogFailOpenWarning("runRuntimeTurn", error));
|
|
3698
|
+
if (compileResult.ok) {
|
|
3699
|
+
compileResult.compileResponse.diagnostics.notes = uniqueNotes([
|
|
3700
|
+
...compileResult.compileResponse.diagnostics.notes,
|
|
3701
|
+
...buildServeRouteLogFailOpenNotes("runRuntimeTurn", error)
|
|
3702
|
+
]);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
try {
|
|
3706
|
+
const eventExport = writeRuntimeEventExportBundle(turn, normalizedEventExport);
|
|
3707
|
+
return {
|
|
3708
|
+
...compileResult,
|
|
3709
|
+
eventExport,
|
|
3710
|
+
warnings
|
|
3711
|
+
};
|
|
3712
|
+
}
|
|
3713
|
+
catch (error) {
|
|
3714
|
+
if (options.failOpen === false) {
|
|
3715
|
+
throw error;
|
|
3716
|
+
}
|
|
3717
|
+
warnings.push(toErrorMessage(error));
|
|
3718
|
+
return {
|
|
3719
|
+
...compileResult,
|
|
3720
|
+
eventExport: {
|
|
3721
|
+
ok: false,
|
|
3722
|
+
wroteBundle: false,
|
|
3723
|
+
error: toErrorMessage(error)
|
|
3724
|
+
},
|
|
3725
|
+
warnings
|
|
3726
|
+
};
|
|
3125
3727
|
}
|
|
3126
|
-
const eventExport = writeRuntimeEventExportBundle(turn, normalizedEventExport);
|
|
3127
|
-
return {
|
|
3128
|
-
...compileResult,
|
|
3129
|
-
eventExport,
|
|
3130
|
-
warnings
|
|
3131
|
-
};
|
|
3132
3728
|
}
|
|
3133
3729
|
catch (error) {
|
|
3134
|
-
if (options.failOpen === false) {
|
|
3135
|
-
throw error;
|
|
3136
|
-
}
|
|
3137
3730
|
warnings.push(toErrorMessage(error));
|
|
3138
3731
|
return {
|
|
3139
3732
|
...compileResult,
|
|
@@ -4117,6 +4710,144 @@ function summarizeOperatorSlot(slot, updatedAt) {
|
|
|
4117
4710
|
findings: [...slot.findings]
|
|
4118
4711
|
};
|
|
4119
4712
|
}
|
|
4713
|
+
function buildMissingLabelFlowSummary(detail) {
|
|
4714
|
+
return {
|
|
4715
|
+
source: "missing",
|
|
4716
|
+
humanLabelCount: null,
|
|
4717
|
+
selfLabelCount: null,
|
|
4718
|
+
asyncTeacherArtifactCount: null,
|
|
4719
|
+
implicitPositiveCount: null,
|
|
4720
|
+
detail
|
|
4721
|
+
};
|
|
4722
|
+
}
|
|
4723
|
+
function buildMissingLearningPathSummary(detail) {
|
|
4724
|
+
return {
|
|
4725
|
+
available: false,
|
|
4726
|
+
source: "missing",
|
|
4727
|
+
policyGradientVersion: "unavailable",
|
|
4728
|
+
policyGradientMethod: null,
|
|
4729
|
+
objective: null,
|
|
4730
|
+
targetConstruction: null,
|
|
4731
|
+
connectOpsFired: null,
|
|
4732
|
+
reconstructedTrajectoryCount: null,
|
|
4733
|
+
detail
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
function countTeacherArtifactBlocks(blocks) {
|
|
4737
|
+
return blocks.filter((block) => block.learning.role === "teacher_supervision" && !block.id.endsWith(":teacher-supervision-summary")).length;
|
|
4738
|
+
}
|
|
4739
|
+
function summarizePolicyGradientVersion(targetConstruction) {
|
|
4740
|
+
if (targetConstruction === "trajectory_reconstruction") {
|
|
4741
|
+
return "v2";
|
|
4742
|
+
}
|
|
4743
|
+
if (targetConstruction === "event_block_plus_related_interaction") {
|
|
4744
|
+
return "v1";
|
|
4745
|
+
}
|
|
4746
|
+
return "unavailable";
|
|
4747
|
+
}
|
|
4748
|
+
function summarizePackLabelFlow(source, pack) {
|
|
4749
|
+
const labelHarvest = pack.manifest.provenance.learningSurface.labelHarvest;
|
|
4750
|
+
return {
|
|
4751
|
+
source,
|
|
4752
|
+
humanLabelCount: labelHarvest.humanLabels,
|
|
4753
|
+
selfLabelCount: labelHarvest.selfLabels,
|
|
4754
|
+
asyncTeacherArtifactCount: countTeacherArtifactBlocks(pack.graph.blocks),
|
|
4755
|
+
implicitPositiveCount: labelHarvest.approvals,
|
|
4756
|
+
detail: source === "active_pack"
|
|
4757
|
+
? "active pack label harvest and teacher artifacts are visible"
|
|
4758
|
+
: source === "materialized_candidate"
|
|
4759
|
+
? "materialized candidate label harvest and teacher artifacts are visible"
|
|
4760
|
+
: "event export label harvest is visible"
|
|
4761
|
+
};
|
|
4762
|
+
}
|
|
4763
|
+
function summarizePackLearningPath(source, pack) {
|
|
4764
|
+
const targetConstruction = pack.router?.training.objective.profile.targetConstruction ?? null;
|
|
4765
|
+
const policyGradientVersion = summarizePolicyGradientVersion(targetConstruction);
|
|
4766
|
+
const reconstructedTrajectoryCount = policyGradientVersion === "v2"
|
|
4767
|
+
? pack.router?.training.routeTraceCount ?? 0
|
|
4768
|
+
: pack.router === null
|
|
4769
|
+
? null
|
|
4770
|
+
: 0;
|
|
4771
|
+
return {
|
|
4772
|
+
available: pack.router !== null,
|
|
4773
|
+
source,
|
|
4774
|
+
policyGradientVersion,
|
|
4775
|
+
policyGradientMethod: pack.router?.training.method ?? null,
|
|
4776
|
+
objective: pack.router?.training.objective.objective ?? null,
|
|
4777
|
+
targetConstruction,
|
|
4778
|
+
connectOpsFired: pack.manifest.graphDynamics.structuralOps.connect,
|
|
4779
|
+
reconstructedTrajectoryCount,
|
|
4780
|
+
detail: pack.router === null
|
|
4781
|
+
? "pack has no learned router artifact"
|
|
4782
|
+
: policyGradientVersion === "v2"
|
|
4783
|
+
? "learned routing uses trajectory-reconstruction PG"
|
|
4784
|
+
: policyGradientVersion === "v1"
|
|
4785
|
+
? "learned routing uses event-reconstruction PG"
|
|
4786
|
+
: "learned routing is present but the PG profile is not recognizable"
|
|
4787
|
+
};
|
|
4788
|
+
}
|
|
4789
|
+
function summarizePackObservability(source, pack) {
|
|
4790
|
+
return {
|
|
4791
|
+
labelFlow: summarizePackLabelFlow(source, pack),
|
|
4792
|
+
learningPath: summarizePackLearningPath(source, pack)
|
|
4793
|
+
};
|
|
4794
|
+
}
|
|
4795
|
+
export function summarizeNormalizedEventExportLabelFlow(normalizedEventExport, asyncTeacherArtifactCount = 0) {
|
|
4796
|
+
const labelHarvest = normalizedEventExport.provenance.learningSurface.labelHarvest;
|
|
4797
|
+
return {
|
|
4798
|
+
source: "event_export",
|
|
4799
|
+
humanLabelCount: labelHarvest.humanLabels,
|
|
4800
|
+
selfLabelCount: labelHarvest.selfLabels,
|
|
4801
|
+
asyncTeacherArtifactCount,
|
|
4802
|
+
implicitPositiveCount: labelHarvest.approvals,
|
|
4803
|
+
detail: "event export label harvest is visible"
|
|
4804
|
+
};
|
|
4805
|
+
}
|
|
4806
|
+
export function summarizeLearningPathFromMaterialization(materialization) {
|
|
4807
|
+
if (materialization === null) {
|
|
4808
|
+
return buildMissingLearningPathSummary("no candidate pack materialized during this learning pass");
|
|
4809
|
+
}
|
|
4810
|
+
return summarizePackLearningPath("materialized_candidate", {
|
|
4811
|
+
manifest: materialization.candidate.manifest,
|
|
4812
|
+
graph: materialization.candidate.payloads.graph,
|
|
4813
|
+
router: materialization.candidate.payloads.router
|
|
4814
|
+
});
|
|
4815
|
+
}
|
|
4816
|
+
function summarizeActivePackObservability(activationRoot, active) {
|
|
4817
|
+
if (active === null) {
|
|
4818
|
+
return {
|
|
4819
|
+
labelFlow: buildMissingLabelFlowSummary("no active pack is attached"),
|
|
4820
|
+
learningPath: buildMissingLearningPathSummary("no active pack is attached")
|
|
4821
|
+
};
|
|
4822
|
+
}
|
|
4823
|
+
if (!active.activationReady) {
|
|
4824
|
+
return {
|
|
4825
|
+
labelFlow: buildMissingLabelFlowSummary(`active pack ${active.packId} is not activation-ready`),
|
|
4826
|
+
learningPath: buildMissingLearningPathSummary(`active pack ${active.packId} is not activation-ready`)
|
|
4827
|
+
};
|
|
4828
|
+
}
|
|
4829
|
+
try {
|
|
4830
|
+
const pack = loadPackFromActivation(activationRoot, "active", { requireActivationReady: true });
|
|
4831
|
+
if (pack === null) {
|
|
4832
|
+
return {
|
|
4833
|
+
labelFlow: buildMissingLabelFlowSummary("active pack payloads are unavailable"),
|
|
4834
|
+
learningPath: buildMissingLearningPathSummary("active pack payloads are unavailable")
|
|
4835
|
+
};
|
|
4836
|
+
}
|
|
4837
|
+
return summarizePackObservability("active_pack", {
|
|
4838
|
+
manifest: pack.manifest,
|
|
4839
|
+
graph: pack.graph,
|
|
4840
|
+
router: pack.router
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
catch (error) {
|
|
4844
|
+
const detail = `active pack observability could not be loaded: ${toErrorMessage(error)}`;
|
|
4845
|
+
return {
|
|
4846
|
+
labelFlow: buildMissingLabelFlowSummary(detail),
|
|
4847
|
+
learningPath: buildMissingLearningPathSummary(detail)
|
|
4848
|
+
};
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4120
4851
|
function summarizeLastPromotion(inspection) {
|
|
4121
4852
|
if (inspection.active === null) {
|
|
4122
4853
|
return {
|
|
@@ -4183,9 +4914,137 @@ function summarizeManyProfileSupport(policyMode) {
|
|
|
4183
4914
|
detail: "The Host has not declared shared-vs-dedicated attachment policy. Keep the operator read current-profile-only, do not infer profile exclusivity from activation state alone, and do not claim same-gateway many-profile proof."
|
|
4184
4915
|
};
|
|
4185
4916
|
}
|
|
4917
|
+
function summarizeRetainedActivationSlots(input) {
|
|
4918
|
+
const retained = [];
|
|
4919
|
+
if (input.candidate !== null) {
|
|
4920
|
+
retained.push(`candidate=${input.candidate.packId}`);
|
|
4921
|
+
}
|
|
4922
|
+
if (input.previous !== null) {
|
|
4923
|
+
retained.push(`previous=${input.previous.packId}`);
|
|
4924
|
+
}
|
|
4925
|
+
return retained.length === 0 ? "none" : retained.join(", ");
|
|
4926
|
+
}
|
|
4186
4927
|
function isAwaitingFirstExportSlot(slot) {
|
|
4187
4928
|
return slot !== null && slot.eventRange.count === 0;
|
|
4188
4929
|
}
|
|
4930
|
+
function summarizeOperatorActivationState(input) {
|
|
4931
|
+
if (input.inspectionError !== null) {
|
|
4932
|
+
return {
|
|
4933
|
+
state: "broken_install",
|
|
4934
|
+
detail: `activation root could not be inspected because activation pointers or pinned pack metadata are unreadable: ${input.inspectionError}`,
|
|
4935
|
+
inspectionError: input.inspectionError
|
|
4936
|
+
};
|
|
4937
|
+
}
|
|
4938
|
+
if (input.active !== null && !input.active.activationReady) {
|
|
4939
|
+
return {
|
|
4940
|
+
state: "broken_install",
|
|
4941
|
+
detail: input.active.findings.length > 0
|
|
4942
|
+
? `active pack ${input.active.packId} is pinned but not activation-ready: ${input.active.findings.join("; ")}`
|
|
4943
|
+
: `active pack ${input.active.packId} is pinned but not activation-ready`,
|
|
4944
|
+
inspectionError: null
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
if (input.active === null) {
|
|
4948
|
+
if (input.candidate !== null || input.previous !== null) {
|
|
4949
|
+
return {
|
|
4950
|
+
state: "stale_incomplete",
|
|
4951
|
+
detail: `activation root has retained non-serving state but no active pack (${summarizeRetainedActivationSlots(input)})`,
|
|
4952
|
+
inspectionError: null
|
|
4953
|
+
};
|
|
4954
|
+
}
|
|
4955
|
+
return {
|
|
4956
|
+
state: "detached",
|
|
4957
|
+
detail: "activation root has no active, candidate, or previous pack pinned",
|
|
4958
|
+
inspectionError: null
|
|
4959
|
+
};
|
|
4960
|
+
}
|
|
4961
|
+
if (input.observability === null) {
|
|
4962
|
+
return {
|
|
4963
|
+
state: "broken_install",
|
|
4964
|
+
detail: `active pack ${input.active.packId} is pinned, but activation observability could not be derived`,
|
|
4965
|
+
inspectionError: null
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
if (input.observability.initHandoff.handoffState === "pg_promoted_pack_authoritative") {
|
|
4969
|
+
return {
|
|
4970
|
+
state: "active_promoted",
|
|
4971
|
+
detail: `active pack ${input.active.packId} is authoritative through promotion, not the seed handoff`,
|
|
4972
|
+
inspectionError: null
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
if (isAwaitingFirstExportSlot(input.active)) {
|
|
4976
|
+
return {
|
|
4977
|
+
state: "awaiting_first_export",
|
|
4978
|
+
detail: `active seed-state pack ${input.active.packId} is healthy but still waiting for the first live export`,
|
|
4979
|
+
inspectionError: null
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4982
|
+
if (input.observability.initHandoff.handoffState === "seed_state_authoritative") {
|
|
4983
|
+
return {
|
|
4984
|
+
state: "healthy_seed",
|
|
4985
|
+
detail: `active seed-state pack ${input.active.packId} is serving beyond the first export`,
|
|
4986
|
+
inspectionError: null
|
|
4987
|
+
};
|
|
4988
|
+
}
|
|
4989
|
+
return {
|
|
4990
|
+
state: "stale_incomplete",
|
|
4991
|
+
detail: `active pack ${input.active.packId} is pinned, but init handoff truth is incomplete (${input.observability.initHandoff.handoffState})`,
|
|
4992
|
+
inspectionError: null
|
|
4993
|
+
};
|
|
4994
|
+
}
|
|
4995
|
+
function summarizeBrainStateWithoutObservability(active, activation) {
|
|
4996
|
+
return {
|
|
4997
|
+
state: active === null ? "no_active_pack" : "missing",
|
|
4998
|
+
initMode: null,
|
|
4999
|
+
runtimePlasticitySource: null,
|
|
5000
|
+
seedStateVisible: false,
|
|
5001
|
+
seedBlockCount: 0,
|
|
5002
|
+
activePackId: active?.packId ?? null,
|
|
5003
|
+
activeWorkspaceSnapshot: active?.workspaceSnapshot ?? null,
|
|
5004
|
+
activeEventExportDigest: active?.eventExportDigest ?? null,
|
|
5005
|
+
detail: activation.detail
|
|
5006
|
+
};
|
|
5007
|
+
}
|
|
5008
|
+
function summarizeGraphWithoutObservability(active, activation) {
|
|
5009
|
+
return {
|
|
5010
|
+
available: false,
|
|
5011
|
+
runtimePlasticitySource: null,
|
|
5012
|
+
structuralOps: null,
|
|
5013
|
+
changed: null,
|
|
5014
|
+
operationsApplied: [],
|
|
5015
|
+
liveBlockCount: null,
|
|
5016
|
+
prunedBlockCount: null,
|
|
5017
|
+
prePruneBlockCount: null,
|
|
5018
|
+
strongestBlockId: null,
|
|
5019
|
+
operatorSummary: null,
|
|
5020
|
+
detail: active === null
|
|
5021
|
+
? activation.detail
|
|
5022
|
+
: `active pack ${active.packId} is pinned, but graph observability is unavailable`
|
|
5023
|
+
};
|
|
5024
|
+
}
|
|
5025
|
+
function summarizeLearnedRoutingWithoutObservability(active) {
|
|
5026
|
+
return {
|
|
5027
|
+
required: active?.routePolicy === "requires_learned_routing",
|
|
5028
|
+
available: false,
|
|
5029
|
+
routerIdentity: active?.routerIdentity ?? null,
|
|
5030
|
+
routeFnVersion: null,
|
|
5031
|
+
trainingMethod: null,
|
|
5032
|
+
routerTrainedAt: null,
|
|
5033
|
+
objective: null,
|
|
5034
|
+
pgProfile: null,
|
|
5035
|
+
routerChecksum: null,
|
|
5036
|
+
objectiveChecksum: null,
|
|
5037
|
+
updateMechanism: null,
|
|
5038
|
+
updateVersion: null,
|
|
5039
|
+
updateCount: null,
|
|
5040
|
+
supervisionCount: null,
|
|
5041
|
+
collectedLabelsTotal: null,
|
|
5042
|
+
freshnessChecksum: null,
|
|
5043
|
+
handoffState: "missing",
|
|
5044
|
+
initMode: null,
|
|
5045
|
+
seedStateVisible: false
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
4189
5048
|
function summarizeBrainState(active, observability) {
|
|
4190
5049
|
if (active === null) {
|
|
4191
5050
|
return {
|
|
@@ -4339,6 +5198,11 @@ function summarizeServePath(compile) {
|
|
|
4339
5198
|
error: compile.error
|
|
4340
5199
|
};
|
|
4341
5200
|
}
|
|
5201
|
+
function probeOperatorServePath(activationRoot, observability, activePackId) {
|
|
5202
|
+
const compileInput = buildAttachStatusCompileInput(activationRoot, undefined);
|
|
5203
|
+
const compile = compileInput === null ? null : buildAttachCompileStatus(compileRuntimeContext(compileInput), observability, activePackId);
|
|
5204
|
+
return summarizeServePath(compile);
|
|
5205
|
+
}
|
|
4342
5206
|
function loadOperatorEventExport(input) {
|
|
4343
5207
|
const eventExportPath = normalizeOptionalString(input.eventExportPath);
|
|
4344
5208
|
if (eventExportPath === undefined) {
|
|
@@ -4527,62 +5391,125 @@ function summarizeSupervision(input) {
|
|
|
4527
5391
|
: "the supplied export does not yet show human supervision"
|
|
4528
5392
|
};
|
|
4529
5393
|
}
|
|
4530
|
-
function
|
|
5394
|
+
function loadTeacherSurfaceFromInput(input) {
|
|
4531
5395
|
const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
|
|
4532
5396
|
if (teacherSnapshotPath === undefined) {
|
|
4533
5397
|
return null;
|
|
4534
5398
|
}
|
|
4535
|
-
|
|
4536
|
-
if (snapshot.runtimeOwner !== "openclaw") {
|
|
4537
|
-
throw new Error("teacher snapshot runtimeOwner must be openclaw");
|
|
4538
|
-
}
|
|
4539
|
-
return snapshot;
|
|
5399
|
+
return loadTeacherSurface(teacherSnapshotPath);
|
|
4540
5400
|
}
|
|
4541
5401
|
function summarizeTeacherLoop(input) {
|
|
4542
|
-
const
|
|
4543
|
-
if (teacherSnapshotPath === undefined) {
|
|
5402
|
+
const loaded = loadTeacherSurfaceFromInput(input);
|
|
5403
|
+
if (loaded === null && normalizeOptionalString(input.teacherSnapshotPath) === undefined) {
|
|
4544
5404
|
return {
|
|
4545
5405
|
available: false,
|
|
4546
5406
|
sourcePath: null,
|
|
5407
|
+
sourceKind: "missing",
|
|
5408
|
+
lastRunAt: null,
|
|
4547
5409
|
lastNoOpReason: "unavailable",
|
|
4548
5410
|
latestFreshness: "unavailable",
|
|
5411
|
+
startedAt: null,
|
|
5412
|
+
lastHeartbeatAt: null,
|
|
5413
|
+
lastScanAt: null,
|
|
4549
5414
|
lastProcessedAt: null,
|
|
5415
|
+
artifactCount: null,
|
|
4550
5416
|
queueDepth: null,
|
|
4551
5417
|
queueCapacity: null,
|
|
4552
5418
|
running: null,
|
|
5419
|
+
replayedBundleCount: null,
|
|
5420
|
+
replayedEventCount: null,
|
|
5421
|
+
exportedBundleCount: null,
|
|
5422
|
+
exportedEventCount: null,
|
|
5423
|
+
sessionTailSessionsTracked: null,
|
|
5424
|
+
sessionTailBridgedEventCount: null,
|
|
5425
|
+
localSessionTailNoopReason: null,
|
|
5426
|
+
learningCadence: "unavailable",
|
|
5427
|
+
scanPolicy: "unavailable",
|
|
5428
|
+
liveSlicesPerCycle: null,
|
|
5429
|
+
backfillSlicesPerCycle: null,
|
|
5430
|
+
failureMode: "unavailable",
|
|
5431
|
+
failureDetail: null,
|
|
5432
|
+
lastAppliedMaterializationJobId: null,
|
|
4553
5433
|
lastMaterializedPackId: null,
|
|
4554
5434
|
notes: [],
|
|
4555
5435
|
detail: "no teacher snapshot path supplied"
|
|
4556
5436
|
};
|
|
4557
5437
|
}
|
|
4558
|
-
|
|
4559
|
-
|
|
5438
|
+
if (loaded === null) {
|
|
5439
|
+
const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
|
|
4560
5440
|
return {
|
|
4561
5441
|
available: false,
|
|
4562
|
-
sourcePath: path.resolve(teacherSnapshotPath),
|
|
5442
|
+
sourcePath: teacherSnapshotPath === undefined ? null : path.resolve(teacherSnapshotPath),
|
|
5443
|
+
sourceKind: "missing",
|
|
5444
|
+
lastRunAt: null,
|
|
4563
5445
|
lastNoOpReason: "unavailable",
|
|
4564
5446
|
latestFreshness: "unavailable",
|
|
5447
|
+
startedAt: null,
|
|
5448
|
+
lastHeartbeatAt: null,
|
|
5449
|
+
lastScanAt: null,
|
|
4565
5450
|
lastProcessedAt: null,
|
|
5451
|
+
artifactCount: null,
|
|
4566
5452
|
queueDepth: null,
|
|
4567
5453
|
queueCapacity: null,
|
|
4568
5454
|
running: null,
|
|
5455
|
+
replayedBundleCount: null,
|
|
5456
|
+
replayedEventCount: null,
|
|
5457
|
+
exportedBundleCount: null,
|
|
5458
|
+
exportedEventCount: null,
|
|
5459
|
+
sessionTailSessionsTracked: null,
|
|
5460
|
+
sessionTailBridgedEventCount: null,
|
|
5461
|
+
localSessionTailNoopReason: null,
|
|
5462
|
+
learningCadence: "unavailable",
|
|
5463
|
+
scanPolicy: "unavailable",
|
|
5464
|
+
liveSlicesPerCycle: null,
|
|
5465
|
+
backfillSlicesPerCycle: null,
|
|
5466
|
+
failureMode: "unavailable",
|
|
5467
|
+
failureDetail: null,
|
|
5468
|
+
lastAppliedMaterializationJobId: null,
|
|
4569
5469
|
lastMaterializedPackId: null,
|
|
4570
5470
|
notes: [],
|
|
4571
5471
|
detail: "teacher snapshot could not be loaded"
|
|
4572
5472
|
};
|
|
4573
5473
|
}
|
|
5474
|
+
const snapshot = loaded.snapshot;
|
|
5475
|
+
const watchSnapshot = loaded.watchSnapshot;
|
|
4574
5476
|
return {
|
|
4575
5477
|
available: true,
|
|
4576
|
-
sourcePath:
|
|
5478
|
+
sourcePath: loaded.sourcePath,
|
|
5479
|
+
sourceKind: loaded.sourceKind,
|
|
5480
|
+
lastRunAt: watchSnapshot?.lastRunAt ?? snapshot.runtime?.lastHeartbeatAt ?? snapshot.diagnostics.lastProcessedAt ?? null,
|
|
4577
5481
|
lastNoOpReason: snapshot.diagnostics.lastNoOpReason,
|
|
4578
5482
|
latestFreshness: snapshot.diagnostics.latestFreshness,
|
|
5483
|
+
startedAt: snapshot.runtime?.startedAt ?? null,
|
|
5484
|
+
lastHeartbeatAt: snapshot.runtime?.lastHeartbeatAt ?? null,
|
|
5485
|
+
lastScanAt: snapshot.runtime?.lastScanAt ?? null,
|
|
4579
5486
|
lastProcessedAt: snapshot.diagnostics.lastProcessedAt,
|
|
5487
|
+
artifactCount: watchSnapshot?.teacher.artifactCount ?? snapshot.teacher.artifactCount,
|
|
4580
5488
|
queueDepth: snapshot.queue.depth,
|
|
4581
5489
|
queueCapacity: snapshot.queue.capacity,
|
|
4582
5490
|
running: snapshot.queue.running,
|
|
5491
|
+
replayedBundleCount: watchSnapshot?.replayedBundleCount ?? null,
|
|
5492
|
+
replayedEventCount: watchSnapshot?.replayedEventCount ?? null,
|
|
5493
|
+
exportedBundleCount: watchSnapshot?.exportedBundleCount ?? null,
|
|
5494
|
+
exportedEventCount: watchSnapshot?.exportedEventCount ?? null,
|
|
5495
|
+
sessionTailSessionsTracked: watchSnapshot?.sessionTailSessionsTracked ?? null,
|
|
5496
|
+
sessionTailBridgedEventCount: watchSnapshot?.sessionTailBridgedEventCount ?? null,
|
|
5497
|
+
localSessionTailNoopReason: watchSnapshot?.localSessionTailNoopReason ?? null,
|
|
5498
|
+
learningCadence: watchSnapshot?.labeling.learningCadence ?? "unavailable",
|
|
5499
|
+
scanPolicy: watchSnapshot?.labeling.scanPolicy ?? "unavailable",
|
|
5500
|
+
liveSlicesPerCycle: watchSnapshot?.labeling.liveSlicesPerCycle ?? null,
|
|
5501
|
+
backfillSlicesPerCycle: watchSnapshot?.labeling.backfillSlicesPerCycle ?? null,
|
|
5502
|
+
failureMode: watchSnapshot?.failure?.mode ?? "none",
|
|
5503
|
+
failureDetail: watchSnapshot?.failure?.detail ?? null,
|
|
5504
|
+
lastAppliedMaterializationJobId: watchSnapshot?.teacher.lastAppliedMaterializationJobId ??
|
|
5505
|
+
snapshot.runtime?.lastAppliedMaterializationJobId ??
|
|
5506
|
+
snapshot.learner.lastMaterialization?.jobId ??
|
|
5507
|
+
null,
|
|
4583
5508
|
lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null,
|
|
4584
5509
|
notes: [...snapshot.diagnostics.notes],
|
|
4585
|
-
detail:
|
|
5510
|
+
detail: loaded.sourceKind === "watch_snapshot"
|
|
5511
|
+
? "canonical watch teacher snapshot loaded"
|
|
5512
|
+
: "raw async teacher snapshot loaded"
|
|
4586
5513
|
};
|
|
4587
5514
|
}
|
|
4588
5515
|
function summarizeLearningBacklogState(plan, principalLagStatus) {
|
|
@@ -4639,8 +5566,8 @@ function summarizeAlwaysOnLearning(input, active) {
|
|
|
4639
5566
|
sequenceLag: null,
|
|
4640
5567
|
status: "unavailable"
|
|
4641
5568
|
};
|
|
4642
|
-
const
|
|
4643
|
-
if (teacherSnapshotPath === undefined) {
|
|
5569
|
+
const loadedTeacherSurface = loadTeacherSurfaceFromInput(input);
|
|
5570
|
+
if (loadedTeacherSurface === null && normalizeOptionalString(input.teacherSnapshotPath) === undefined) {
|
|
4644
5571
|
return {
|
|
4645
5572
|
available: false,
|
|
4646
5573
|
sourcePath: null,
|
|
@@ -4672,11 +5599,11 @@ function summarizeAlwaysOnLearning(input, active) {
|
|
|
4672
5599
|
detail: "no teacher snapshot path supplied"
|
|
4673
5600
|
};
|
|
4674
5601
|
}
|
|
4675
|
-
|
|
4676
|
-
|
|
5602
|
+
if (loadedTeacherSurface === null) {
|
|
5603
|
+
const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
|
|
4677
5604
|
return {
|
|
4678
5605
|
available: false,
|
|
4679
|
-
sourcePath: path.resolve(teacherSnapshotPath),
|
|
5606
|
+
sourcePath: teacherSnapshotPath === undefined ? null : path.resolve(teacherSnapshotPath),
|
|
4680
5607
|
bootstrapped: null,
|
|
4681
5608
|
mode: "unavailable",
|
|
4682
5609
|
nextPriorityLane: "unavailable",
|
|
@@ -4705,6 +5632,7 @@ function summarizeAlwaysOnLearning(input, active) {
|
|
|
4705
5632
|
detail: "teacher snapshot could not be loaded"
|
|
4706
5633
|
};
|
|
4707
5634
|
}
|
|
5635
|
+
const snapshot = loadedTeacherSurface.snapshot;
|
|
4708
5636
|
const plan = describeAlwaysOnLearningRuntimeState(snapshot.learner.state, snapshot.learner.lastMaterialization);
|
|
4709
5637
|
const latestPrincipalSequence = plan.principalBacklog.checkpoints.reduce((latest, checkpoint) => {
|
|
4710
5638
|
const candidate = checkpoint.newestPendingSequence ?? checkpoint.learnedThroughSequence;
|
|
@@ -4730,7 +5658,7 @@ function summarizeAlwaysOnLearning(input, active) {
|
|
|
4730
5658
|
});
|
|
4731
5659
|
return {
|
|
4732
5660
|
available: true,
|
|
4733
|
-
sourcePath:
|
|
5661
|
+
sourcePath: loadedTeacherSurface.sourcePath,
|
|
4734
5662
|
bootstrapped: plan.bootstrapped,
|
|
4735
5663
|
mode: plan.mode,
|
|
4736
5664
|
nextPriorityLane: plan.nextPriorityLane,
|
|
@@ -4779,7 +5707,13 @@ function buildOperatorFindings(report) {
|
|
|
4779
5707
|
const push = (severity, code, summary, detail) => {
|
|
4780
5708
|
findings.push({ severity, code, summary, detail });
|
|
4781
5709
|
};
|
|
4782
|
-
if (report.
|
|
5710
|
+
if (report.activation.state === "broken_install") {
|
|
5711
|
+
push("fail", "activation_broken_install", "activation root is broken", report.activation.detail);
|
|
5712
|
+
}
|
|
5713
|
+
else if (report.activation.state === "stale_incomplete") {
|
|
5714
|
+
push("fail", "activation_stale_incomplete", "activation root is stale or incomplete", report.activation.detail);
|
|
5715
|
+
}
|
|
5716
|
+
else if (report.active === null) {
|
|
4783
5717
|
push("fail", "active_missing", "active slot is empty", "no active pack found; this is the pre-bootstrap state — call `bootstrapRuntimeAttach()` to activate an initial pack before compiling or serving");
|
|
4784
5718
|
}
|
|
4785
5719
|
else if (!report.active.activationReady) {
|
|
@@ -4920,12 +5854,18 @@ function summarizeCurrentProfileLogRoot(activationRoot) {
|
|
|
4920
5854
|
const logRoot = path.join(path.resolve(activationRoot), LEARNING_SPINE_LOG_LAYOUT.dir);
|
|
4921
5855
|
return existsSync(logRoot) ? logRoot : null;
|
|
4922
5856
|
}
|
|
4923
|
-
function summarizeCurrentProfileLastLearningUpdateAt(activationRoot, learning) {
|
|
5857
|
+
function summarizeCurrentProfileLastLearningUpdateAt(activationRoot, learning, teacherLoop) {
|
|
4924
5858
|
const updates = readLearningSpineLogEntries(activationRoot, "pgRouteUpdates");
|
|
4925
|
-
return updates.at(-1)?.recordedAt ?? learning.lastMaterializedAt ?? null;
|
|
5859
|
+
return updates.at(-1)?.recordedAt ?? teacherLoop.lastRunAt ?? learning.lastMaterializedAt ?? null;
|
|
4926
5860
|
}
|
|
4927
5861
|
function summarizeCurrentProfileBrainSummary(input) {
|
|
4928
5862
|
const packId = input.activePackId ?? "unknown";
|
|
5863
|
+
if (input.activationState === "broken_install") {
|
|
5864
|
+
return "Brain activation is broken and needs repair before serve-path truth can be trusted.";
|
|
5865
|
+
}
|
|
5866
|
+
if (input.activationState === "stale_incomplete") {
|
|
5867
|
+
return "Brain activation has retained stale/incomplete state and no serving active pack.";
|
|
5868
|
+
}
|
|
4929
5869
|
if (!input.attached) {
|
|
4930
5870
|
return "Brain is not attached to the current Profile.";
|
|
4931
5871
|
}
|
|
@@ -4961,6 +5901,7 @@ function summarizeCurrentProfileBrainStatusLevel(input) {
|
|
|
4961
5901
|
function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId) {
|
|
4962
5902
|
const attached = report.active !== null;
|
|
4963
5903
|
const awaitingFirstExport = isAwaitingFirstExportSlot(report.active);
|
|
5904
|
+
const activationState = report.activation.state;
|
|
4964
5905
|
const routerIdentity = report.servePath.routerIdentity ?? report.learnedRouting.routerIdentity ?? report.active?.routerIdentity ?? null;
|
|
4965
5906
|
const routeFreshness = report.servePath.refreshStatus === "updated" || report.servePath.refreshStatus === "no_supervision"
|
|
4966
5907
|
? report.servePath.refreshStatus
|
|
@@ -4999,16 +5940,20 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
|
|
|
4999
5940
|
routerIdentity,
|
|
5000
5941
|
routerChecksum: report.learnedRouting.routerChecksum,
|
|
5001
5942
|
lastExportAt: report.supervision.exportedAt,
|
|
5002
|
-
lastLearningUpdateAt: summarizeCurrentProfileLastLearningUpdateAt(report.activationRoot, report.learning),
|
|
5943
|
+
lastLearningUpdateAt: summarizeCurrentProfileLastLearningUpdateAt(report.activationRoot, report.learning, report.teacherLoop),
|
|
5003
5944
|
lastPromotionAt: report.promotion.lastPromotion.at,
|
|
5004
5945
|
summary: summarizeCurrentProfileBrainSummary({
|
|
5946
|
+
activationState,
|
|
5005
5947
|
attached,
|
|
5006
5948
|
serveState: report.servePath.state,
|
|
5007
5949
|
brainState: report.brain.state,
|
|
5008
5950
|
awaitingFirstExport,
|
|
5009
|
-
activePackId
|
|
5951
|
+
activePackId,
|
|
5952
|
+
activationDetail: report.activation.detail
|
|
5010
5953
|
}),
|
|
5011
|
-
detail:
|
|
5954
|
+
detail: activationState === "broken_install" || activationState === "stale_incomplete" || activationState === "detached"
|
|
5955
|
+
? report.activation.detail
|
|
5956
|
+
: report.brain.detail
|
|
5012
5957
|
},
|
|
5013
5958
|
attachment: attached
|
|
5014
5959
|
? {
|
|
@@ -5037,21 +5982,28 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
|
|
|
5037
5982
|
status,
|
|
5038
5983
|
brainState: report.brain.state,
|
|
5039
5984
|
serveState: report.servePath.state,
|
|
5985
|
+
activationState,
|
|
5040
5986
|
usedLearnedRouteFn: report.servePath.usedLearnedRouteFn,
|
|
5041
5987
|
failOpen: report.servePath.fallbackToStaticContext,
|
|
5042
5988
|
awaitingFirstExport,
|
|
5043
5989
|
structuralDecision: report.servePath.structuralDecision,
|
|
5044
|
-
detail:
|
|
5045
|
-
?
|
|
5046
|
-
|
|
5047
|
-
: report.
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5990
|
+
detail: activationState === "broken_install"
|
|
5991
|
+
? `current profile activation is broken: ${report.activation.detail}`
|
|
5992
|
+
: activationState === "stale_incomplete"
|
|
5993
|
+
? `current profile activation is stale/incomplete: ${report.activation.detail}`
|
|
5994
|
+
: activationState === "detached"
|
|
5995
|
+
? "current profile has no attached active pack at the activation boundary"
|
|
5996
|
+
: report.servePath.state === "serving_active_pack"
|
|
5997
|
+
? awaitingFirstExport
|
|
5998
|
+
? `current profile is serving seed-state pack ${activePackId ?? "unknown"} while awaiting the first exported turn`
|
|
5999
|
+
: report.brain.state === "pg_promoted_pack_authoritative"
|
|
6000
|
+
? `current profile is serving promoted pack ${activePackId ?? "unknown"}; serve-visible change came from activation promotion, not hot-path mutation`
|
|
6001
|
+
: `current profile is serving active pack ${activePackId ?? "unknown"}; learned routing is active, but authority is still seed-state`
|
|
6002
|
+
: report.servePath.state === "fail_open_static_context"
|
|
6003
|
+
? "current profile would fail open to static context because no serving pack is available"
|
|
6004
|
+
: report.servePath.state === "hard_fail"
|
|
6005
|
+
? "current profile cannot serve because the learned-route or activation requirement hard-failed"
|
|
6006
|
+
: "current profile serve state has not been compile-probed yet"
|
|
5055
6007
|
},
|
|
5056
6008
|
currentTurnAttribution: null
|
|
5057
6009
|
};
|
|
@@ -5060,59 +6012,100 @@ export function buildOperatorSurfaceReport(input) {
|
|
|
5060
6012
|
const activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
|
|
5061
6013
|
const updatedAt = normalizeIsoTimestamp(input.updatedAt, "updatedAt", new Date().toISOString());
|
|
5062
6014
|
const brainAttachmentPolicy = normalizeBrainAttachmentPolicy(input.brainAttachmentPolicy);
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
6015
|
+
let inspection = null;
|
|
6016
|
+
let observability = null;
|
|
6017
|
+
let inspectionError = null;
|
|
6018
|
+
try {
|
|
6019
|
+
inspection = inspectActivationState(activationRoot, updatedAt);
|
|
6020
|
+
}
|
|
6021
|
+
catch (error) {
|
|
6022
|
+
inspectionError = toErrorMessage(error);
|
|
6023
|
+
}
|
|
6024
|
+
const active = inspection === null ? null : summarizeOperatorSlot(inspection.active, inspection.pointers.active?.updatedAt ?? null);
|
|
6025
|
+
const candidate = inspection === null ? null : summarizeOperatorSlot(inspection.candidate, inspection.pointers.candidate?.updatedAt ?? null);
|
|
6026
|
+
const previous = inspection === null ? null : summarizeOperatorSlot(inspection.previous, inspection.pointers.previous?.updatedAt ?? null);
|
|
6027
|
+
if (inspection !== null && inspection.active !== null) {
|
|
6028
|
+
try {
|
|
6029
|
+
observability = describeActivationObservability(activationRoot, "active", {
|
|
6030
|
+
updatedAt
|
|
6031
|
+
});
|
|
6032
|
+
}
|
|
6033
|
+
catch (error) {
|
|
6034
|
+
inspectionError ??= `activation observability failed: ${toErrorMessage(error)}`;
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
const activation = summarizeOperatorActivationState({
|
|
6038
|
+
inspection,
|
|
6039
|
+
observability,
|
|
6040
|
+
active,
|
|
6041
|
+
candidate,
|
|
6042
|
+
previous,
|
|
6043
|
+
inspectionError
|
|
5066
6044
|
});
|
|
5067
|
-
const
|
|
5068
|
-
|
|
6045
|
+
const activeObservability = inspectionError === null
|
|
6046
|
+
? summarizeActivePackObservability(activationRoot, active)
|
|
6047
|
+
: {
|
|
6048
|
+
labelFlow: buildMissingLabelFlowSummary(`activation observability is unavailable: ${inspectionError}`),
|
|
6049
|
+
learningPath: buildMissingLearningPathSummary(`activation observability is unavailable: ${inspectionError}`)
|
|
6050
|
+
};
|
|
6051
|
+
const servePath = probeOperatorServePath(activationRoot, observability, active?.packId ?? null);
|
|
5069
6052
|
const reportBase = {
|
|
5070
6053
|
generatedAt: updatedAt,
|
|
5071
6054
|
activationRoot,
|
|
6055
|
+
activation,
|
|
5072
6056
|
active,
|
|
5073
|
-
candidate
|
|
5074
|
-
previous
|
|
6057
|
+
candidate,
|
|
6058
|
+
previous,
|
|
5075
6059
|
freshness: {
|
|
5076
|
-
activeBehindPromotionReadyCandidate: observability
|
|
5077
|
-
candidateAheadBy: summarizeCandidateAheadBy(observability
|
|
6060
|
+
activeBehindPromotionReadyCandidate: observability?.promotionFreshness.activeBehindPromotionReadyCandidate ?? false,
|
|
6061
|
+
candidateAheadBy: summarizeCandidateAheadBy(observability?.promotionFreshness.candidateAheadBy ?? null)
|
|
5078
6062
|
},
|
|
5079
|
-
brain: summarizeBrainState(active, observability),
|
|
5080
|
-
graph: summarizeGraphObservability(active, observability),
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
6063
|
+
brain: observability === null ? summarizeBrainStateWithoutObservability(active, activation) : summarizeBrainState(active, observability),
|
|
6064
|
+
graph: observability === null ? summarizeGraphWithoutObservability(active, activation) : summarizeGraphObservability(active, observability),
|
|
6065
|
+
labelFlow: activeObservability.labelFlow,
|
|
6066
|
+
learningPath: activeObservability.learningPath,
|
|
6067
|
+
learnedRouting: observability === null
|
|
6068
|
+
? summarizeLearnedRoutingWithoutObservability(active)
|
|
6069
|
+
: {
|
|
6070
|
+
required: observability.learnedRouteFn.required,
|
|
6071
|
+
available: observability.learnedRouteFn.available,
|
|
6072
|
+
routerIdentity: observability.learnedRouteFn.routerIdentity,
|
|
6073
|
+
routeFnVersion: observability.learnedRouteFn.routeFnVersion,
|
|
6074
|
+
trainingMethod: observability.learnedRouteFn.trainingMethod,
|
|
6075
|
+
routerTrainedAt: observability.learnedRouteFn.routerTrainedAt,
|
|
6076
|
+
objective: observability.learnedRouteFn.objective,
|
|
6077
|
+
pgProfile: observability.learnedRouteFn.pgProfile,
|
|
6078
|
+
routerChecksum: observability.learnedRouteFn.routerChecksum,
|
|
6079
|
+
objectiveChecksum: observability.learnedRouteFn.objectiveChecksum,
|
|
6080
|
+
updateMechanism: observability.learnedRouteFn.updateMechanism,
|
|
6081
|
+
updateVersion: observability.learnedRouteFn.updateVersion,
|
|
6082
|
+
updateCount: observability.learnedRouteFn.updateCount,
|
|
6083
|
+
supervisionCount: observability.learnedRouteFn.supervisionCount,
|
|
6084
|
+
collectedLabelsTotal: observability.learnedRouteFn.collectedLabels?.total ?? null,
|
|
6085
|
+
freshnessChecksum: observability.learnedRouteFn.freshnessChecksum,
|
|
6086
|
+
handoffState: observability.initHandoff.handoffState,
|
|
6087
|
+
initMode: observability.initHandoff.initMode,
|
|
6088
|
+
seedStateVisible: observability.initHandoff.seedStateVisible
|
|
6089
|
+
},
|
|
6090
|
+
servePath,
|
|
5103
6091
|
promotion: {
|
|
5104
|
-
allowed: inspection
|
|
5105
|
-
findings: [...inspection
|
|
5106
|
-
lastPromotion:
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
6092
|
+
allowed: inspection?.promotion.allowed ?? false,
|
|
6093
|
+
findings: [...(inspection?.promotion.findings ?? [])],
|
|
6094
|
+
lastPromotion: inspection === null ? {
|
|
6095
|
+
known: false,
|
|
6096
|
+
at: null,
|
|
6097
|
+
confidence: "unknown_from_local_pointers",
|
|
6098
|
+
note: activation.detail
|
|
6099
|
+
} : summarizeLastPromotion(inspection),
|
|
6100
|
+
activeUpdatedAt: inspection?.pointers.active?.updatedAt ?? null,
|
|
6101
|
+
candidateUpdatedAt: inspection?.pointers.candidate?.updatedAt ?? null,
|
|
6102
|
+
previousUpdatedAt: inspection?.pointers.previous?.updatedAt ?? null
|
|
5110
6103
|
},
|
|
5111
6104
|
rollback: {
|
|
5112
|
-
allowed: inspection
|
|
5113
|
-
findings: [...inspection
|
|
5114
|
-
previousPackId: inspection
|
|
5115
|
-
state: inspection.rollback.allowed ? "ready" : inspection.active === null ? "unknown" : "blocked"
|
|
6105
|
+
allowed: inspection?.rollback.allowed ?? false,
|
|
6106
|
+
findings: [...(inspection?.rollback.findings ?? [])],
|
|
6107
|
+
previousPackId: inspection?.previous?.packId ?? inspection?.pointers.previous?.packId ?? null,
|
|
6108
|
+
state: inspection === null ? "unknown" : inspection.rollback.allowed ? "ready" : inspection.active === null ? "unknown" : "blocked"
|
|
5116
6109
|
},
|
|
5117
6110
|
supervision: summarizeSupervision(input),
|
|
5118
6111
|
learning: summarizeAlwaysOnLearning(input, active),
|
|
@@ -5198,8 +6191,9 @@ export { describeNormalizedEventExportObservability } from "@openclawbrain/event
|
|
|
5198
6191
|
export { describeCompileFallbackUsage } from "@openclawbrain/compiler";
|
|
5199
6192
|
export { describeActivationObservability, inspectActivationState, rollbackActivePack } from "@openclawbrain/pack-format";
|
|
5200
6193
|
export { createOpenClawLocalSessionTail, OpenClawLocalSessionTail } from "./session-tail.js";
|
|
5201
|
-
export { discoverOpenClawMainSessionStores, loadOpenClawSessionIndex, readOpenClawAcpStreamFile, readOpenClawSessionFile } from "./session-store.js";
|
|
6194
|
+
export { discoverOpenClawMainSessionStores, discoverOpenClawSessionStores, loadOpenClawSessionIndex, readOpenClawAcpStreamFile, readOpenClawSessionFile } from "./session-store.js";
|
|
5202
6195
|
export { buildPassiveLearningSessionExportFromOpenClawSessionStore, buildPassiveLearningStoreExportFromOpenClawSessionIndex } from "./local-session-passive-learning.js";
|
|
6196
|
+
export { DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_TIMEOUT_MS, OllamaClient, OllamaClientError, createOllamaClient } from "./ollama-client.js";
|
|
5203
6197
|
export { resolveActivationRoot } from "./resolve-activation-root.js";
|
|
5204
6198
|
export { runDaemonCommand, parseDaemonArgs } from "./daemon.js";
|
|
5205
6199
|
//# sourceMappingURL=index.js.map
|