@openclawbrain/cli 0.4.26 → 0.4.28
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/cli.js +194 -9
- package/dist/src/daemon.d.ts +2 -0
- package/dist/src/daemon.js +19 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +1 -1
- package/dist/src/learning-spine.d.ts +2 -1
- package/dist/src/local-learner.d.ts +17 -1
- package/dist/src/local-learner.js +109 -13
- package/dist/src/openclaw-hook-truth.d.ts +22 -0
- package/dist/src/openclaw-hook-truth.js +117 -0
- package/dist/src/proof-command.js +43 -4
- package/dist/src/status-learning-path.js +130 -0
- package/dist/src/teacher-labeler.d.ts +1 -1
- package/dist/src/teacher-labeler.js +4 -1
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { buildTeacherSupervisionArtifactsFromNormalizedEventExport, createAlways
|
|
|
13
13
|
import { inspectActivationState, loadPackFromActivation, promoteCandidatePack, resolveLearningSpineLogPath, stageCandidatePack } from "@openclawbrain/pack-format";
|
|
14
14
|
import { resolveActivationRoot } from "./resolve-activation-root.js";
|
|
15
15
|
import { describeOpenClawHomeInspection, discoverOpenClawHomes, formatOpenClawHomeLayout, formatOpenClawHomeProfileSource, inspectOpenClawHome } from "./openclaw-home-layout.js";
|
|
16
|
-
import { inspectOpenClawBrainHookStatus, inspectOpenClawBrainPluginAllowlist } from "./openclaw-hook-truth.js";
|
|
16
|
+
import { describeOpenClawBrainHotfixBoundary, inspectOpenClawBrainHookStatus, inspectOpenClawBrainPluginAllowlist } from "./openclaw-hook-truth.js";
|
|
17
17
|
import { describeOpenClawBrainInstallIdentity, describeOpenClawBrainInstallLayout, findInstalledOpenClawBrainPlugin, getOpenClawBrainKnownPluginIds, normalizeOpenClawBrainPluginsConfig, pinInstalledOpenClawBrainPluginActivationRoot, resolveOpenClawBrainInstallTarget } from "./openclaw-plugin-install.js";
|
|
18
18
|
import { buildOpenClawBrainConvergeRestartPlan, classifyOpenClawBrainConvergeVerification, describeOpenClawBrainConvergeChangeReasons, diffOpenClawBrainConvergeRuntimeFingerprint, finalizeOpenClawBrainConvergeResult, planOpenClawBrainConvergePluginAction, shouldReplaceOpenClawBrainInstallBeforeConverge } from "./install-converge.js";
|
|
19
19
|
import { loadAttachmentPolicyDeclaration, resolveEffectiveAttachmentPolicyTruth, writeAttachmentPolicyDeclaration } from "./attachment-policy-truth.js";
|
|
@@ -25,7 +25,7 @@ import { summarizePackVectorEmbeddingState } from "./embedding-status.js";
|
|
|
25
25
|
import { buildTracedLearningBridgePayloadFromRuntime, buildTracedLearningStatusSurface, persistTracedLearningBridgeState } from "./traced-learning-bridge.js";
|
|
26
26
|
import { discoverOpenClawSessionStores, loadOpenClawSessionIndex, readOpenClawSessionFile } from "./session-store.js";
|
|
27
27
|
import { readOpenClawBrainProviderDefaults, readOpenClawBrainProviderConfig, readOpenClawBrainProviderConfigFromSources, resolveOpenClawBrainProviderDefaultsPath } from "./provider-config.js";
|
|
28
|
-
import { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary, formatOperatorLearningPathSummary } from "./status-learning-path.js";
|
|
28
|
+
import { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary, formatOperatorLearningFlowSummary, formatOperatorLearningHealthSummary, formatOperatorLearningPathSummary } from "./status-learning-path.js";
|
|
29
29
|
import { buildProofCommandForOpenClawHome, buildProofCommandHelpSection, captureOperatorProofBundle, formatOperatorProofResult, parseProofCliArgs } from "./proof-command.js";
|
|
30
30
|
const OPENCLAWBRAIN_EMBEDDER_BASE_URL_ENV = "OPENCLAWBRAIN_EMBEDDER_BASE_URL";
|
|
31
31
|
const OPENCLAWBRAIN_EMBEDDER_PROVIDER_ENV = "OPENCLAWBRAIN_EMBEDDER_PROVIDER";
|
|
@@ -950,6 +950,27 @@ function summarizeStatusAttachmentTruth(input) {
|
|
|
950
950
|
})
|
|
951
951
|
};
|
|
952
952
|
}
|
|
953
|
+
function summarizeStatusHotfixBoundary(status) {
|
|
954
|
+
return describeOpenClawBrainHotfixBoundary({
|
|
955
|
+
hookInspection: status.hook,
|
|
956
|
+
daemonInspection: inspectManagedLearnerService(status.host.activationRoot)
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
function formatStatusHotfixBoundarySummary(boundary) {
|
|
960
|
+
return [
|
|
961
|
+
`boundary=${boundary.boundary}`,
|
|
962
|
+
`skew=${boundary.skew}`,
|
|
963
|
+
`daemon=${boundary.daemonPackage ?? "unverified"}`,
|
|
964
|
+
`hook=${boundary.hookPackage ?? "unverified"}`
|
|
965
|
+
].join(" ");
|
|
966
|
+
}
|
|
967
|
+
function formatStatusHotfixBoundaryPaths(boundary) {
|
|
968
|
+
return [
|
|
969
|
+
`daemonPath=${boundary.daemonPath === null ? "none" : shortenPath(boundary.daemonPath)}`,
|
|
970
|
+
`hookPath=${boundary.hookPath === null ? "unverified" : shortenPath(boundary.hookPath)}`,
|
|
971
|
+
`runtimeGuard=${boundary.runtimeGuardPath === null ? "unverified" : shortenPath(boundary.runtimeGuardPath)}`
|
|
972
|
+
].join(" ");
|
|
973
|
+
}
|
|
953
974
|
function normalizeAttachmentPolicyMode(value) {
|
|
954
975
|
return value === "undeclared" || value === "dedicated" || value === "shared"
|
|
955
976
|
? value
|
|
@@ -1417,6 +1438,7 @@ function formatTracedLearningSurface(surface) {
|
|
|
1417
1438
|
function buildCompactStatusHeader(status, report, options) {
|
|
1418
1439
|
const installHook = summarizeStatusInstallHook(options.openclawHome);
|
|
1419
1440
|
const hookLoad = summarizeStatusHookLoad(installHook, status);
|
|
1441
|
+
const hotfixBoundary = summarizeStatusHotfixBoundary(status);
|
|
1420
1442
|
const embeddings = summarizeStatusEmbeddings(report, options.providerConfig);
|
|
1421
1443
|
const localLlm = summarizeStatusLocalLlm(options.providerConfig);
|
|
1422
1444
|
const teacher = summarizeStatusTeacher(report, options.providerConfig, localLlm);
|
|
@@ -1433,6 +1455,9 @@ function buildCompactStatusHeader(status, report, options) {
|
|
|
1433
1455
|
return [
|
|
1434
1456
|
`lifecycle attach=${status.attachment.state} learner=${yesNo(status.passiveLearning.learnerRunning)} watch=${summarizeStatusWatchState(status)} export=${status.passiveLearning.exportState} promote=${summarizeStatusPromotionState(status)} serve=${summarizeStatusServeReality(status)}`,
|
|
1435
1457
|
`hook install=${hookLoad.installState} loadability=${hookLoad.loadability} loadProof=${hookLoad.loadProof} layout=${status.hook.installLayout ?? "unverified"} additional=${status.hook.additionalInstallCount ?? 0} severity=${hookLoad.guardSeverity} actionability=${hookLoad.guardActionability} summary=${hookLoad.guardSummary}`,
|
|
1458
|
+
`surface ${formatStatusHotfixBoundarySummary(hotfixBoundary)}`,
|
|
1459
|
+
`surfaces ${formatStatusHotfixBoundaryPaths(hotfixBoundary)}`,
|
|
1460
|
+
`hotfix ${hotfixBoundary.guidance}`,
|
|
1436
1461
|
`attachTruth current=${attachmentTruth.currentProfileLabel} hook=${attachmentTruth.hookFiles} config=${attachmentTruth.configLoad} runtime=${attachmentTruth.runtimeLoad} watcher=${attachmentTruth.watcher} attachedSet=${formatAttachedProfileTruthCompactList(attachmentTruth.attachedProfiles)} why=${attachmentTruth.detail}`,
|
|
1437
1462
|
`passive firstExport=${yesNo(status.passiveLearning.firstExportOccurred)} backlog=${status.passiveLearning.backlogState} pending=${formatStatusNullableNumber(status.passiveLearning.pendingLive)}/${formatStatusNullableNumber(status.passiveLearning.pendingBackfill)}`,
|
|
1438
1463
|
`serving pack=${status.passiveLearning.currentServingPackId ?? "none"} lastExport=${status.passiveLearning.lastExportAt ?? "none"} lastPromotion=${status.passiveLearning.lastPromotionAt ?? "none"}`,
|
|
@@ -1442,6 +1467,8 @@ function buildCompactStatusHeader(status, report, options) {
|
|
|
1442
1467
|
`explain ${status.brain.summary}`,
|
|
1443
1468
|
`graph blocks=${report.graph.blockCount ?? "none"} strongest=${report.graph.strongestBlockId ?? "none"} latest=${report.graph.latestMaterialization.packId ?? "none"} latestChanged=${yesNo(report.graph.latestMaterialization.changed)} connect=${formatCompactGraphConnectDiagnostics(report.graph.latestMaterialization.connectDiagnostics ?? report.graph.connectDiagnostics)}`,
|
|
1444
1469
|
`attribution ${formatOperatorLearningAttributionSummary({ status })}`,
|
|
1470
|
+
`learnFlow ${formatOperatorLearningFlowSummary({ tracedLearning })}`,
|
|
1471
|
+
`health ${formatOperatorLearningHealthSummary({ tracedLearning, teacher })}`,
|
|
1445
1472
|
`teacher model=${teacher.model} enabled=${yesNo(teacher.enabled)} healthy=${yesNo(teacher.healthy)} stale=${yesNo(teacher.stale)} idle=${yesNo(teacher.idle)} cycle=${teacher.latestCycle} why=${teacher.detail}`,
|
|
1446
1473
|
`embedder model=${embedder.model} provisioned=${yesNo(embedder.provisioned)} live=${yesNo(embedder.live)} why=${embedder.detail}`,
|
|
1447
1474
|
`routeFn available=${yesNo(routeFn.available)} freshness=${routeFn.freshness} trained=${routeFn.trainedAt ?? "none"} updated=${routeFn.updatedAt ?? "none"} used=${routeFn.usedAt ?? "none"} why=${routeFn.detail}`,
|
|
@@ -1454,8 +1481,10 @@ function buildCompactStatusHeader(status, report, options) {
|
|
|
1454
1481
|
function formatCurrentProfileStatusSummary(status, report, targetInspection, options) {
|
|
1455
1482
|
const installHook = summarizeStatusInstallHook(options.openclawHome);
|
|
1456
1483
|
const displayedStatus = summarizeDisplayedStatus(status, installHook);
|
|
1484
|
+
const hotfixBoundary = summarizeStatusHotfixBoundary(status);
|
|
1457
1485
|
const embeddings = summarizeStatusEmbeddings(report, options.providerConfig);
|
|
1458
1486
|
const localLlm = summarizeStatusLocalLlm(options.providerConfig);
|
|
1487
|
+
const teacher = summarizeStatusTeacher(report, options.providerConfig, localLlm);
|
|
1459
1488
|
const liveModels = embeddings.models.length === 0 ? "none" : embeddings.models.join("|");
|
|
1460
1489
|
const attachmentTruth = summarizeStatusAttachmentTruth({
|
|
1461
1490
|
activationRoot: status.host.activationRoot,
|
|
@@ -1480,6 +1509,7 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
|
|
|
1480
1509
|
`host runtime=${status.host.runtimeOwner} activation=${status.host.activationRoot}`,
|
|
1481
1510
|
`profile selector=${status.profile.selector}${profileIdSuffix} attachment=${status.attachment.state} policy=${status.attachment.policyMode}`,
|
|
1482
1511
|
`guard severity=${status.hook.guardSeverity} actionability=${status.hook.guardActionability} action=${status.hook.guardAction} summary=${status.hook.guardSummary}`,
|
|
1512
|
+
`surfaceNote ${hotfixBoundary.detail}`,
|
|
1483
1513
|
`attachTruth current=${attachmentTruth.currentProfileLabel} hook=${attachmentTruth.hookFiles} config=${attachmentTruth.configLoad} runtime=${attachmentTruth.runtimeLoad} watcher=${attachmentTruth.watcher} detail=${attachmentTruth.detail}`,
|
|
1484
1514
|
`attachedSet ${formatAttachedProfileTruthDetailedList(attachmentTruth.attachedProfiles)} proofPath=${shortenPath(attachmentTruth.runtimeProofPath)} proofError=${attachmentTruth.runtimeProofError ?? "none"}`,
|
|
1485
1515
|
`manyProfile surface=${report.manyProfile.operatorSurface} policy=${report.manyProfile.declaredAttachmentPolicy} intent=${report.manyProfile.sameGatewayIntent} checkedProof=${report.manyProfile.checkedInProofTopology} sameGatewayProof=${yesNo(report.manyProfile.sameGatewayProof)} sharedWriteProof=${yesNo(report.manyProfile.sharedWriteSafetyProof)}`,
|
|
@@ -1500,6 +1530,8 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
|
|
|
1500
1530
|
learningPath: report.learningPath,
|
|
1501
1531
|
tracedLearning
|
|
1502
1532
|
})}`,
|
|
1533
|
+
`learnFlow ${formatOperatorLearningFlowSummary({ tracedLearning })}`,
|
|
1534
|
+
`health ${formatOperatorLearningHealthSummary({ tracedLearning, teacher })}`,
|
|
1503
1535
|
`feedback ${formatOperatorFeedbackSummary({ tracedLearning })}`,
|
|
1504
1536
|
`attribution ${formatOperatorLearningAttributionSummary({ status })}`,
|
|
1505
1537
|
`attrCover ${formatOperatorAttributionCoverageSummary({ tracedLearning })}`,
|
|
@@ -4596,19 +4628,170 @@ function runUninstallCommand(parsed) {
|
|
|
4596
4628
|
}
|
|
4597
4629
|
return 0;
|
|
4598
4630
|
}
|
|
4599
|
-
function resolveServeTimeLearningRuntimeInput(activationRoot) {
|
|
4631
|
+
function resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport = null) {
|
|
4600
4632
|
const logPath = resolveLearningSpineLogPath(activationRoot, "serveTimeRouteDecisions");
|
|
4601
|
-
const { entries:
|
|
4633
|
+
const { entries: boundedServeTimeDecisions, fallbackReason } = readBoundedJsonlTail(logPath);
|
|
4634
|
+
const historicalRecovery = fallbackReason === null
|
|
4635
|
+
? { decisions: [], scanFailed: false }
|
|
4636
|
+
: readHistoricalServeTimeDecisions(logPath, collectServeTimeDecisionRecoveryTargets(normalizedEventExport));
|
|
4637
|
+
const serveTimeDecisions = mergeHistoricalServeTimeDecisions(historicalRecovery.decisions, boundedServeTimeDecisions);
|
|
4602
4638
|
const decisionLogCount = serveTimeDecisions.length;
|
|
4603
4639
|
const pgVersion = decisionLogCount > 0 ? "v2" : "v1";
|
|
4640
|
+
const resolvedFallbackReason = combineServeTimeLearningFallbackReasons(fallbackReason, historicalRecovery.scanFailed ? "historical_recovery_scan_failed" : null);
|
|
4604
4641
|
return {
|
|
4605
4642
|
pgVersion,
|
|
4606
4643
|
serveTimeDecisions,
|
|
4607
4644
|
decisionLogCount,
|
|
4608
4645
|
baselineState: pgVersion === "v2" ? loadOrInitBaseline(activationRoot) : undefined,
|
|
4609
|
-
fallbackReason:
|
|
4646
|
+
fallbackReason: resolvedFallbackReason === null ? null : `serve_time_decision_log_${resolvedFallbackReason}`
|
|
4610
4647
|
};
|
|
4611
4648
|
}
|
|
4649
|
+
function combineServeTimeLearningFallbackReasons(...reasons) {
|
|
4650
|
+
const resolved = reasons
|
|
4651
|
+
.filter((reason) => typeof reason === "string" && reason.length > 0);
|
|
4652
|
+
if (resolved.length === 0) {
|
|
4653
|
+
return null;
|
|
4654
|
+
}
|
|
4655
|
+
return [...new Set(resolved.flatMap((reason) => reason.split("+").filter((part) => part.length > 0)))].join("+");
|
|
4656
|
+
}
|
|
4657
|
+
function mergeHistoricalServeTimeDecisions(historicalDecisions, boundedServeTimeDecisions) {
|
|
4658
|
+
const merged = [];
|
|
4659
|
+
const seenRecordIds = new Set();
|
|
4660
|
+
for (const decision of [...historicalDecisions, ...boundedServeTimeDecisions]) {
|
|
4661
|
+
const recordId = normalizeServeTimeDecisionRecoveryString(decision?.recordId);
|
|
4662
|
+
if (recordId !== null) {
|
|
4663
|
+
if (seenRecordIds.has(recordId)) {
|
|
4664
|
+
continue;
|
|
4665
|
+
}
|
|
4666
|
+
seenRecordIds.add(recordId);
|
|
4667
|
+
}
|
|
4668
|
+
merged.push(decision);
|
|
4669
|
+
}
|
|
4670
|
+
return merged;
|
|
4671
|
+
}
|
|
4672
|
+
function readHistoricalServeTimeDecisions(logPath, targets) {
|
|
4673
|
+
if (!hasServeTimeDecisionRecoveryTargets(targets)) {
|
|
4674
|
+
return { decisions: [], scanFailed: false };
|
|
4675
|
+
}
|
|
4676
|
+
let raw;
|
|
4677
|
+
try {
|
|
4678
|
+
raw = readFileSync(logPath, "utf8");
|
|
4679
|
+
}
|
|
4680
|
+
catch {
|
|
4681
|
+
return { decisions: [], scanFailed: true };
|
|
4682
|
+
}
|
|
4683
|
+
const decisions = [];
|
|
4684
|
+
for (const line of raw.split(/\r?\n/u)) {
|
|
4685
|
+
const trimmed = line.trim();
|
|
4686
|
+
if (trimmed.length === 0) {
|
|
4687
|
+
continue;
|
|
4688
|
+
}
|
|
4689
|
+
try {
|
|
4690
|
+
const decision = JSON.parse(trimmed);
|
|
4691
|
+
const recordId = normalizeServeTimeDecisionRecoveryString(decision?.recordId);
|
|
4692
|
+
const selectionDigestKey = buildServeTimeDecisionRecoverySelectionKey(decision?.selectionDigest, decision?.activePackGraphChecksum);
|
|
4693
|
+
const turnCompileEventId = normalizeServeTimeDecisionRecoveryString(decision?.turnCompileEventId);
|
|
4694
|
+
if ((recordId !== null && targets.recordIds.has(recordId)) ||
|
|
4695
|
+
(selectionDigestKey !== null && targets.selectionDigestKeys.has(selectionDigestKey)) ||
|
|
4696
|
+
(turnCompileEventId !== null && targets.turnCompileEventIds.has(turnCompileEventId))) {
|
|
4697
|
+
decisions.push(decision);
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
catch {
|
|
4701
|
+
// skip malformed lines
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
return { decisions, scanFailed: false };
|
|
4705
|
+
}
|
|
4706
|
+
function hasServeTimeDecisionRecoveryTargets(targets) {
|
|
4707
|
+
return targets.recordIds.size > 0 ||
|
|
4708
|
+
targets.selectionDigestKeys.size > 0 ||
|
|
4709
|
+
targets.turnCompileEventIds.size > 0;
|
|
4710
|
+
}
|
|
4711
|
+
function collectServeTimeDecisionRecoveryTargets(normalizedEventExport) {
|
|
4712
|
+
const targets = {
|
|
4713
|
+
recordIds: new Set(),
|
|
4714
|
+
selectionDigestKeys: new Set(),
|
|
4715
|
+
turnCompileEventIds: new Set()
|
|
4716
|
+
};
|
|
4717
|
+
const interactions = Array.isArray(normalizedEventExport?.interactionEvents)
|
|
4718
|
+
? normalizedEventExport.interactionEvents
|
|
4719
|
+
: [];
|
|
4720
|
+
const feedbackEvents = Array.isArray(normalizedEventExport?.feedbackEvents)
|
|
4721
|
+
? normalizedEventExport.feedbackEvents
|
|
4722
|
+
: [];
|
|
4723
|
+
const interactionsById = new Map();
|
|
4724
|
+
for (const interaction of interactions) {
|
|
4725
|
+
const interactionId = normalizeServeTimeDecisionRecoveryString(interaction?.eventId);
|
|
4726
|
+
if (interactionId !== null && !interactionsById.has(interactionId)) {
|
|
4727
|
+
interactionsById.set(interactionId, interaction);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
const candidateInteractions = [];
|
|
4731
|
+
for (const feedback of feedbackEvents) {
|
|
4732
|
+
const relatedInteractionId = normalizeServeTimeDecisionRecoveryString(feedback?.relatedInteractionId);
|
|
4733
|
+
if (relatedInteractionId === null) {
|
|
4734
|
+
continue;
|
|
4735
|
+
}
|
|
4736
|
+
targets.turnCompileEventIds.add(relatedInteractionId);
|
|
4737
|
+
const relatedInteraction = interactionsById.get(relatedInteractionId);
|
|
4738
|
+
if (relatedInteraction !== undefined) {
|
|
4739
|
+
candidateInteractions.push(relatedInteraction);
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
for (const interaction of candidateInteractions) {
|
|
4743
|
+
const routeMetadata = readServeTimeDecisionRecoveryRecord(interaction?.routeMetadata);
|
|
4744
|
+
const decisionProvenance = readServeTimeDecisionRecoveryRecord(interaction?.decisionProvenance);
|
|
4745
|
+
const metadata = readServeTimeDecisionRecoveryRecord(interaction?.metadata);
|
|
4746
|
+
const serveDecisionRecordId = normalizeServeTimeDecisionRecoveryString(interaction?.serveDecisionRecordId)
|
|
4747
|
+
?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.serveDecisionRecordId)
|
|
4748
|
+
?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.serveDecisionRecordId)
|
|
4749
|
+
?? normalizeServeTimeDecisionRecoveryString(metadata?.serveDecisionRecordId);
|
|
4750
|
+
if (serveDecisionRecordId !== null) {
|
|
4751
|
+
targets.recordIds.add(serveDecisionRecordId);
|
|
4752
|
+
}
|
|
4753
|
+
const selectionDigestKey = buildServeTimeDecisionRecoverySelectionKey(normalizeServeTimeDecisionRecoveryString(interaction?.selectionDigest)
|
|
4754
|
+
?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.selectionDigest)
|
|
4755
|
+
?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.selectionDigest)
|
|
4756
|
+
?? normalizeServeTimeDecisionRecoveryString(metadata?.selectionDigest), normalizeServeTimeDecisionRecoveryString(interaction?.activePackGraphChecksum)
|
|
4757
|
+
?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.activePackGraphChecksum)
|
|
4758
|
+
?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.activePackGraphChecksum)
|
|
4759
|
+
?? normalizeServeTimeDecisionRecoveryString(metadata?.activePackGraphChecksum));
|
|
4760
|
+
if (selectionDigestKey !== null) {
|
|
4761
|
+
targets.selectionDigestKeys.add(selectionDigestKey);
|
|
4762
|
+
}
|
|
4763
|
+
const explicitTurnCompileEventId = normalizeServeTimeDecisionRecoveryString(interaction?.turnCompileEventId)
|
|
4764
|
+
?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.turnCompileEventId)
|
|
4765
|
+
?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.turnCompileEventId)
|
|
4766
|
+
?? normalizeServeTimeDecisionRecoveryString(metadata?.turnCompileEventId);
|
|
4767
|
+
if (explicitTurnCompileEventId !== null) {
|
|
4768
|
+
targets.turnCompileEventIds.add(explicitTurnCompileEventId);
|
|
4769
|
+
}
|
|
4770
|
+
const softTurnCompileEventId = normalizeServeTimeDecisionRecoveryString(interaction?.eventId);
|
|
4771
|
+
if (softTurnCompileEventId !== null) {
|
|
4772
|
+
targets.turnCompileEventIds.add(softTurnCompileEventId);
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
return targets;
|
|
4776
|
+
}
|
|
4777
|
+
function readServeTimeDecisionRecoveryRecord(value) {
|
|
4778
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4779
|
+
}
|
|
4780
|
+
function normalizeServeTimeDecisionRecoveryString(value) {
|
|
4781
|
+
if (typeof value !== "string") {
|
|
4782
|
+
return null;
|
|
4783
|
+
}
|
|
4784
|
+
const trimmed = value.trim();
|
|
4785
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4786
|
+
}
|
|
4787
|
+
function buildServeTimeDecisionRecoverySelectionKey(selectionDigest, activePackGraphChecksum) {
|
|
4788
|
+
const normalizedSelectionDigest = normalizeServeTimeDecisionRecoveryString(selectionDigest);
|
|
4789
|
+
const normalizedGraphChecksum = normalizeServeTimeDecisionRecoveryString(activePackGraphChecksum);
|
|
4790
|
+
if (normalizedSelectionDigest === null || normalizedGraphChecksum === null) {
|
|
4791
|
+
return null;
|
|
4792
|
+
}
|
|
4793
|
+
return `${normalizedGraphChecksum}|${normalizedSelectionDigest}`;
|
|
4794
|
+
}
|
|
4612
4795
|
function resolveActivationInspectionPackId(inspection, slot) {
|
|
4613
4796
|
return inspection?.[slot]?.packId ?? inspection?.pointers?.[slot]?.packId ?? null;
|
|
4614
4797
|
}
|
|
@@ -4854,7 +5037,7 @@ async function runLearnCommand(parsed) {
|
|
|
4854
5037
|
}
|
|
4855
5038
|
const learningExport = normalizedEventExport;
|
|
4856
5039
|
const resolvedEmbedder = resolveCliEmbedderConfig(undefined, activationRoot);
|
|
4857
|
-
const serveTimeLearning = resolveServeTimeLearningRuntimeInput(activationRoot);
|
|
5040
|
+
const serveTimeLearning = resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport);
|
|
4858
5041
|
const learnerResult = drainAlwaysOnLearningRuntime({
|
|
4859
5042
|
packLabel: "learn-cli",
|
|
4860
5043
|
workspace: {
|
|
@@ -5678,8 +5861,8 @@ export async function createWatchCommandRuntime(input) {
|
|
|
5678
5861
|
},
|
|
5679
5862
|
learnedRouting: true,
|
|
5680
5863
|
...(teacherLabeler !== null ? { teacherLabeler } : {}),
|
|
5681
|
-
resolveLearnedRoutingState: () => {
|
|
5682
|
-
const resolved = resolveServeTimeLearningRuntimeInput(activationRoot);
|
|
5864
|
+
resolveLearnedRoutingState: (normalizedEventExport) => {
|
|
5865
|
+
const resolved = resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport);
|
|
5683
5866
|
if (resolved.fallbackReason !== null && resolved.fallbackReason !== lastServeTimeFallbackReason) {
|
|
5684
5867
|
log(`Serve-time routing fallback: ${resolved.fallbackReason}`);
|
|
5685
5868
|
}
|
|
@@ -6367,10 +6550,12 @@ export function runOperatorCli(argv = process.argv.slice(2)) {
|
|
|
6367
6550
|
const status = statusWithReport.status;
|
|
6368
6551
|
const tracedLearning = buildTracedLearningStatusSurface(activationRoot);
|
|
6369
6552
|
const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, statusOrRollback.json ? null : statusWithReport.report);
|
|
6553
|
+
const hotfixBoundaryTruth = summarizeStatusHotfixBoundary(normalizedStatusAndReport.status);
|
|
6370
6554
|
if (statusOrRollback.json) {
|
|
6371
6555
|
console.log(JSON.stringify({
|
|
6372
6556
|
...normalizedStatusAndReport.status,
|
|
6373
|
-
tracedLearning
|
|
6557
|
+
tracedLearning,
|
|
6558
|
+
hotfixBoundaryTruth
|
|
6374
6559
|
}, null, 2));
|
|
6375
6560
|
}
|
|
6376
6561
|
else {
|
package/dist/src/daemon.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface ManagedLearnerServiceInspection {
|
|
|
46
46
|
configuredCommand: string | null;
|
|
47
47
|
configuredRuntimePath: string | null;
|
|
48
48
|
configuredRuntimePackageSpec: string | null;
|
|
49
|
+
configuredRuntimePackageName: string | null;
|
|
50
|
+
configuredRuntimePackageVersion: string | null;
|
|
49
51
|
configuredRuntimeLooksEphemeral: boolean | null;
|
|
50
52
|
matchesRequestedActivationRoot: boolean | null;
|
|
51
53
|
launchctlAvailable: boolean;
|
package/dist/src/daemon.js
CHANGED
|
@@ -306,6 +306,17 @@ export function describeManagedLearnerServiceRuntimeGuard(inspection) {
|
|
|
306
306
|
detail: `Learner service points at the durable ${CLI_PACKAGE_NAME} runtime.`
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
|
+
function buildDaemonHotfixBoundary(inspection) {
|
|
310
|
+
return {
|
|
311
|
+
surface: "daemon_runtime",
|
|
312
|
+
separateFromInstalledHookSurface: true,
|
|
313
|
+
runtimePath: inspection.configuredRuntimePath ?? null,
|
|
314
|
+
guidance: "Patch this daemon runtime path for background watch/learner fixes. Use `openclawbrain status --openclaw-home <path> --detailed` to inspect the separate installed hook/runtime-guard surface before patching OpenClaw load behavior.",
|
|
315
|
+
detail: inspection.configuredRuntimePath === null
|
|
316
|
+
? "daemon status is only reporting the background watch surface; no configured runtime path is visible yet."
|
|
317
|
+
: `daemon status is reporting the background watch runtime at ${inspection.configuredRuntimePath}; installed hook/runtime-guard paths live on the OpenClaw profile side.`
|
|
318
|
+
};
|
|
319
|
+
}
|
|
309
320
|
function resolveDaemonProgramArguments() {
|
|
310
321
|
for (const candidate of getOpenclawbrainCliScriptPathCandidates()) {
|
|
311
322
|
const cliScriptPath = resolveCliScriptCandidate(candidate);
|
|
@@ -970,6 +981,11 @@ export function daemonStatus(activationRoot, json) {
|
|
|
970
981
|
? null
|
|
971
982
|
: canonicalizeActivationRoot(configuredActivationRoot) === serviceIdentity.canonicalActivationRoot;
|
|
972
983
|
const daemonLaunchDescription = describeDaemonProgramArguments(configuredProgramArguments);
|
|
984
|
+
const hotfixBoundary = buildDaemonHotfixBoundary({
|
|
985
|
+
installed: plistInstalled,
|
|
986
|
+
configuredProgramArguments,
|
|
987
|
+
...daemonLaunchDescription,
|
|
988
|
+
});
|
|
973
989
|
if (json) {
|
|
974
990
|
console.log(JSON.stringify({
|
|
975
991
|
command: "daemon status",
|
|
@@ -986,6 +1002,7 @@ export function daemonStatus(activationRoot, json) {
|
|
|
986
1002
|
...watchStatePaths,
|
|
987
1003
|
watchState,
|
|
988
1004
|
lastLogLines,
|
|
1005
|
+
hotfixBoundary,
|
|
989
1006
|
}, null, 2));
|
|
990
1007
|
}
|
|
991
1008
|
else {
|
|
@@ -1015,6 +1032,8 @@ export function daemonStatus(activationRoot, json) {
|
|
|
1015
1032
|
const runtimeWarning = daemonLaunchDescription.configuredRuntimeLooksEphemeral ? " [ephemeral]" : "";
|
|
1016
1033
|
console.log(` Runtime: ${daemonLaunchDescription.configuredRuntimePath}${runtimePackageSuffix}${runtimeWarning}`);
|
|
1017
1034
|
}
|
|
1035
|
+
console.log(" Runtime surface: daemon watch/learner runtime");
|
|
1036
|
+
console.log(` Hotfix boundary: ${hotfixBoundary.guidance}`);
|
|
1018
1037
|
const runtimeGuard = describeManagedLearnerServiceRuntimeGuard({
|
|
1019
1038
|
installed: plistInstalled,
|
|
1020
1039
|
configuredProgramArguments,
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type CompileSelectionMode } from "@openclawbrain/compiler";
|
|
2
2
|
import { CONTRACT_IDS, type ArtifactManifestV1, type ActivationPointerRecordV1, type ActivationPointerSlot, type RuntimeTurnBrainAttachmentPolicyV1, type ContextCompactionMode, type ContextContributionEvidenceStateV1, type CurrentProfileBrainStatusAnswerV1, type CurrentProfileActivationStateV1, type CurrentProfilePassiveLearningDeltaSummaryV1, type CurrentProfilePassiveLearningWatchStateV1, type CurrentProfileAttachmentStateV1, type CurrentProfileAttachmentProofStateV1, type CurrentProfileHookInstallStateV1, type CurrentProfileHookLoadabilityV1, type CurrentProfileHookLoadProofV1, type BrainServeHotPathTimingV1, type CurrentProfileStructuralDecisionV1, type FeedbackEventKind, type PackGraphConnectDiagnosticsV1, type PackGraphEvolutionV1, type EventSemanticSurfaceV1, type FeedbackEventV1, type KernelSurfaceValidationResultV1, type LearningBootProfile, type LearningCadence, type LearningScanPolicy, type InteractionEventV1, type NormalizedEventExportV1, type NormalizedEventV1, type PrincipalPriorityClassV1, type PrincipalRoleV1, type RouteMode, type RuntimeCompileResponseV1, type RuntimeCompileStructuralSignalsV1, type RuntimeCompileTargetV1, type RuntimeGraphPlasticityStateV1, type RuntimePlasticitySourceV1, type SparseFeedbackPolicyV1, type TeacherAuthorityV1, type TeacherSupervisionArtifactV1, type WorkspaceInjectionSurfaceV1 } from "@openclawbrain/contracts";
|
|
3
3
|
import { type EventExportLaneV1 } from "@openclawbrain/event-export";
|
|
4
|
-
import { type AdvanceAlwaysOnLearningRuntimeInput, type AlwaysOnLearningCadenceV1, type AlwaysOnLearningMaterializationJobV1, type AlwaysOnLearningRuntimePlanV1, type AlwaysOnLearningRuntimeStateV1, type BaselineStateV1, type PendingPrincipalEventV1, type PrincipalLearningCheckpointV1 } from "./local-learner.js";
|
|
5
|
-
import { type ActivationInspection, type ActivationObservabilityReport, type GraphEvolutionLogV1, type LearningSpineServeRouteBreadcrumbsV1, type ActivationSlotInspection, type InitHandoffState
|
|
4
|
+
import { type AdvanceAlwaysOnLearningRuntimeInput, type AlwaysOnLearningCadenceV1, type AlwaysOnLearningMaterializationJobV1, type AlwaysOnLearningRuntimePlanV1, type AlwaysOnLearningRuntimeStateV1, type BaselineStateV1, type PendingPrincipalEventV1, type PrincipalLearningCheckpointV1, type LearningSpineServeRouteDecisionLogEntryV1 } from "./local-learner.js";
|
|
5
|
+
import { type ActivationInspection, type ActivationObservabilityReport, type GraphEvolutionLogV1, type LearningSpineServeRouteBreadcrumbsV1, type ActivationSlotInspection, type InitHandoffState } from "@openclawbrain/pack-format";
|
|
6
6
|
export { clearOpenClawProfileRuntimeLoadProof, listOpenClawProfileRuntimeLoadProofs, recordOpenClawProfileRuntimeLoadProof, resolveAttachmentRuntimeLoadProofsPath, type OpenClawProfileRuntimeLoadProofRecordV1, type OpenClawProfileRuntimeLoadProofSetV1, type OpenClawProfileRuntimeLoadProofsV1 } from "./attachment-truth.js";
|
|
7
7
|
import { type AsyncTeacherLabelerConfigV1 } from "./teacher-labeler.js";
|
|
8
8
|
export { createHttpOllamaTeacherLabelerClient, createOllamaTeacherLabeler, createTeacherLabeler, summarizeTeacherLabelerOpportunity, type AsyncTeacherLabelerConfigV1, type AsyncTeacherNoopLabelerConfigV1, type AsyncTeacherOllamaLabelerConfigV1, type OllamaTeacherLabelerClient, type TeacherLabeler, type TeacherLabelerOpportunityInputV1, type TeacherLabelerOpportunityV1, type TeacherLabelerResultV1, type TeacherLabelerRunInputV1 } from "./teacher-labeler.js";
|
package/dist/src/index.js
CHANGED
|
@@ -904,7 +904,7 @@ export class AsyncTeacherLiveLoop {
|
|
|
904
904
|
interactionEvents: this.interactionEvents,
|
|
905
905
|
feedbackEvents: this.feedbackEvents
|
|
906
906
|
});
|
|
907
|
-
const learnedRoutingState = this.input.resolveLearnedRoutingState?.() ?? {};
|
|
907
|
+
const learnedRoutingState = this.input.resolveLearnedRoutingState?.(mergedNormalizedEventExport) ?? {};
|
|
908
908
|
const currentDedupIds = new Set(this.teacherArtifacts.map((artifact) => artifact.dedupId));
|
|
909
909
|
const currentCycleBuiltArtifacts = buildTeacherSupervisionArtifactsFromNormalizedEventExport({
|
|
910
910
|
normalizedEventExport: job.normalizedEventExport,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AlwaysOnLearningMaterializationJobV1 } from "@openclawbrain/learner";
|
|
2
2
|
import { type BrainServeHotPathTimingV1, type NormalizedEventExportV1, type RouteMode, type RuntimeCompileResponseV1 } from "@openclawbrain/contracts";
|
|
3
|
-
import { type LearningSpinePgRouteUpdateLogEntryV1, type LearningSpineServeRouteBreadcrumbsV1, type
|
|
3
|
+
import { type LearningSpinePgRouteUpdateLogEntryV1, type LearningSpineServeRouteBreadcrumbsV1, type PackDescriptor } from "@openclawbrain/pack-format";
|
|
4
|
+
import { type LearningSpineServeRouteDecisionLogEntryV1 } from "./local-learner.js";
|
|
4
5
|
type CompileFailureLike = {
|
|
5
6
|
ok: false;
|
|
6
7
|
fallbackToStaticContext: boolean;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import { type ArtifactManifestV1, type FeedbackEventV1, type InteractionEventV1, type NormalizedEventExportV1, type NormalizedEventV1, type PrincipalPriorityClassV1, type PrincipalRoleV1, type PackGraphPayloadV1, type PackVectorsPayloadV1, type RouterArtifactV1, type RouterPolicyUpdateV1, type RuntimeCompileStructuralSignalsV1, type RuntimeGraphPlasticityStateV1, type SparseFeedbackPolicyV1, type TeacherSupervisionArtifactV1 } from "@openclawbrain/contracts";
|
|
2
2
|
import { type EventExportCursorV1, type EventExportLaneV1, type NormalizedEventExportBridgeV1, type NormalizedEventExportSliceV1 } from "@openclawbrain/event-export";
|
|
3
3
|
import type { TextEmbedder } from "@openclawbrain/compiler";
|
|
4
|
-
import { type PackDescriptor, type GraphEvolutionLogV1, type LearningSpineServeRouteDecisionLogEntryV1 } from "@openclawbrain/pack-format";
|
|
4
|
+
import { type PackDescriptor, type GraphEvolutionLogV1, type LearningSpineServeRouteDecisionLogEntryV1 as PackFormatLearningSpineServeRouteDecisionLogEntryV1 } from "@openclawbrain/pack-format";
|
|
5
5
|
import { type WorkspaceMetadataInput } from "@openclawbrain/workspace-metadata";
|
|
6
|
+
export interface LearningSpineServeRouteCandidateScoreV1 {
|
|
7
|
+
blockId: string;
|
|
8
|
+
selected: boolean;
|
|
9
|
+
actionScore: number;
|
|
10
|
+
actionProbability: number;
|
|
11
|
+
compactedFrom?: string[];
|
|
12
|
+
matchedTokens?: string[];
|
|
13
|
+
routingChannels?: string[];
|
|
14
|
+
}
|
|
15
|
+
export type LearningSpineServeRouteDecisionLogEntryV1 = Omit<PackFormatLearningSpineServeRouteDecisionLogEntryV1, "candidateSetIds" | "chosenContextIds" | "candidateScores" | "selectedKernelContextIds" | "selectedBrainContextIds"> & {
|
|
16
|
+
candidateSetIds: string[];
|
|
17
|
+
chosenContextIds: string[];
|
|
18
|
+
candidateScores: LearningSpineServeRouteCandidateScoreV1[];
|
|
19
|
+
selectedKernelContextIds: string[];
|
|
20
|
+
selectedBrainContextIds: string[];
|
|
21
|
+
};
|
|
6
22
|
export interface CandidatePackEventExports {
|
|
7
23
|
interactionEvents: InteractionEventV1[];
|
|
8
24
|
feedbackEvents: FeedbackEventV1[];
|
|
@@ -455,6 +455,98 @@ function normalizeTeacherSupervisionArtifacts(artifacts) {
|
|
|
455
455
|
.filter((artifact) => !artifact.sourceEventIds.some((eventId) => supersededEventIds.has(eventId)))
|
|
456
456
|
.sort(compareTeacherSupervisionArtifacts);
|
|
457
457
|
}
|
|
458
|
+
function normalizeServeTimeDecisionStringArray(values) {
|
|
459
|
+
if (!Array.isArray(values)) {
|
|
460
|
+
return [];
|
|
461
|
+
}
|
|
462
|
+
return values.filter((value) => typeof value === "string" && value.length > 0);
|
|
463
|
+
}
|
|
464
|
+
function normalizeServeTimeDecisionScore(score) {
|
|
465
|
+
if (score === null || typeof score !== "object" || Array.isArray(score)) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
if (typeof score.blockId !== "string" || score.blockId.length === 0) {
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
blockId: score.blockId,
|
|
473
|
+
selected: score.selected === true,
|
|
474
|
+
actionScore: Number.isFinite(score.actionScore) ? score.actionScore : 0,
|
|
475
|
+
actionProbability: Number.isFinite(score.actionProbability) ? score.actionProbability : 0,
|
|
476
|
+
...(Array.isArray(score.compactedFrom) ? { compactedFrom: normalizeServeTimeDecisionStringArray(score.compactedFrom) } : {}),
|
|
477
|
+
...(Array.isArray(score.matchedTokens) ? { matchedTokens: normalizeServeTimeDecisionStringArray(score.matchedTokens) } : {}),
|
|
478
|
+
...(Array.isArray(score.routingChannels) ? { routingChannels: normalizeServeTimeDecisionStringArray(score.routingChannels) } : {})
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function normalizeServeTimeDecisionLogEntry(decision) {
|
|
482
|
+
if (decision === null || typeof decision !== "object" || Array.isArray(decision)) {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
const selectedKernelContextIds = normalizeServeTimeDecisionStringArray(decision.selectedKernelContextIds);
|
|
486
|
+
const selectedBrainContextIds = normalizeServeTimeDecisionStringArray(decision.selectedBrainContextIds);
|
|
487
|
+
return {
|
|
488
|
+
...decision,
|
|
489
|
+
candidateSetIds: normalizeServeTimeDecisionStringArray(decision.candidateSetIds),
|
|
490
|
+
chosenContextIds: normalizeServeTimeDecisionStringArray(decision.chosenContextIds),
|
|
491
|
+
candidateScores: Array.isArray(decision.candidateScores)
|
|
492
|
+
? decision.candidateScores.map((score) => normalizeServeTimeDecisionScore(score)).filter((score) => score !== null)
|
|
493
|
+
: [],
|
|
494
|
+
kernelContextCount: Number.isInteger(decision.kernelContextCount) && decision.kernelContextCount >= 0
|
|
495
|
+
? decision.kernelContextCount
|
|
496
|
+
: selectedKernelContextIds.length,
|
|
497
|
+
brainContextCount: Number.isInteger(decision.brainContextCount) && decision.brainContextCount >= 0
|
|
498
|
+
? decision.brainContextCount
|
|
499
|
+
: selectedBrainContextIds.length,
|
|
500
|
+
selectedKernelContextIds,
|
|
501
|
+
selectedBrainContextIds
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function normalizeServeTimeDecisionsForLearner(serveTimeDecisions) {
|
|
505
|
+
if (serveTimeDecisions === undefined) {
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
if (!Array.isArray(serveTimeDecisions)) {
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
return serveTimeDecisions
|
|
512
|
+
.map((decision) => normalizeServeTimeDecisionLogEntry(decision))
|
|
513
|
+
.filter((decision) => decision !== null);
|
|
514
|
+
}
|
|
515
|
+
function projectServeTimeDecisionForRoutingSeed(decision) {
|
|
516
|
+
return {
|
|
517
|
+
recordId: typeof decision.recordId === "string" ? decision.recordId : null,
|
|
518
|
+
recordedAt: typeof decision.recordedAt === "string" ? decision.recordedAt : null,
|
|
519
|
+
sessionId: typeof decision.sessionId === "string" ? decision.sessionId : null,
|
|
520
|
+
channel: typeof decision.channel === "string" ? decision.channel : null,
|
|
521
|
+
turnCompileEventId: typeof decision.turnCompileEventId === "string" ? decision.turnCompileEventId : null,
|
|
522
|
+
turnCreatedAt: typeof decision.turnCreatedAt === "string" ? decision.turnCreatedAt : null,
|
|
523
|
+
activePackId: typeof decision.activePackId === "string" ? decision.activePackId : null,
|
|
524
|
+
activePackGraphChecksum: typeof decision.activePackGraphChecksum === "string" ? decision.activePackGraphChecksum : null,
|
|
525
|
+
routerIdentity: typeof decision.routerIdentity === "string" ? decision.routerIdentity : null,
|
|
526
|
+
selectionDigest: typeof decision.selectionDigest === "string" ? decision.selectionDigest : null,
|
|
527
|
+
usedLearnedRouteFn: decision.usedLearnedRouteFn === true,
|
|
528
|
+
fallbackReason: typeof decision.fallbackReason === "string" ? decision.fallbackReason : null,
|
|
529
|
+
candidateSetIds: decision.candidateSetIds,
|
|
530
|
+
chosenContextIds: decision.chosenContextIds,
|
|
531
|
+
candidateScores: decision.candidateScores.map((score) => ({
|
|
532
|
+
blockId: score.blockId,
|
|
533
|
+
selected: score.selected,
|
|
534
|
+
actionScore: score.actionScore,
|
|
535
|
+
actionProbability: score.actionProbability,
|
|
536
|
+
compactedFrom: score.compactedFrom ?? []
|
|
537
|
+
})),
|
|
538
|
+
kernelContextCount: decision.kernelContextCount,
|
|
539
|
+
brainContextCount: decision.brainContextCount,
|
|
540
|
+
selectedKernelContextIds: decision.selectedKernelContextIds,
|
|
541
|
+
selectedBrainContextIds: decision.selectedBrainContextIds
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function checksumServeTimeDecisionsForRoutingSeed(serveTimeDecisions) {
|
|
545
|
+
if (serveTimeDecisions === undefined) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
return checksumJsonPayload(serveTimeDecisions.map((decision) => projectServeTimeDecisionForRoutingSeed(decision)));
|
|
549
|
+
}
|
|
458
550
|
function teacherSupervisionContentForInteraction(event) {
|
|
459
551
|
const message = event.messageId === undefined ? "" : ` Message: ${event.messageId}.`;
|
|
460
552
|
const pack = event.packId === undefined ? "" : ` Pack: ${event.packId}.`;
|
|
@@ -893,7 +985,7 @@ function buildAlwaysOnLearningMaterializationJob(input, current, selectedSlices,
|
|
|
893
985
|
...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
|
|
894
986
|
principalBacklog,
|
|
895
987
|
...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
|
|
896
|
-
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions:
|
|
988
|
+
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
|
|
897
989
|
...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {}),
|
|
898
990
|
...(input.activationRoot !== undefined ? { activationRoot: input.activationRoot } : {})
|
|
899
991
|
};
|
|
@@ -1049,7 +1141,7 @@ export function buildCandidatePackFromNormalizedEventExportSlice(input) {
|
|
|
1049
1141
|
...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
|
|
1050
1142
|
...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
|
|
1051
1143
|
...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
|
|
1052
|
-
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions:
|
|
1144
|
+
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
|
|
1053
1145
|
...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {})
|
|
1054
1146
|
});
|
|
1055
1147
|
}
|
|
@@ -1080,7 +1172,7 @@ export function buildCandidatePackBundleFromNormalizedEventExportBridge(input) {
|
|
|
1080
1172
|
...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
|
|
1081
1173
|
...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
|
|
1082
1174
|
...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
|
|
1083
|
-
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions:
|
|
1175
|
+
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
|
|
1084
1176
|
...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {})
|
|
1085
1177
|
})
|
|
1086
1178
|
};
|
|
@@ -3565,7 +3657,8 @@ function remapServeTimeDecisionToGraph(decision, resolveBlockId) {
|
|
|
3565
3657
|
const remappedSelectedBrainContextIds = remapIds(decision.selectedBrainContextIds);
|
|
3566
3658
|
const chosenSet = new Set(remappedChosenContextIds);
|
|
3567
3659
|
const remappedScoresByBlockId = new Map();
|
|
3568
|
-
|
|
3660
|
+
const candidateScores = Array.isArray(decision.candidateScores) ? decision.candidateScores : [];
|
|
3661
|
+
for (const score of candidateScores) {
|
|
3569
3662
|
const resolvedBlockId = resolveBlockId(score.blockId);
|
|
3570
3663
|
if (resolvedBlockId === null) {
|
|
3571
3664
|
continue;
|
|
@@ -4540,13 +4633,15 @@ function buildGraphLocalActionSetFromScores(nodeBlockId, neighborBlockIds, graph
|
|
|
4540
4633
|
* Traces through the graph starting from the highest-scoring selected block.
|
|
4541
4634
|
*/
|
|
4542
4635
|
export function reconstructTrajectoryFromServeDecision(decision, graph, vectors, adjacency, tau, outcome, baselineValue) {
|
|
4543
|
-
const
|
|
4636
|
+
const chosenContextIds = Array.isArray(decision.chosenContextIds) ? decision.chosenContextIds : [];
|
|
4637
|
+
const candidateScores = Array.isArray(decision.candidateScores) ? decision.candidateScores : [];
|
|
4638
|
+
const chosenSet = new Set(chosenContextIds);
|
|
4544
4639
|
const candidateScoresMap = new Map();
|
|
4545
|
-
for (const cs of
|
|
4640
|
+
for (const cs of candidateScores) {
|
|
4546
4641
|
candidateScoresMap.set(cs.blockId, cs.actionScore);
|
|
4547
4642
|
}
|
|
4548
4643
|
// Sort chosen blocks by score descending to find entry point
|
|
4549
|
-
const chosenWithScores =
|
|
4644
|
+
const chosenWithScores = chosenContextIds
|
|
4550
4645
|
.map((blockId) => ({ blockId, score: candidateScoresMap.get(blockId) ?? 0 }))
|
|
4551
4646
|
.sort((a, b) => b.score - a.score);
|
|
4552
4647
|
const steps = [];
|
|
@@ -4679,7 +4774,7 @@ function createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, se
|
|
|
4679
4774
|
// 1. Build adjacency map from graph
|
|
4680
4775
|
const adjacency = buildAdjacencyMap(graph);
|
|
4681
4776
|
const resolveBlockId = buildGraphBlockIdResolver(graph);
|
|
4682
|
-
const remappedServeTimeDecisions = serveTimeDecisions.map((decision) => remapServeTimeDecisionToGraph(decision, resolveBlockId));
|
|
4777
|
+
const remappedServeTimeDecisions = (serveTimeDecisions ?? []).map((decision) => remapServeTimeDecisionToGraph(decision, resolveBlockId));
|
|
4683
4778
|
// 2. Join serve-time decisions with explicit feedback first, then let teacher-v2 observations override when available.
|
|
4684
4779
|
const outcomeMap = joinDecisionsWithFeedback(remappedServeTimeDecisions, eventExport);
|
|
4685
4780
|
const teacherObservationBindings = joinDecisionsWithTeacherObservationOutcomes(remappedServeTimeDecisions, teacherObservationOutcomes);
|
|
@@ -4710,7 +4805,7 @@ function createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, se
|
|
|
4710
4805
|
`traj-${stableHash(checksumJsonPayload({ decisionId: d.recordId, steps: trajectory.steps.map((s) => s.nodeBlockId) }))}` === trajectory.trajectoryId);
|
|
4711
4806
|
const candidateScoresMap = new Map();
|
|
4712
4807
|
if (decision !== undefined) {
|
|
4713
|
-
for (const cs of decision.candidateScores) {
|
|
4808
|
+
for (const cs of decision.candidateScores ?? []) {
|
|
4714
4809
|
candidateScoresMap.set(cs.blockId, cs.actionScore);
|
|
4715
4810
|
}
|
|
4716
4811
|
}
|
|
@@ -5000,7 +5095,8 @@ export function buildCandidatePack(input) {
|
|
|
5000
5095
|
});
|
|
5001
5096
|
const learningSurface = eventExport?.provenance.learningSurface ?? defaultLearningSurface(workspace, offlineArtifacts, workspaceInit);
|
|
5002
5097
|
const sparseFeedback = normalizeSparseFeedbackPolicy(input.sparseFeedback);
|
|
5003
|
-
const
|
|
5098
|
+
const serveTimeDecisions = normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions);
|
|
5099
|
+
const decisionLogCount = serveTimeDecisions?.length ?? 0;
|
|
5004
5100
|
const useV2 = input.pgVersion === "v2" && decisionLogCount > 0;
|
|
5005
5101
|
const fallbackReason = !input.learnedRouting
|
|
5006
5102
|
? null
|
|
@@ -5010,7 +5106,7 @@ export function buildCandidatePack(input) {
|
|
|
5010
5106
|
const routingSeed = input.learnedRouting && (input.pgVersion === "v2" || decisionLogCount > 0 || input.baselineState !== undefined)
|
|
5011
5107
|
? {
|
|
5012
5108
|
pgVersionRequested: input.pgVersion ?? "v1",
|
|
5013
|
-
serveTimeDecisionDigest:
|
|
5109
|
+
serveTimeDecisionDigest: checksumServeTimeDecisionsForRoutingSeed(serveTimeDecisions),
|
|
5014
5110
|
baselineState: input.baselineState ?? null
|
|
5015
5111
|
}
|
|
5016
5112
|
: null;
|
|
@@ -5048,7 +5144,7 @@ export function buildCandidatePack(input) {
|
|
|
5048
5144
|
: loadTeacherObservationOutcomesFromActivation(input.activationRoot);
|
|
5049
5145
|
if (input.learnedRouting) {
|
|
5050
5146
|
if (useV2) {
|
|
5051
|
-
const v2Result = createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport,
|
|
5147
|
+
const v2Result = createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, serveTimeDecisions ?? [], input.baselineState ?? initBaseline(), input.sparseFeedback, input.principalBacklog, teacherObservationOutcomes);
|
|
5052
5148
|
router = v2Result.artifact;
|
|
5053
5149
|
updatedBaseline = v2Result.updatedBaseline;
|
|
5054
5150
|
observationBindingStats = v2Result.observationBindingStats;
|
|
@@ -5211,7 +5307,7 @@ export function buildCandidatePackFromNormalizedEventExport(input) {
|
|
|
5211
5307
|
...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
|
|
5212
5308
|
...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
|
|
5213
5309
|
...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
|
|
5214
|
-
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions:
|
|
5310
|
+
...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
|
|
5215
5311
|
...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {}),
|
|
5216
5312
|
...(input.activationRoot !== undefined ? { activationRoot: input.activationRoot } : {})
|
|
5217
5313
|
};
|
|
@@ -16,6 +16,7 @@ export interface OpenClawBrainHookInspection {
|
|
|
16
16
|
manifestId: string | null;
|
|
17
17
|
installId: string | null;
|
|
18
18
|
packageName: string | null;
|
|
19
|
+
packageVersion: string | null;
|
|
19
20
|
installLayout: OpenClawBrainInstallLayout | null;
|
|
20
21
|
additionalInstallCount: number;
|
|
21
22
|
installState: OpenClawBrainHookInstallState;
|
|
@@ -31,9 +32,30 @@ export interface OpenClawBrainHookLoadSummary extends OpenClawBrainHookInspectio
|
|
|
31
32
|
guardSummary: string;
|
|
32
33
|
guardAction: string;
|
|
33
34
|
}
|
|
35
|
+
export interface OpenClawBrainDaemonRuntimeSurfaceInspection {
|
|
36
|
+
configuredRuntimePath: string | null;
|
|
37
|
+
configuredRuntimePackageSpec?: string | null;
|
|
38
|
+
configuredRuntimePackageName?: string | null;
|
|
39
|
+
configuredRuntimePackageVersion?: string | null;
|
|
40
|
+
}
|
|
41
|
+
export interface OpenClawBrainHotfixBoundarySummary {
|
|
42
|
+
boundary: string;
|
|
43
|
+
skew: string;
|
|
44
|
+
daemonPath: string | null;
|
|
45
|
+
hookPath: string | null;
|
|
46
|
+
runtimeGuardPath: string | null;
|
|
47
|
+
daemonPackage: string | null;
|
|
48
|
+
hookPackage: string | null;
|
|
49
|
+
guidance: string;
|
|
50
|
+
detail: string;
|
|
51
|
+
}
|
|
34
52
|
export declare function inspectOpenClawBrainPluginAllowlist(openclawHome: string): {
|
|
35
53
|
state: Exclude<OpenClawBrainPluginAllowlistState, "unverified">;
|
|
36
54
|
detail: string;
|
|
37
55
|
};
|
|
38
56
|
export declare function inspectOpenClawBrainHookStatus(openclawHome: string | null | undefined): OpenClawBrainHookInspection;
|
|
39
57
|
export declare function summarizeOpenClawBrainHookLoad(inspection: OpenClawBrainHookInspection, statusProbeReady: boolean): OpenClawBrainHookLoadSummary;
|
|
58
|
+
export declare function describeOpenClawBrainHotfixBoundary(input: {
|
|
59
|
+
hookInspection: OpenClawBrainHookInspection;
|
|
60
|
+
daemonInspection?: OpenClawBrainDaemonRuntimeSurfaceInspection | null;
|
|
61
|
+
}): OpenClawBrainHotfixBoundarySummary;
|
|
@@ -35,6 +35,37 @@ function shortenPath(fullPath) {
|
|
|
35
35
|
}
|
|
36
36
|
return fullPath;
|
|
37
37
|
}
|
|
38
|
+
function readInstalledHookPackageVersion(packageJsonPath) {
|
|
39
|
+
if (typeof packageJsonPath !== "string" || packageJsonPath.trim().length === 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
44
|
+
return typeof parsed?.version === "string" && parsed.version.trim().length > 0
|
|
45
|
+
? parsed.version.trim()
|
|
46
|
+
: null;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function formatPackageIdentity(packageName, packageVersion, packageSpec = null) {
|
|
53
|
+
if (typeof packageSpec === "string" && packageSpec.trim().length > 0) {
|
|
54
|
+
return packageSpec.trim();
|
|
55
|
+
}
|
|
56
|
+
if (typeof packageName !== "string" || packageName.trim().length === 0) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const normalizedName = packageName.trim();
|
|
60
|
+
return typeof packageVersion === "string" && packageVersion.trim().length > 0
|
|
61
|
+
? `${normalizedName}@${packageVersion.trim()}`
|
|
62
|
+
: normalizedName;
|
|
63
|
+
}
|
|
64
|
+
function normalizeSurfacePath(filePath) {
|
|
65
|
+
return typeof filePath === "string" && filePath.trim().length > 0
|
|
66
|
+
? path.resolve(filePath)
|
|
67
|
+
: null;
|
|
68
|
+
}
|
|
38
69
|
function inspectInstalledHookActivationRoot(loaderEntryPath) {
|
|
39
70
|
let content;
|
|
40
71
|
try {
|
|
@@ -147,6 +178,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
147
178
|
manifestId: null,
|
|
148
179
|
installId: null,
|
|
149
180
|
packageName: null,
|
|
181
|
+
packageVersion: null,
|
|
150
182
|
installLayout: null,
|
|
151
183
|
additionalInstallCount: 0,
|
|
152
184
|
installState: "unverified",
|
|
@@ -173,6 +205,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
173
205
|
manifestId: incompleteInstall?.manifestId ?? null,
|
|
174
206
|
installId: incompleteInstall?.installId ?? null,
|
|
175
207
|
packageName: incompleteInstall?.packageName ?? null,
|
|
208
|
+
packageVersion: readInstalledHookPackageVersion(incompleteInstall?.packageJsonPath ?? null),
|
|
176
209
|
installLayout: incompleteInstall?.installLayout ?? null,
|
|
177
210
|
additionalInstallCount: installedPlugin.additionalInstalls.length,
|
|
178
211
|
installState: "not_installed",
|
|
@@ -189,6 +222,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
189
222
|
const allowlist = inspectOpenClawBrainPluginAllowlist(resolvedHome);
|
|
190
223
|
const layoutLabel = describeOpenClawBrainInstallLayout(selectedInstall.installLayout);
|
|
191
224
|
const identityDetail = describeOpenClawBrainInstallIdentity(selectedInstall);
|
|
225
|
+
const packageVersion = readInstalledHookPackageVersion(selectedInstall.packageJsonPath);
|
|
192
226
|
const activationRootState = inspectInstalledHookActivationRoot(selectedInstall.loaderEntryPath);
|
|
193
227
|
if (allowlist.state === "blocked") {
|
|
194
228
|
return {
|
|
@@ -202,6 +236,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
202
236
|
manifestId: selectedInstall.manifestId,
|
|
203
237
|
installId: selectedInstall.installId,
|
|
204
238
|
packageName: selectedInstall.packageName,
|
|
239
|
+
packageVersion,
|
|
205
240
|
installLayout: selectedInstall.installLayout,
|
|
206
241
|
additionalInstallCount: installedPlugin.additionalInstalls.length,
|
|
207
242
|
installState: "blocked_by_allowlist",
|
|
@@ -224,6 +259,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
224
259
|
manifestId: selectedInstall.manifestId,
|
|
225
260
|
installId: selectedInstall.installId,
|
|
226
261
|
packageName: selectedInstall.packageName,
|
|
262
|
+
packageVersion,
|
|
227
263
|
installLayout: selectedInstall.installLayout,
|
|
228
264
|
additionalInstallCount: installedPlugin.additionalInstalls.length,
|
|
229
265
|
installState: "blocked_by_allowlist",
|
|
@@ -246,6 +282,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
246
282
|
manifestId: selectedInstall.manifestId,
|
|
247
283
|
installId: selectedInstall.installId,
|
|
248
284
|
packageName: selectedInstall.packageName,
|
|
285
|
+
packageVersion,
|
|
249
286
|
installLayout: selectedInstall.installLayout,
|
|
250
287
|
additionalInstallCount: installedPlugin.additionalInstalls.length,
|
|
251
288
|
installState: "installed",
|
|
@@ -266,6 +303,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
|
|
|
266
303
|
manifestId: selectedInstall.manifestId,
|
|
267
304
|
installId: selectedInstall.installId,
|
|
268
305
|
packageName: selectedInstall.packageName,
|
|
306
|
+
packageVersion,
|
|
269
307
|
installLayout: selectedInstall.installLayout,
|
|
270
308
|
additionalInstallCount: installedPlugin.additionalInstalls.length,
|
|
271
309
|
installState: "installed",
|
|
@@ -284,4 +322,83 @@ export function summarizeOpenClawBrainHookLoad(inspection, statusProbeReady) {
|
|
|
284
322
|
: "not_ready"
|
|
285
323
|
};
|
|
286
324
|
}
|
|
325
|
+
export function describeOpenClawBrainHotfixBoundary(input) {
|
|
326
|
+
const hookInspection = input.hookInspection;
|
|
327
|
+
const daemonInspection = input.daemonInspection ?? null;
|
|
328
|
+
const daemonPath = normalizeSurfacePath(daemonInspection?.configuredRuntimePath ?? null);
|
|
329
|
+
const hookPath = normalizeSurfacePath(hookInspection.hookPath);
|
|
330
|
+
const runtimeGuardPath = normalizeSurfacePath(hookInspection.runtimeGuardPath);
|
|
331
|
+
const daemonPackage = formatPackageIdentity(daemonInspection?.configuredRuntimePackageName ?? null, daemonInspection?.configuredRuntimePackageVersion ?? null, daemonInspection?.configuredRuntimePackageSpec ?? null);
|
|
332
|
+
const hookPackage = formatPackageIdentity(hookInspection.packageName, hookInspection.packageVersion);
|
|
333
|
+
if (hookInspection.scope === "activation_root_only") {
|
|
334
|
+
return {
|
|
335
|
+
boundary: "hook_surface_unverified",
|
|
336
|
+
skew: "unverified",
|
|
337
|
+
daemonPath,
|
|
338
|
+
hookPath: null,
|
|
339
|
+
runtimeGuardPath: null,
|
|
340
|
+
daemonPackage,
|
|
341
|
+
hookPackage: null,
|
|
342
|
+
guidance: "Pin --openclaw-home before patching the installed hook/runtime-guard surface; activation-root-only status does not prove which OpenClaw install you would be changing.",
|
|
343
|
+
detail: daemonPath === null
|
|
344
|
+
? "activation-root-only status does not expose the installed hook/runtime-guard surface."
|
|
345
|
+
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but activation-root-only status still does not expose the installed hook/runtime-guard surface.`
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
if (hookPath === null && runtimeGuardPath === null) {
|
|
349
|
+
return {
|
|
350
|
+
boundary: "hook_surface_unverified",
|
|
351
|
+
skew: "unverified",
|
|
352
|
+
daemonPath,
|
|
353
|
+
hookPath: null,
|
|
354
|
+
runtimeGuardPath: null,
|
|
355
|
+
daemonPackage,
|
|
356
|
+
hookPackage,
|
|
357
|
+
guidance: daemonPath === null
|
|
358
|
+
? "Repair or reinstall the installed hook surface before patching OpenClaw load behavior."
|
|
359
|
+
: "Patch the daemon runtime path for background watch fixes, but repair or reinstall the installed hook/runtime-guard surface before patching OpenClaw load behavior.",
|
|
360
|
+
detail: daemonPath === null
|
|
361
|
+
? "no verified daemon runtime path or installed hook/runtime-guard path is visible from this status snapshot."
|
|
362
|
+
: `daemon runtime path ${shortenPath(daemonPath)} is visible, but the installed hook/runtime-guard surface is not yet loadable.`
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
if (daemonPath === null) {
|
|
366
|
+
return {
|
|
367
|
+
boundary: "daemon_surface_only",
|
|
368
|
+
skew: "unverified",
|
|
369
|
+
daemonPath: null,
|
|
370
|
+
hookPath,
|
|
371
|
+
runtimeGuardPath,
|
|
372
|
+
daemonPackage: null,
|
|
373
|
+
hookPackage,
|
|
374
|
+
guidance: "Patch the installed hook/runtime-guard surface for OpenClaw load fixes. No configured daemon runtime path is visible from status.",
|
|
375
|
+
detail: `installed hook loads from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${runtimeGuardPath === null ? "" : ` with runtime-guard ${shortenPath(runtimeGuardPath)}`}, but no configured daemon runtime path is visible.`
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
const samePath = daemonPath === hookPath || daemonPath === runtimeGuardPath;
|
|
379
|
+
const daemonVersion = daemonInspection?.configuredRuntimePackageVersion ?? null;
|
|
380
|
+
const hookVersion = hookInspection.packageVersion ?? null;
|
|
381
|
+
const skew = samePath
|
|
382
|
+
? "same_path"
|
|
383
|
+
: daemonVersion !== null && hookVersion !== null
|
|
384
|
+
? daemonVersion === hookVersion
|
|
385
|
+
? "split_path_same_version"
|
|
386
|
+
: "split_path_version_skew"
|
|
387
|
+
: "split_path_version_unverified";
|
|
388
|
+
return {
|
|
389
|
+
boundary: samePath ? "same_surface" : "split_surfaces",
|
|
390
|
+
skew,
|
|
391
|
+
daemonPath,
|
|
392
|
+
hookPath,
|
|
393
|
+
runtimeGuardPath,
|
|
394
|
+
daemonPackage,
|
|
395
|
+
hookPackage,
|
|
396
|
+
guidance: samePath
|
|
397
|
+
? "Daemon and installed hook paths currently collapse to the same file; verify both surfaces before patching anyway."
|
|
398
|
+
: "Patch the daemon runtime path for background watch/learner fixes. Patch the installed hook/runtime-guard paths for OpenClaw load fixes.",
|
|
399
|
+
detail: samePath
|
|
400
|
+
? `daemon runtime path ${shortenPath(daemonPath)} currently resolves to the same file as the installed OpenClaw hook surface.`
|
|
401
|
+
: `daemon background watch runs from ${shortenPath(daemonPath)}${daemonPackage === null ? "" : ` (${daemonPackage})`}; OpenClaw loads the installed hook from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${hookPackage === null ? "" : ` (${hookPackage})`}${runtimeGuardPath === null ? "" : ` and runtime-guard ${shortenPath(runtimeGuardPath)}`}.`
|
|
402
|
+
};
|
|
403
|
+
}
|
|
287
404
|
//# sourceMappingURL=openclaw-hook-truth.js.map
|
|
@@ -546,7 +546,7 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
546
546
|
};
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
-
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, coverageSnapshot, hardeningSnapshot }) {
|
|
549
|
+
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, surfaceLine, surfacesLine, hotfixLine, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, learningFlowLine, learningHealthLine, coverageSnapshot, hardeningSnapshot }) {
|
|
550
550
|
const passed = [];
|
|
551
551
|
const missing = [];
|
|
552
552
|
const warnings = Array.isArray(verdict.warnings) ? verdict.warnings : [];
|
|
@@ -602,11 +602,33 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
602
602
|
"## Warnings",
|
|
603
603
|
...(warnings.length === 0 ? ["- none"] : warnings.map((item) => `- ${item}`)),
|
|
604
604
|
"",
|
|
605
|
+
"## Hotfix Boundary",
|
|
606
|
+
...(surfaceLine === null
|
|
607
|
+
? ["- hotfix boundary line not reported by detailed status"]
|
|
608
|
+
: [`- ${surfaceLine}`]),
|
|
609
|
+
...(surfacesLine === null
|
|
610
|
+
? ["- hotfix paths line not reported by detailed status"]
|
|
611
|
+
: [`- ${surfacesLine}`]),
|
|
612
|
+
...(hotfixLine === null
|
|
613
|
+
? ["- hotfix guidance line not reported by detailed status"]
|
|
614
|
+
: [`- ${hotfixLine}`]),
|
|
615
|
+
"",
|
|
605
616
|
"## Runtime Guard",
|
|
606
617
|
...(guardLine === null
|
|
607
618
|
? ["- runtime guard line not reported by detailed status"]
|
|
608
619
|
: [`- ${guardLine}`]),
|
|
609
620
|
"",
|
|
621
|
+
"## Learning Flow",
|
|
622
|
+
...(learningPathLine === null
|
|
623
|
+
? ["- learning path line not reported by detailed status"]
|
|
624
|
+
: [`- ${learningPathLine}`]),
|
|
625
|
+
...(learningFlowLine === null
|
|
626
|
+
? ["- learning flow line not reported by detailed status"]
|
|
627
|
+
: [`- ${learningFlowLine}`]),
|
|
628
|
+
...(learningHealthLine === null
|
|
629
|
+
? ["- learning health line not reported by detailed status"]
|
|
630
|
+
: [`- ${learningHealthLine}`]),
|
|
631
|
+
"",
|
|
610
632
|
"## Learning Attribution",
|
|
611
633
|
...(feedbackLine === null
|
|
612
634
|
? ["- feedback line not reported by detailed status"]
|
|
@@ -617,9 +639,6 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
617
639
|
...(attributionCoverageLine === null
|
|
618
640
|
? ["- attribution coverage line not reported by detailed status"]
|
|
619
641
|
: [`- ${attributionCoverageLine}`]),
|
|
620
|
-
...(learningPathLine === null
|
|
621
|
-
? []
|
|
622
|
-
: [`- ${learningPathLine}`]),
|
|
623
642
|
"",
|
|
624
643
|
"## Coverage snapshot",
|
|
625
644
|
`- attached profiles: ${coverageSnapshot.attachedProfileCount}`,
|
|
@@ -916,11 +935,16 @@ export function captureOperatorProofBundle(options) {
|
|
|
916
935
|
const gatewayLogPath = extractGatewayLogPath(gatewayStatusCapture.stdout);
|
|
917
936
|
const activationRoot = extractActivationRoot(statusCapture.stdout, options.activationRoot ?? null);
|
|
918
937
|
const statusSignals = extractStatusSignals(statusCapture.stdout);
|
|
938
|
+
const surfaceLine = extractDetailedStatusLine(statusCapture.stdout, "surface");
|
|
939
|
+
const surfacesLine = extractDetailedStatusLine(statusCapture.stdout, "surfaces");
|
|
940
|
+
const hotfixLine = extractDetailedStatusLine(statusCapture.stdout, "hotfix");
|
|
919
941
|
const attachTruthLine = extractDetailedStatusLine(statusCapture.stdout, "attachTruth");
|
|
920
942
|
const attachedSetLine = extractDetailedStatusLine(statusCapture.stdout, "attachedSet");
|
|
921
943
|
const serveLine = extractDetailedStatusLine(statusCapture.stdout, "serve");
|
|
922
944
|
const routeFnLine = extractDetailedStatusLine(statusCapture.stdout, "routeFn");
|
|
923
945
|
const guardLine = extractDetailedStatusLine(statusCapture.stdout, "guard");
|
|
946
|
+
const learningFlowLine = extractDetailedStatusLine(statusCapture.stdout, "learnFlow");
|
|
947
|
+
const learningHealthLine = extractDetailedStatusLine(statusCapture.stdout, "health");
|
|
924
948
|
const feedbackLine = extractDetailedStatusLine(statusCapture.stdout, "feedback");
|
|
925
949
|
const attributionLine = extractDetailedStatusLine(statusCapture.stdout, "attribution");
|
|
926
950
|
const attributionCoverageLine = extractDetailedStatusLine(statusCapture.stdout, "attrCover");
|
|
@@ -978,7 +1002,12 @@ export function captureOperatorProofBundle(options) {
|
|
|
978
1002
|
},
|
|
979
1003
|
runtimeLoadProofPath,
|
|
980
1004
|
runtimeLoadProofError: runtimeLoadProofSnapshot.error,
|
|
1005
|
+
surfaceLine,
|
|
1006
|
+
surfacesLine,
|
|
1007
|
+
hotfixLine,
|
|
981
1008
|
guardLine,
|
|
1009
|
+
learningFlowLine,
|
|
1010
|
+
learningHealthLine,
|
|
982
1011
|
feedbackLine,
|
|
983
1012
|
attributionLine,
|
|
984
1013
|
attributionCoverageLine,
|
|
@@ -994,7 +1023,12 @@ export function captureOperatorProofBundle(options) {
|
|
|
994
1023
|
statusSignals,
|
|
995
1024
|
breadcrumbs,
|
|
996
1025
|
runtimeLoadProofSnapshot,
|
|
1026
|
+
surfaceLine,
|
|
1027
|
+
surfacesLine,
|
|
1028
|
+
hotfixLine,
|
|
997
1029
|
guardLine,
|
|
1030
|
+
learningFlowLine,
|
|
1031
|
+
learningHealthLine,
|
|
998
1032
|
feedbackLine,
|
|
999
1033
|
attributionLine,
|
|
1000
1034
|
attributionCoverageLine,
|
|
@@ -1015,7 +1049,12 @@ export function captureOperatorProofBundle(options) {
|
|
|
1015
1049
|
hardeningSnapshot,
|
|
1016
1050
|
verdict,
|
|
1017
1051
|
statusSignals,
|
|
1052
|
+
surfaceLine,
|
|
1053
|
+
surfacesLine,
|
|
1054
|
+
hotfixLine,
|
|
1018
1055
|
guardLine,
|
|
1056
|
+
learningFlowLine,
|
|
1057
|
+
learningHealthLine,
|
|
1019
1058
|
feedbackLine,
|
|
1020
1059
|
attributionLine,
|
|
1021
1060
|
attributionCoverageLine,
|
|
@@ -7,10 +7,123 @@ function isSeedAwaitingFirstPromotion(status) {
|
|
|
7
7
|
function normalizeOptionalString(value) {
|
|
8
8
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
9
9
|
}
|
|
10
|
+
function normalizeCount(value) {
|
|
11
|
+
return Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
|
|
12
|
+
}
|
|
10
13
|
function formatOptionalFeedbackLatest(tracedLearning) {
|
|
11
14
|
const latestLabel = normalizeOptionalString(tracedLearning?.feedbackSummary?.latestLabel);
|
|
12
15
|
return latestLabel === null ? "" : ` latest=${latestLabel}`;
|
|
13
16
|
}
|
|
17
|
+
function isLearningSurfaceVisible(tracedLearning) {
|
|
18
|
+
return tracedLearning?.present !== false;
|
|
19
|
+
}
|
|
20
|
+
function hasKnownAttributionCoverage(coverage) {
|
|
21
|
+
return coverage !== null &&
|
|
22
|
+
typeof coverage === "object" &&
|
|
23
|
+
!Array.isArray(coverage) &&
|
|
24
|
+
(coverage.visible === true ||
|
|
25
|
+
coverage.gatingVisible === true ||
|
|
26
|
+
Number.isFinite(coverage.completedWithoutEvaluationCount) ||
|
|
27
|
+
Number.isFinite(coverage.readyCount) ||
|
|
28
|
+
Number.isFinite(coverage.delayedCount) ||
|
|
29
|
+
Number.isFinite(coverage.budgetDeferredCount));
|
|
30
|
+
}
|
|
31
|
+
function readSupervisedTraceCount(tracedLearning) {
|
|
32
|
+
return normalizeCount(tracedLearning?.feedbackSummary?.supervisedTraceCount ?? tracedLearning?.supervisionCount);
|
|
33
|
+
}
|
|
34
|
+
function hasLoadedLearningSignal(tracedLearning) {
|
|
35
|
+
return normalizeOptionalString(tracedLearning?.materializedPackId) !== null ||
|
|
36
|
+
normalizeCount(tracedLearning?.routeTraceCount) > 0 ||
|
|
37
|
+
readSupervisedTraceCount(tracedLearning) > 0 ||
|
|
38
|
+
normalizeCount(tracedLearning?.routerUpdateCount) > 0;
|
|
39
|
+
}
|
|
40
|
+
function summarizeOperatorLearningFlow(tracedLearning) {
|
|
41
|
+
const surfaceVisible = isLearningSurfaceVisible(tracedLearning);
|
|
42
|
+
return {
|
|
43
|
+
harvested: surfaceVisible ? normalizeCount(tracedLearning?.teacherArtifactCount) : null,
|
|
44
|
+
eligible: hasKnownAttributionCoverage(tracedLearning?.attributionCoverage)
|
|
45
|
+
? normalizeCount(tracedLearning?.attributionCoverage?.readyCount)
|
|
46
|
+
: null,
|
|
47
|
+
loaded: surfaceVisible ? hasLoadedLearningSignal(tracedLearning) : null,
|
|
48
|
+
pack: surfaceVisible ? normalizeOptionalString(tracedLearning?.materializedPackId) ?? "none" : null,
|
|
49
|
+
matched: surfaceVisible ? normalizeCount(tracedLearning?.routeTraceCount) : null,
|
|
50
|
+
supervised: surfaceVisible ? readSupervisedTraceCount(tracedLearning) : null,
|
|
51
|
+
updated: surfaceVisible ? normalizeCount(tracedLearning?.routerUpdateCount) : null
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function formatKnownOperatorValue(value) {
|
|
55
|
+
return value === null ? "unknown" : String(value);
|
|
56
|
+
}
|
|
57
|
+
function summarizeOperatorLearningState(flow) {
|
|
58
|
+
if (flow.harvested === null &&
|
|
59
|
+
flow.eligible === null &&
|
|
60
|
+
flow.loaded === null &&
|
|
61
|
+
flow.matched === null &&
|
|
62
|
+
flow.supervised === null &&
|
|
63
|
+
flow.updated === null) {
|
|
64
|
+
return {
|
|
65
|
+
state: "learning-unknown",
|
|
66
|
+
detail: "learning stage truth is not visible in the current status surface"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (flow.harvested > 0 &&
|
|
70
|
+
flow.eligible !== null &&
|
|
71
|
+
flow.eligible > 0 &&
|
|
72
|
+
flow.matched === 0 &&
|
|
73
|
+
flow.supervised === 0 &&
|
|
74
|
+
flow.updated === 0) {
|
|
75
|
+
return {
|
|
76
|
+
state: "stalled-learning",
|
|
77
|
+
detail: "harvested artifacts and eligible feedback are visible, but no matched routes, supervision, or router updates are visible"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if ((flow.matched ?? 0) > 0 || (flow.supervised ?? 0) > 0 || (flow.updated ?? 0) > 0) {
|
|
81
|
+
return {
|
|
82
|
+
state: "progress-visible",
|
|
83
|
+
detail: `matched=${flow.matched ?? 0} supervised=${flow.supervised ?? 0} updated=${flow.updated ?? 0}`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (flow.harvested > 0 && flow.eligible === 0) {
|
|
87
|
+
return {
|
|
88
|
+
state: "harvested-not-yet-eligible",
|
|
89
|
+
detail: "teacher artifacts are visible, but no eligible feedback is queued yet"
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (flow.harvested > 0 && flow.eligible === null) {
|
|
93
|
+
return {
|
|
94
|
+
state: "harvested-eligibility-unknown",
|
|
95
|
+
detail: "teacher artifacts are visible, but eligible feedback truth is not surfaced yet"
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (flow.harvested === 0 && flow.eligible !== null && flow.eligible > 0) {
|
|
99
|
+
return {
|
|
100
|
+
state: "eligible-without-harvest",
|
|
101
|
+
detail: "eligible feedback is visible without harvested teacher artifacts"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (flow.harvested === 0 && flow.eligible === 0) {
|
|
105
|
+
return {
|
|
106
|
+
state: "idle-no-eligible-feedback",
|
|
107
|
+
detail: "no harvested teacher artifacts or eligible feedback are visible"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
state: "learning-unknown",
|
|
112
|
+
detail: "learning stage truth is incomplete"
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function summarizeOperatorDaemonState(teacher) {
|
|
116
|
+
if (teacher?.enabled !== true) {
|
|
117
|
+
return "daemon-disabled";
|
|
118
|
+
}
|
|
119
|
+
if (teacher?.healthy === true) {
|
|
120
|
+
return "healthy-daemon";
|
|
121
|
+
}
|
|
122
|
+
if (teacher?.healthy === false) {
|
|
123
|
+
return "degraded-daemon";
|
|
124
|
+
}
|
|
125
|
+
return "daemon-unknown";
|
|
126
|
+
}
|
|
14
127
|
function formatOperatorFeedbackSummary({ tracedLearning }) {
|
|
15
128
|
const routeTraceCount = tracedLearning?.feedbackSummary?.routeTraceCount ?? tracedLearning?.routeTraceCount ?? 0;
|
|
16
129
|
const supervisedTraceCount = tracedLearning?.feedbackSummary?.supervisedTraceCount ?? tracedLearning?.supervisionCount ?? 0;
|
|
@@ -78,4 +191,21 @@ export function formatOperatorLearningPathSummary({ status, learningPath, traced
|
|
|
78
191
|
...detailParts
|
|
79
192
|
].join(" ");
|
|
80
193
|
}
|
|
194
|
+
export function formatOperatorLearningFlowSummary({ tracedLearning }) {
|
|
195
|
+
const flow = summarizeOperatorLearningFlow(tracedLearning);
|
|
196
|
+
return [
|
|
197
|
+
`harvested=${formatKnownOperatorValue(flow.harvested)}`,
|
|
198
|
+
`eligible=${formatKnownOperatorValue(flow.eligible)}`,
|
|
199
|
+
`loaded=${flow.loaded === null ? "unknown" : flow.loaded ? "yes" : "no"}`,
|
|
200
|
+
`pack=${flow.pack ?? "unknown"}`,
|
|
201
|
+
`matched=${formatKnownOperatorValue(flow.matched)}`,
|
|
202
|
+
`supervised=${formatKnownOperatorValue(flow.supervised)}`,
|
|
203
|
+
`updated=${formatKnownOperatorValue(flow.updated)}`
|
|
204
|
+
].join(" ");
|
|
205
|
+
}
|
|
206
|
+
export function formatOperatorLearningHealthSummary({ tracedLearning, teacher }) {
|
|
207
|
+
const flow = summarizeOperatorLearningFlow(tracedLearning);
|
|
208
|
+
const learning = summarizeOperatorLearningState(flow);
|
|
209
|
+
return `daemon=${summarizeOperatorDaemonState(teacher)} learning=${learning.state} detail=${learning.detail}`;
|
|
210
|
+
}
|
|
81
211
|
export { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type NormalizedEventExportV1, type TeacherSupervisionArtifactV1 } from "@openclawbrain/contracts";
|
|
2
|
-
import type { LearningSpineServeRouteDecisionLogEntryV1 } from "
|
|
2
|
+
import type { LearningSpineServeRouteDecisionLogEntryV1 } from "./local-learner.js";
|
|
3
3
|
export interface TeacherLabelerRunInputV1 {
|
|
4
4
|
normalizedEventExport: NormalizedEventExportV1;
|
|
5
5
|
observedAt: string;
|
|
@@ -141,11 +141,14 @@ function buildPrompt(candidates, config) {
|
|
|
141
141
|
payload
|
|
142
142
|
].join("\n");
|
|
143
143
|
}
|
|
144
|
+
function isTeacherLabelerCandidateInteraction(interaction) {
|
|
145
|
+
return interaction.kind === "memory_compiled" || interaction.kind === "message_delivered";
|
|
146
|
+
}
|
|
144
147
|
function collectCandidates(input, config) {
|
|
145
148
|
const decisions = [...(input.serveTimeDecisions ?? [])].sort((left, right) => Date.parse(right.recordedAt) - Date.parse(left.recordedAt));
|
|
146
149
|
const matchServeTimeDecision = createServeTimeDecisionMatcher(decisions);
|
|
147
150
|
return input.normalizedEventExport.interactionEvents
|
|
148
|
-
.filter((interaction) => interaction
|
|
151
|
+
.filter((interaction) => isTeacherLabelerCandidateInteraction(interaction))
|
|
149
152
|
.sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))
|
|
150
153
|
.map((interaction) => {
|
|
151
154
|
const decision = matchServeTimeDecision(interaction);
|
package/package.json
CHANGED