@openclawbrain/openclaw 0.2.1 → 0.2.3

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/dist/src/index.js CHANGED
@@ -229,6 +229,19 @@ function cloneAlwaysOnLearningMaterializationJobOrNull(value) {
229
229
  function cloneTeacherSupervisionArtifacts(value) {
230
230
  return [...structuredClone(value)];
231
231
  }
232
+ function cloneAsyncTeacherSnapshotState(value) {
233
+ if (value === undefined) {
234
+ return undefined;
235
+ }
236
+ return {
237
+ interactionEvents: [...structuredClone(value.interactionEvents)],
238
+ feedbackEvents: [...structuredClone(value.feedbackEvents)],
239
+ seenExportDigests: [...value.seenExportDigests]
240
+ };
241
+ }
242
+ function cloneAsyncTeacherSnapshotRuntime(value) {
243
+ return value === undefined ? undefined : { ...value };
244
+ }
232
245
  function cloneCanonicalSupervision(value) {
233
246
  return structuredClone(value);
234
247
  }
@@ -548,6 +561,25 @@ export class AsyncTeacherLiveLoop {
548
561
  if (!Number.isInteger(this.staleAfterMs) || this.staleAfterMs <= 0) {
549
562
  throw new Error("staleAfterMs must be a positive integer");
550
563
  }
564
+ const resumedSnapshot = input.resumeFromSnapshot;
565
+ if (resumedSnapshot !== undefined && resumedSnapshot !== null) {
566
+ if (resumedSnapshot.runtimeOwner !== "openclaw") {
567
+ throw new Error("async teacher resume snapshot runtimeOwner must be openclaw");
568
+ }
569
+ this.interactionEvents = [...structuredClone(resumedSnapshot.state?.interactionEvents ?? [])];
570
+ this.feedbackEvents = [...structuredClone(resumedSnapshot.state?.feedbackEvents ?? [])];
571
+ this.teacherArtifacts = cloneTeacherSupervisionArtifacts(resumedSnapshot.teacher.artifacts);
572
+ this.learnerState = structuredClone(resumedSnapshot.learner.state);
573
+ this.lastMaterialization = cloneAlwaysOnLearningMaterializationJobOrNull(resumedSnapshot.learner.lastMaterialization);
574
+ this.diagnostics = {
575
+ ...structuredClone(resumedSnapshot.diagnostics),
576
+ notes: [...resumedSnapshot.diagnostics.notes]
577
+ };
578
+ for (const exportDigest of resumedSnapshot.state?.seenExportDigests ?? []) {
579
+ this.seenExportDigests.add(exportDigest);
580
+ }
581
+ this.refreshNotes();
582
+ }
551
583
  }
552
584
  enqueueNormalizedEventExport(normalizedEventExport, options = {}) {
553
585
  const validationErrors = validateNormalizedEventExport(normalizedEventExport);
@@ -745,6 +777,11 @@ export class AsyncTeacherLiveLoop {
745
777
  diagnostics: {
746
778
  ...this.diagnostics,
747
779
  notes: [...this.diagnostics.notes]
780
+ },
781
+ state: {
782
+ interactionEvents: [...structuredClone(this.interactionEvents)],
783
+ feedbackEvents: [...structuredClone(this.feedbackEvents)],
784
+ seenExportDigests: [...this.seenExportDigests].sort()
748
785
  }
749
786
  };
750
787
  }
@@ -781,6 +818,7 @@ export class AsyncTeacherLiveLoop {
781
818
  const emittedArtifactCount = builtArtifacts.filter((artifact) => !currentDedupIds.has(artifact.dedupId)).length;
782
819
  const dedupedArtifactCount = builtArtifacts.length - emittedArtifactCount;
783
820
  this.teacherArtifacts = nextTeacherArtifacts;
821
+ const learnedRoutingState = this.input.resolveLearnedRoutingState?.() ?? {};
784
822
  const learnerResult = advanceAlwaysOnLearningRuntime({
785
823
  packLabel: this.input.packLabel,
786
824
  workspace: this.input.workspace,
@@ -795,10 +833,17 @@ export class AsyncTeacherLiveLoop {
795
833
  ...(this.input.sparseFeedback !== undefined ? { sparseFeedback: this.input.sparseFeedback } : {}),
796
834
  ...(this.input.liveSliceSize !== undefined ? { liveSliceSize: this.input.liveSliceSize } : {}),
797
835
  ...(this.input.backfillSliceSize !== undefined ? { backfillSliceSize: this.input.backfillSliceSize } : {}),
798
- ...(this.input.cadence !== undefined ? { cadence: this.input.cadence } : {})
836
+ ...(this.input.cadence !== undefined ? { cadence: this.input.cadence } : {}),
837
+ ...(learnedRoutingState.pgVersion !== undefined ? { pgVersion: learnedRoutingState.pgVersion } : {}),
838
+ ...(learnedRoutingState.serveTimeDecisions !== undefined ? { serveTimeDecisions: learnedRoutingState.serveTimeDecisions } : {}),
839
+ ...(learnedRoutingState.baselineState !== undefined ? { baselineState: learnedRoutingState.baselineState } : {})
799
840
  });
800
841
  this.learnerState = structuredClone(learnerResult.state);
801
842
  this.lastMaterialization = cloneAlwaysOnLearningMaterializationJobOrNull(learnerResult.materialization);
843
+ const updatedBaseline = learnerResult.materialization?.candidate.routingBuild.updatedBaseline ?? null;
844
+ if (updatedBaseline !== null) {
845
+ this.input.persistUpdatedBaseline?.(structuredClone(updatedBaseline));
846
+ }
802
847
  this.diagnostics.processedExportCount += 1;
803
848
  this.diagnostics.emittedArtifactCount += emittedArtifactCount;
804
849
  this.diagnostics.dedupedArtifactCount += dedupedArtifactCount;
@@ -927,18 +972,53 @@ export function scanLiveEventExport(input) {
927
972
  })
928
973
  }
929
974
  };
975
+ const labelFlow = summarizeNormalizedEventExportLabelFlow(normalizedEventExport, teacherArtifacts.length);
976
+ const learningPath = summarizeLearningPathFromMaterialization(learnerResult.materialization);
930
977
  return {
931
978
  runtimeOwner: "openclaw",
932
979
  scanMode: "live",
933
980
  observedAt,
934
981
  packLabel,
935
982
  supervision: buildCanonicalSupervision(normalizedEventExport),
936
- snapshot
983
+ snapshot,
984
+ labelFlow,
985
+ learningPath
937
986
  };
938
987
  }
939
988
  function readJsonFile(filePath) {
940
989
  return JSON.parse(readFileSync(filePath, "utf8"));
941
990
  }
991
+ export function resolveAsyncTeacherLiveLoopSnapshotPath(activationRoot) {
992
+ return path.join(path.resolve(normalizeNonEmptyString(activationRoot, "activationRoot")), "async-teacher-live-loop.snapshot.json");
993
+ }
994
+ export function loadAsyncTeacherLiveLoopSnapshot(snapshotPath) {
995
+ const snapshot = readJsonFile(path.resolve(snapshotPath));
996
+ if (snapshot.runtimeOwner !== "openclaw") {
997
+ throw new Error("async teacher snapshot runtimeOwner must be openclaw");
998
+ }
999
+ const cloned = {
1000
+ ...snapshot,
1001
+ diagnostics: {
1002
+ ...snapshot.diagnostics,
1003
+ notes: [...snapshot.diagnostics.notes]
1004
+ },
1005
+ teacher: {
1006
+ ...snapshot.teacher,
1007
+ artifacts: cloneTeacherSupervisionArtifacts(snapshot.teacher.artifacts)
1008
+ },
1009
+ learner: {
1010
+ state: structuredClone(snapshot.learner.state),
1011
+ lastMaterialization: cloneAlwaysOnLearningMaterializationJobOrNull(snapshot.learner.lastMaterialization)
1012
+ }
1013
+ };
1014
+ if (snapshot.state !== undefined) {
1015
+ cloned.state = cloneAsyncTeacherSnapshotState(snapshot.state);
1016
+ }
1017
+ if (snapshot.runtime !== undefined) {
1018
+ cloned.runtime = cloneAsyncTeacherSnapshotRuntime(snapshot.runtime);
1019
+ }
1020
+ return cloned;
1021
+ }
942
1022
  function resolveBundlePayloadPath(rootDir, payloadPath) {
943
1023
  const resolved = path.resolve(rootDir, payloadPath);
944
1024
  const relative = path.relative(rootDir, resolved);
@@ -1770,6 +1850,15 @@ function normalizeIsoTimestamp(value, fieldName, fallbackValue) {
1770
1850
  function normalizeMode(value) {
1771
1851
  return value ?? "heuristic";
1772
1852
  }
1853
+ function normalizeCompileSelectionMode(value) {
1854
+ if (value === undefined) {
1855
+ return undefined;
1856
+ }
1857
+ if (value === "flat_rank_v1" || value === "graph_walk_v1") {
1858
+ return value;
1859
+ }
1860
+ throw new Error(`selectionMode must be flat_rank_v1 or graph_walk_v1, received ${String(value)}`);
1861
+ }
1773
1862
  function normalizeRuntimeHints(value) {
1774
1863
  if (value === undefined) {
1775
1864
  return [];
@@ -1955,6 +2044,9 @@ export function formatPromptContext(compileResponse) {
1955
2044
  lines.push("[/BRAIN_CONTEXT]");
1956
2045
  return `${lines.join("\n")}\n`;
1957
2046
  }
2047
+ function resolveActivationRootForFailure(value) {
2048
+ return path.resolve(normalizeOptionalString(value) ?? ".");
2049
+ }
1958
2050
  function failOpenCompileResult(error, activationRoot) {
1959
2051
  return {
1960
2052
  ok: false,
@@ -1990,6 +2082,70 @@ function classifyCompileFailure(error, activationRoot) {
1990
2082
  function uniqueNotes(notes) {
1991
2083
  return [...new Set(notes.filter((note) => note.length > 0))];
1992
2084
  }
2085
+ function buildServeRouteLogFailOpenWarning(scope, error) {
2086
+ return `learning spine serve route log failed open (${scope}): ${toErrorMessage(error)}`;
2087
+ }
2088
+ function buildServeRouteLogFailOpenNotes(scope, error) {
2089
+ return [
2090
+ "serve_route_log_status=fail_open",
2091
+ `serve_route_log_scope=${scope}`,
2092
+ `serve_route_log_error=${toErrorMessage(error)}`
2093
+ ];
2094
+ }
2095
+ function normalizeServeRouteChannel(value) {
2096
+ if (typeof value !== "string") {
2097
+ return undefined;
2098
+ }
2099
+ const trimmed = value.trim();
2100
+ return trimmed.length > 0 ? trimmed : undefined;
2101
+ }
2102
+ function normalizeServeRouteMessage(value) {
2103
+ return typeof value === "string" ? value.trim() : "";
2104
+ }
2105
+ function appendCompileServeRouteDecisionLog(input) {
2106
+ if (input.compileInput._suppressServeLog) {
2107
+ return;
2108
+ }
2109
+ const recordedAt = new Date().toISOString();
2110
+ const sessionId = normalizeServeRouteChannel(input.compileInput.sessionId) ?? `ext-compile-${Date.now()}`;
2111
+ const channel = normalizeServeRouteChannel(input.compileInput.channel) ?? "extension";
2112
+ const syntheticTurn = {
2113
+ sessionId,
2114
+ channel,
2115
+ userMessage: input.userMessage,
2116
+ createdAt: recordedAt
2117
+ };
2118
+ if (input.compileInput.maxContextBlocks !== undefined) {
2119
+ syntheticTurn.maxContextBlocks = input.compileInput.maxContextBlocks;
2120
+ }
2121
+ if (input.compileInput.budgetStrategy === "fixed_v1" || input.compileInput.budgetStrategy === "empirical_v1") {
2122
+ syntheticTurn.budgetStrategy = input.compileInput.budgetStrategy;
2123
+ }
2124
+ if (input.compileInput.mode === "heuristic" || input.compileInput.mode === "learned") {
2125
+ syntheticTurn.mode = input.compileInput.mode;
2126
+ }
2127
+ if (input.compileInput.runtimeHints !== undefined) {
2128
+ syntheticTurn.runtimeHints = input.compileInput.runtimeHints;
2129
+ }
2130
+ try {
2131
+ appendServeTimeRouteDecisionLog({
2132
+ activationRoot: input.activationRoot,
2133
+ turn: syntheticTurn,
2134
+ compileResult: input.compileResult,
2135
+ recordedAt
2136
+ });
2137
+ }
2138
+ catch (error) {
2139
+ if (input.compileResult.ok) {
2140
+ input.compileResult.compileResponse.diagnostics.notes = uniqueNotes([
2141
+ ...input.compileResult.compileResponse.diagnostics.notes,
2142
+ ...buildServeRouteLogFailOpenNotes("compileRuntimeContext", error)
2143
+ ]);
2144
+ }
2145
+ console.warn(`[openclawbrain] ${buildServeRouteLogFailOpenWarning("compileRuntimeContext", error)} ` +
2146
+ `(activationRoot=${input.activationRoot}, sessionId=${sessionId}, channel=${channel})`);
2147
+ }
2148
+ }
1993
2149
  function roundMetric(value) {
1994
2150
  return Math.round(value * 100) / 100;
1995
2151
  }
@@ -2220,24 +2376,52 @@ export function resolveActivePackForCompile(activationRoot) {
2220
2376
  };
2221
2377
  }
2222
2378
  export function compileRuntimeContext(input) {
2223
- const activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
2224
- const agentId = normalizeOptionalString(input.agentId) ?? process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
2225
- const runtimeHints = normalizeRuntimeHints(input.runtimeHints);
2379
+ const fallbackActivationRoot = resolveActivationRootForFailure(input.activationRoot);
2380
+ let activationRoot = fallbackActivationRoot;
2381
+ let agentId = process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
2382
+ let runtimeHints = [];
2383
+ let selectionMode;
2384
+ let userMessage = "";
2385
+ let maxContextChars;
2386
+ let mode = "heuristic";
2387
+ let result;
2388
+ try {
2389
+ activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
2390
+ agentId = normalizeOptionalString(input.agentId) ?? process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
2391
+ runtimeHints = normalizeRuntimeHints(input.runtimeHints);
2392
+ selectionMode = normalizeCompileSelectionMode(input.selectionMode);
2393
+ userMessage = normalizeNonEmptyString(input.message, "message");
2394
+ maxContextChars =
2395
+ input.maxContextChars !== undefined
2396
+ ? normalizeNonNegativeInteger(input.maxContextChars, "maxContextChars", input.maxContextChars)
2397
+ : undefined;
2398
+ mode = normalizeMode(input.mode);
2399
+ }
2400
+ catch (error) {
2401
+ result = failOpenCompileResult(error, fallbackActivationRoot);
2402
+ appendCompileServeRouteDecisionLog({
2403
+ compileInput: input,
2404
+ activationRoot: result.activationRoot,
2405
+ compileResult: result,
2406
+ userMessage: normalizeServeRouteMessage(input.message)
2407
+ });
2408
+ return result;
2409
+ }
2226
2410
  try {
2227
2411
  const target = resolveActivePackForCompile(activationRoot);
2228
2412
  const resolvedBudget = resolveCompileBudget(target, input);
2229
2413
  const compile = compileRuntimeFromActivation(activationRoot, {
2230
2414
  contract: CONTRACT_IDS.runtimeCompile,
2231
2415
  agentId,
2232
- userMessage: normalizeNonEmptyString(input.message, "message"),
2416
+ userMessage,
2233
2417
  maxContextBlocks: resolvedBudget.maxContextBlocks,
2234
- ...(input.maxContextChars !== undefined
2235
- ? { maxContextChars: normalizeNonNegativeInteger(input.maxContextChars, "maxContextChars", input.maxContextChars) }
2236
- : {}),
2237
- modeRequested: normalizeMode(input.mode),
2418
+ ...(maxContextChars !== undefined ? { maxContextChars } : {}),
2419
+ modeRequested: mode,
2238
2420
  activePackId: target.activePointer.packId,
2239
2421
  ...(input.compactionMode !== undefined ? { compactionMode: input.compactionMode } : {}),
2240
2422
  ...(runtimeHints.length > 0 ? { runtimeHints } : {})
2423
+ }, {
2424
+ ...(selectionMode !== undefined ? { selectionMode } : {})
2241
2425
  });
2242
2426
  const compileResponse = {
2243
2427
  ...compile.response,
@@ -2246,7 +2430,7 @@ export function compileRuntimeContext(input) {
2246
2430
  notes: uniqueNotes([...compile.response.diagnostics.notes, ...resolvedBudget.notes, "OpenClaw remains the runtime owner"])
2247
2431
  }
2248
2432
  };
2249
- return {
2433
+ result = {
2250
2434
  ok: true,
2251
2435
  fallbackToStaticContext: false,
2252
2436
  hardRequirementViolated: false,
@@ -2258,8 +2442,15 @@ export function compileRuntimeContext(input) {
2258
2442
  };
2259
2443
  }
2260
2444
  catch (error) {
2261
- return classifyCompileFailure(error, activationRoot);
2445
+ result = classifyCompileFailure(error, activationRoot);
2262
2446
  }
2447
+ appendCompileServeRouteDecisionLog({
2448
+ compileInput: input,
2449
+ activationRoot: result.activationRoot,
2450
+ compileResult: result,
2451
+ userMessage
2452
+ });
2453
+ return result;
2263
2454
  }
2264
2455
  function readDiagnosticNoteValue(notes, prefix) {
2265
2456
  const note = notes.find((entry) => entry.startsWith(prefix));
@@ -3082,29 +3273,33 @@ export function writeScannedEventExportBundle(input) {
3082
3273
  });
3083
3274
  }
3084
3275
  export function runRuntimeTurn(turn, options = {}) {
3276
+ const warnings = [];
3085
3277
  const agentId = normalizeOptionalString(turn.agentId);
3086
3278
  const compileInput = {
3087
- activationRoot: options.activationRoot ?? normalizeNonEmptyString(turn.activationRoot ?? undefined, "activationRoot"),
3088
- message: normalizeNonEmptyString(turn.userMessage, "userMessage"),
3279
+ activationRoot: (options.activationRoot ?? turn.activationRoot),
3280
+ message: turn.userMessage,
3089
3281
  ...(agentId !== undefined ? { agentId } : {}),
3090
3282
  ...(turn.maxContextBlocks !== undefined ? { maxContextBlocks: turn.maxContextBlocks } : {}),
3091
3283
  ...(turn.budgetStrategy !== undefined ? { budgetStrategy: turn.budgetStrategy } : {}),
3092
3284
  ...(turn.mode !== undefined ? { mode: turn.mode } : {}),
3093
- ...(turn.runtimeHints !== undefined ? { runtimeHints: turn.runtimeHints } : {})
3285
+ ...(turn.selectionMode !== undefined ? { selectionMode: turn.selectionMode } : {}),
3286
+ ...(turn.runtimeHints !== undefined ? { runtimeHints: turn.runtimeHints } : {}),
3287
+ _suppressServeLog: true
3094
3288
  };
3095
3289
  const compileResult = compileRuntimeContext(compileInput);
3096
- const warnings = [];
3097
3290
  const serveLoggedAt = turn.compile?.createdAt ?? turn.createdAt ?? new Date().toISOString();
3098
3291
  if (!compileResult.ok && compileResult.hardRequirementViolated) {
3099
3292
  try {
3100
3293
  appendServeTimeRouteDecisionLog({
3101
- activationRoot: compileInput.activationRoot,
3294
+ activationRoot: compileResult.activationRoot,
3102
3295
  turn,
3103
3296
  compileResult,
3104
3297
  recordedAt: serveLoggedAt
3105
3298
  });
3106
3299
  }
3107
- catch {
3300
+ catch (error) {
3301
+ console.warn(`[openclawbrain] serve-time route decision log failed before hard-fail throw: ${toErrorMessage(error)} ` +
3302
+ `(activationRoot=${compileResult.activationRoot}, sessionId=${turn.sessionId}, channel=${turn.channel})`);
3108
3303
  }
3109
3304
  throw new Error(compileResult.error);
3110
3305
  }
@@ -3113,7 +3308,7 @@ export function runRuntimeTurn(turn, options = {}) {
3113
3308
  try {
3114
3309
  const compileEvent = normalizedEventExport.interactionEvents.find((event) => event.kind === "memory_compiled");
3115
3310
  appendServeTimeRouteDecisionLog({
3116
- activationRoot: compileInput.activationRoot,
3311
+ activationRoot: compileResult.activationRoot,
3117
3312
  turn,
3118
3313
  compileResult,
3119
3314
  normalizedEventExport,
@@ -3121,19 +3316,39 @@ export function runRuntimeTurn(turn, options = {}) {
3121
3316
  });
3122
3317
  }
3123
3318
  catch (error) {
3124
- warnings.push(`learning spine serve log failed: ${toErrorMessage(error)}`);
3319
+ warnings.push(buildServeRouteLogFailOpenWarning("runRuntimeTurn", error));
3320
+ if (compileResult.ok) {
3321
+ compileResult.compileResponse.diagnostics.notes = uniqueNotes([
3322
+ ...compileResult.compileResponse.diagnostics.notes,
3323
+ ...buildServeRouteLogFailOpenNotes("runRuntimeTurn", error)
3324
+ ]);
3325
+ }
3326
+ }
3327
+ try {
3328
+ const eventExport = writeRuntimeEventExportBundle(turn, normalizedEventExport);
3329
+ return {
3330
+ ...compileResult,
3331
+ eventExport,
3332
+ warnings
3333
+ };
3334
+ }
3335
+ catch (error) {
3336
+ if (options.failOpen === false) {
3337
+ throw error;
3338
+ }
3339
+ warnings.push(toErrorMessage(error));
3340
+ return {
3341
+ ...compileResult,
3342
+ eventExport: {
3343
+ ok: false,
3344
+ wroteBundle: false,
3345
+ error: toErrorMessage(error)
3346
+ },
3347
+ warnings
3348
+ };
3125
3349
  }
3126
- const eventExport = writeRuntimeEventExportBundle(turn, normalizedEventExport);
3127
- return {
3128
- ...compileResult,
3129
- eventExport,
3130
- warnings
3131
- };
3132
3350
  }
3133
3351
  catch (error) {
3134
- if (options.failOpen === false) {
3135
- throw error;
3136
- }
3137
3352
  warnings.push(toErrorMessage(error));
3138
3353
  return {
3139
3354
  ...compileResult,
@@ -4117,6 +4332,144 @@ function summarizeOperatorSlot(slot, updatedAt) {
4117
4332
  findings: [...slot.findings]
4118
4333
  };
4119
4334
  }
4335
+ function buildMissingLabelFlowSummary(detail) {
4336
+ return {
4337
+ source: "missing",
4338
+ humanLabelCount: null,
4339
+ selfLabelCount: null,
4340
+ asyncTeacherArtifactCount: null,
4341
+ implicitPositiveCount: null,
4342
+ detail
4343
+ };
4344
+ }
4345
+ function buildMissingLearningPathSummary(detail) {
4346
+ return {
4347
+ available: false,
4348
+ source: "missing",
4349
+ policyGradientVersion: "unavailable",
4350
+ policyGradientMethod: null,
4351
+ objective: null,
4352
+ targetConstruction: null,
4353
+ connectOpsFired: null,
4354
+ reconstructedTrajectoryCount: null,
4355
+ detail
4356
+ };
4357
+ }
4358
+ function countTeacherArtifactBlocks(blocks) {
4359
+ return blocks.filter((block) => block.learning.role === "teacher_supervision" && !block.id.endsWith(":teacher-supervision-summary")).length;
4360
+ }
4361
+ function summarizePolicyGradientVersion(targetConstruction) {
4362
+ if (targetConstruction === "trajectory_reconstruction") {
4363
+ return "v2";
4364
+ }
4365
+ if (targetConstruction === "event_block_plus_related_interaction") {
4366
+ return "v1";
4367
+ }
4368
+ return "unavailable";
4369
+ }
4370
+ function summarizePackLabelFlow(source, pack) {
4371
+ const labelHarvest = pack.manifest.provenance.learningSurface.labelHarvest;
4372
+ return {
4373
+ source,
4374
+ humanLabelCount: labelHarvest.humanLabels,
4375
+ selfLabelCount: labelHarvest.selfLabels,
4376
+ asyncTeacherArtifactCount: countTeacherArtifactBlocks(pack.graph.blocks),
4377
+ implicitPositiveCount: labelHarvest.approvals,
4378
+ detail: source === "active_pack"
4379
+ ? "active pack label harvest and teacher artifacts are visible"
4380
+ : source === "materialized_candidate"
4381
+ ? "materialized candidate label harvest and teacher artifacts are visible"
4382
+ : "event export label harvest is visible"
4383
+ };
4384
+ }
4385
+ function summarizePackLearningPath(source, pack) {
4386
+ const targetConstruction = pack.router?.training.objective.profile.targetConstruction ?? null;
4387
+ const policyGradientVersion = summarizePolicyGradientVersion(targetConstruction);
4388
+ const reconstructedTrajectoryCount = policyGradientVersion === "v2"
4389
+ ? pack.router?.training.routeTraceCount ?? 0
4390
+ : pack.router === null
4391
+ ? null
4392
+ : 0;
4393
+ return {
4394
+ available: pack.router !== null,
4395
+ source,
4396
+ policyGradientVersion,
4397
+ policyGradientMethod: pack.router?.training.method ?? null,
4398
+ objective: pack.router?.training.objective.objective ?? null,
4399
+ targetConstruction,
4400
+ connectOpsFired: pack.manifest.graphDynamics.structuralOps.connect,
4401
+ reconstructedTrajectoryCount,
4402
+ detail: pack.router === null
4403
+ ? "pack has no learned router artifact"
4404
+ : policyGradientVersion === "v2"
4405
+ ? "learned routing uses trajectory-reconstruction PG"
4406
+ : policyGradientVersion === "v1"
4407
+ ? "learned routing uses event-reconstruction PG"
4408
+ : "learned routing is present but the PG profile is not recognizable"
4409
+ };
4410
+ }
4411
+ function summarizePackObservability(source, pack) {
4412
+ return {
4413
+ labelFlow: summarizePackLabelFlow(source, pack),
4414
+ learningPath: summarizePackLearningPath(source, pack)
4415
+ };
4416
+ }
4417
+ export function summarizeNormalizedEventExportLabelFlow(normalizedEventExport, asyncTeacherArtifactCount = 0) {
4418
+ const labelHarvest = normalizedEventExport.provenance.learningSurface.labelHarvest;
4419
+ return {
4420
+ source: "event_export",
4421
+ humanLabelCount: labelHarvest.humanLabels,
4422
+ selfLabelCount: labelHarvest.selfLabels,
4423
+ asyncTeacherArtifactCount,
4424
+ implicitPositiveCount: labelHarvest.approvals,
4425
+ detail: "event export label harvest is visible"
4426
+ };
4427
+ }
4428
+ export function summarizeLearningPathFromMaterialization(materialization) {
4429
+ if (materialization === null) {
4430
+ return buildMissingLearningPathSummary("no candidate pack materialized during this learning pass");
4431
+ }
4432
+ return summarizePackLearningPath("materialized_candidate", {
4433
+ manifest: materialization.candidate.manifest,
4434
+ graph: materialization.candidate.payloads.graph,
4435
+ router: materialization.candidate.payloads.router
4436
+ });
4437
+ }
4438
+ function summarizeActivePackObservability(activationRoot, active) {
4439
+ if (active === null) {
4440
+ return {
4441
+ labelFlow: buildMissingLabelFlowSummary("no active pack is attached"),
4442
+ learningPath: buildMissingLearningPathSummary("no active pack is attached")
4443
+ };
4444
+ }
4445
+ if (!active.activationReady) {
4446
+ return {
4447
+ labelFlow: buildMissingLabelFlowSummary(`active pack ${active.packId} is not activation-ready`),
4448
+ learningPath: buildMissingLearningPathSummary(`active pack ${active.packId} is not activation-ready`)
4449
+ };
4450
+ }
4451
+ try {
4452
+ const pack = loadPackFromActivation(activationRoot, "active", { requireActivationReady: true });
4453
+ if (pack === null) {
4454
+ return {
4455
+ labelFlow: buildMissingLabelFlowSummary("active pack payloads are unavailable"),
4456
+ learningPath: buildMissingLearningPathSummary("active pack payloads are unavailable")
4457
+ };
4458
+ }
4459
+ return summarizePackObservability("active_pack", {
4460
+ manifest: pack.manifest,
4461
+ graph: pack.graph,
4462
+ router: pack.router
4463
+ });
4464
+ }
4465
+ catch (error) {
4466
+ const detail = `active pack observability could not be loaded: ${toErrorMessage(error)}`;
4467
+ return {
4468
+ labelFlow: buildMissingLabelFlowSummary(detail),
4469
+ learningPath: buildMissingLearningPathSummary(detail)
4470
+ };
4471
+ }
4472
+ }
4120
4473
  function summarizeLastPromotion(inspection) {
4121
4474
  if (inspection.active === null) {
4122
4475
  return {
@@ -4532,11 +4885,7 @@ function loadTeacherSnapshot(input) {
4532
4885
  if (teacherSnapshotPath === undefined) {
4533
4886
  return null;
4534
4887
  }
4535
- const snapshot = readJsonFile(path.resolve(teacherSnapshotPath));
4536
- if (snapshot.runtimeOwner !== "openclaw") {
4537
- throw new Error("teacher snapshot runtimeOwner must be openclaw");
4538
- }
4539
- return snapshot;
4888
+ return loadAsyncTeacherLiveLoopSnapshot(teacherSnapshotPath);
4540
4889
  }
4541
4890
  function summarizeTeacherLoop(input) {
4542
4891
  const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
@@ -4546,10 +4895,14 @@ function summarizeTeacherLoop(input) {
4546
4895
  sourcePath: null,
4547
4896
  lastNoOpReason: "unavailable",
4548
4897
  latestFreshness: "unavailable",
4898
+ startedAt: null,
4899
+ lastHeartbeatAt: null,
4900
+ lastScanAt: null,
4549
4901
  lastProcessedAt: null,
4550
4902
  queueDepth: null,
4551
4903
  queueCapacity: null,
4552
4904
  running: null,
4905
+ lastAppliedMaterializationJobId: null,
4553
4906
  lastMaterializedPackId: null,
4554
4907
  notes: [],
4555
4908
  detail: "no teacher snapshot path supplied"
@@ -4562,10 +4915,14 @@ function summarizeTeacherLoop(input) {
4562
4915
  sourcePath: path.resolve(teacherSnapshotPath),
4563
4916
  lastNoOpReason: "unavailable",
4564
4917
  latestFreshness: "unavailable",
4918
+ startedAt: null,
4919
+ lastHeartbeatAt: null,
4920
+ lastScanAt: null,
4565
4921
  lastProcessedAt: null,
4566
4922
  queueDepth: null,
4567
4923
  queueCapacity: null,
4568
4924
  running: null,
4925
+ lastAppliedMaterializationJobId: null,
4569
4926
  lastMaterializedPackId: null,
4570
4927
  notes: [],
4571
4928
  detail: "teacher snapshot could not be loaded"
@@ -4576,10 +4933,14 @@ function summarizeTeacherLoop(input) {
4576
4933
  sourcePath: path.resolve(teacherSnapshotPath),
4577
4934
  lastNoOpReason: snapshot.diagnostics.lastNoOpReason,
4578
4935
  latestFreshness: snapshot.diagnostics.latestFreshness,
4936
+ startedAt: snapshot.runtime?.startedAt ?? null,
4937
+ lastHeartbeatAt: snapshot.runtime?.lastHeartbeatAt ?? null,
4938
+ lastScanAt: snapshot.runtime?.lastScanAt ?? null,
4579
4939
  lastProcessedAt: snapshot.diagnostics.lastProcessedAt,
4580
4940
  queueDepth: snapshot.queue.depth,
4581
4941
  queueCapacity: snapshot.queue.capacity,
4582
4942
  running: snapshot.queue.running,
4943
+ lastAppliedMaterializationJobId: snapshot.runtime?.lastAppliedMaterializationJobId ?? null,
4583
4944
  lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null,
4584
4945
  notes: [...snapshot.diagnostics.notes],
4585
4946
  detail: "async teacher diagnostics loaded"
@@ -5066,6 +5427,7 @@ export function buildOperatorSurfaceReport(input) {
5066
5427
  });
5067
5428
  const attachStatus = describeAttachStatus({ activationRoot });
5068
5429
  const active = summarizeOperatorSlot(inspection.active, inspection.pointers.active?.updatedAt ?? null);
5430
+ const activeObservability = summarizeActivePackObservability(activationRoot, active);
5069
5431
  const reportBase = {
5070
5432
  generatedAt: updatedAt,
5071
5433
  activationRoot,
@@ -5078,6 +5440,8 @@ export function buildOperatorSurfaceReport(input) {
5078
5440
  },
5079
5441
  brain: summarizeBrainState(active, observability),
5080
5442
  graph: summarizeGraphObservability(active, observability),
5443
+ labelFlow: activeObservability.labelFlow,
5444
+ learningPath: activeObservability.learningPath,
5081
5445
  learnedRouting: {
5082
5446
  required: observability.learnedRouteFn.required,
5083
5447
  available: observability.learnedRouteFn.available,
@@ -5198,7 +5562,7 @@ export { describeNormalizedEventExportObservability } from "@openclawbrain/event
5198
5562
  export { describeCompileFallbackUsage } from "@openclawbrain/compiler";
5199
5563
  export { describeActivationObservability, inspectActivationState, rollbackActivePack } from "@openclawbrain/pack-format";
5200
5564
  export { createOpenClawLocalSessionTail, OpenClawLocalSessionTail } from "./session-tail.js";
5201
- export { discoverOpenClawMainSessionStores, loadOpenClawSessionIndex, readOpenClawAcpStreamFile, readOpenClawSessionFile } from "./session-store.js";
5565
+ export { discoverOpenClawMainSessionStores, discoverOpenClawSessionStores, loadOpenClawSessionIndex, readOpenClawAcpStreamFile, readOpenClawSessionFile } from "./session-store.js";
5202
5566
  export { buildPassiveLearningSessionExportFromOpenClawSessionStore, buildPassiveLearningStoreExportFromOpenClawSessionIndex } from "./local-session-passive-learning.js";
5203
5567
  export { resolveActivationRoot } from "./resolve-activation-root.js";
5204
5568
  export { runDaemonCommand, parseDaemonArgs } from "./daemon.js";