@ouro.bot/cli 0.1.0-alpha.767 → 0.1.0-alpha.769
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.json +16 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +1 -1
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/arc/cares.js +91 -9
- package/dist/heart/core.js +50 -5
- package/dist/heart/daemon/daemon.js +47 -0
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +49 -7
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +4 -1
- package/dist/heart/external-events/router.js +88 -4
- package/dist/heart/private-runtime/decision-renderer.js +2 -0
- package/dist/heart/private-runtime/ledger.js +4 -1
- package/dist/heart/private-runtime/policy.js +22 -8
- package/dist/heart/start-of-turn-packet.js +7 -3
- package/dist/repertoire/tools-continuity.js +23 -28
- package/dist/senses/pipeline.js +11 -4
- package/dist/senses/sanctuary-full-visibility-contract.js +199 -9
- package/dist/senses/sanctuary-storage-optimization-contract.js +2 -3
- package/dist/senses/telegram.js +34 -11
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -45,6 +45,8 @@ exports.claimExternalEvent = claimExternalEvent;
|
|
|
45
45
|
exports.renewExternalEventClaim = renewExternalEventClaim;
|
|
46
46
|
exports.commitExternalEventDisposition = commitExternalEventDisposition;
|
|
47
47
|
exports.failExternalEventAttempt = failExternalEventAttempt;
|
|
48
|
+
exports.externalEventRecoveryFailure = externalEventRecoveryFailure;
|
|
49
|
+
exports.reviveExternalEventAfterRecovery = reviveExternalEventAfterRecovery;
|
|
48
50
|
exports.reconcileExternalEvent = reconcileExternalEvent;
|
|
49
51
|
exports.advanceExternalEventFromAwait = advanceExternalEventFromAwait;
|
|
50
52
|
exports.advanceExternalEventsFromAwait = advanceExternalEventsFromAwait;
|
|
@@ -305,11 +307,19 @@ function isRecord(value) {
|
|
|
305
307
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
306
308
|
return false;
|
|
307
309
|
const candidate = value;
|
|
310
|
+
const failure = candidate.failureProvenance;
|
|
311
|
+
const grant = candidate.recoveryGrant;
|
|
312
|
+
const validFailure = failure === undefined || (failure !== null && typeof failure === "object"
|
|
313
|
+
&& (failure.class === "provider_lane_unavailable" || failure.class === "managed_runtime_unavailable") && canonicalIso(failure.failedAt));
|
|
314
|
+
const validGrant = grant === undefined || (grant !== null && typeof grant === "object"
|
|
315
|
+
&& Number.isSafeInteger(grant.generation) && grant.generation === candidate.generation && canonicalIso(grant.consumedAt));
|
|
308
316
|
return candidate.schemaVersion === 2
|
|
309
317
|
&& typeof candidate.recordPath === "string"
|
|
310
318
|
&& Number.isSafeInteger(candidate.version)
|
|
311
319
|
&& Number.isSafeInteger(candidate.generation)
|
|
312
|
-
&& typeof candidate.observationRevision === "string"
|
|
320
|
+
&& typeof candidate.observationRevision === "string"
|
|
321
|
+
&& validFailure
|
|
322
|
+
&& validGrant;
|
|
313
323
|
}
|
|
314
324
|
function readExternalEventRecord(recordPath) {
|
|
315
325
|
const parsed = JSON.parse(fs.readFileSync(recordPath, "utf8"));
|
|
@@ -359,6 +369,8 @@ function listExternalEventStatus(root) {
|
|
|
359
369
|
careId: record.disposition?.careId ?? null,
|
|
360
370
|
awaitId: record.disposition?.awaitId ?? null,
|
|
361
371
|
lastError: record.lastError,
|
|
372
|
+
failureProvenance: record.failureProvenance ?? null,
|
|
373
|
+
recoveryGrant: record.recoveryGrant ?? null,
|
|
362
374
|
nextAttemptAt: record.nextAttemptAt,
|
|
363
375
|
claimOwner: record.claimOwner,
|
|
364
376
|
claimExpiresAt: record.claimExpiresAt,
|
|
@@ -390,6 +402,8 @@ function listExternalEventStatus(root) {
|
|
|
390
402
|
careId: null,
|
|
391
403
|
awaitId: null,
|
|
392
404
|
lastError: `invalid receipt: ${error instanceof Error ? error.message : /* v8 ignore next -- filesystem and JSON parsers throw Error objects @preserve */ String(error)}`,
|
|
405
|
+
failureProvenance: null,
|
|
406
|
+
recoveryGrant: null,
|
|
393
407
|
nextAttemptAt: null,
|
|
394
408
|
claimOwner: null,
|
|
395
409
|
claimExpiresAt: null,
|
|
@@ -533,6 +547,8 @@ function recordExternalEventInternal(input, options = {}) {
|
|
|
533
547
|
claimExpiresAt: shouldWake || quietInitialReceipt ? null : existing.claimExpiresAt,
|
|
534
548
|
nextAttemptAt: shouldWake || quietInitialReceipt ? null : existing.nextAttemptAt,
|
|
535
549
|
lastError: shouldWake || quietInitialReceipt ? null : existing.lastError,
|
|
550
|
+
...(!shouldWake && !quietInitialReceipt && existing?.failureProvenance ? { failureProvenance: existing.failureProvenance } : {}),
|
|
551
|
+
...(!shouldWake && !quietInitialReceipt && existing?.recoveryGrant ? { recoveryGrant: existing.recoveryGrant } : {}),
|
|
536
552
|
disposition: shouldWake || quietInitialReceipt ? null : existing.disposition,
|
|
537
553
|
pendingObservation: shouldWake || quietInitialReceipt ? null : existing.pendingObservation,
|
|
538
554
|
dispatchEnabled: options.dispatchEnabled ?? existing?.dispatchEnabled ?? true,
|
|
@@ -1032,12 +1048,13 @@ function commitExternalEventDisposition(recordPath, input) {
|
|
|
1032
1048
|
disposition: wakePending ? null : input.disposition,
|
|
1033
1049
|
pendingObservation: null,
|
|
1034
1050
|
pendingPrivilegedProtectiveAction: undefined,
|
|
1051
|
+
...(wakePending ? { failureProvenance: undefined, recoveryGrant: undefined } : {}),
|
|
1035
1052
|
shouldWake: wakePending,
|
|
1036
1053
|
}, now);
|
|
1037
1054
|
});
|
|
1038
1055
|
}
|
|
1039
|
-
function retryState(record, now, maxAttempts, baseDelayMs, error) {
|
|
1040
|
-
const dead = record.attemptCount >= maxAttempts;
|
|
1056
|
+
function retryState(record, now, maxAttempts, baseDelayMs, error, failureClass) {
|
|
1057
|
+
const dead = record.recoveryGrant?.generation === record.generation || record.attemptCount >= maxAttempts;
|
|
1041
1058
|
return {
|
|
1042
1059
|
...record,
|
|
1043
1060
|
executionState: dead ? "dead_letter" : "retry_wait",
|
|
@@ -1045,6 +1062,7 @@ function retryState(record, now, maxAttempts, baseDelayMs, error) {
|
|
|
1045
1062
|
claimExpiresAt: null,
|
|
1046
1063
|
nextAttemptAt: dead ? null : new Date(Date.parse(now) + baseDelayMs * 2 ** Math.max(0, record.attemptCount - 1)).toISOString(),
|
|
1047
1064
|
lastError: error.slice(0, 1_000),
|
|
1065
|
+
...(dead && failureClass && !record.failureProvenance ? { failureProvenance: { class: failureClass, failedAt: now } } : {}),
|
|
1048
1066
|
shouldWake: false,
|
|
1049
1067
|
};
|
|
1050
1068
|
}
|
|
@@ -1055,9 +1073,73 @@ function failExternalEventAttempt(recordPath, input) {
|
|
|
1055
1073
|
const now = input.now?.() ?? new Date().toISOString();
|
|
1056
1074
|
const maxAttempts = input.maxAttempts ?? 5;
|
|
1057
1075
|
const baseDelayMs = input.baseDelayMs ?? 1_000;
|
|
1076
|
+
if (input.failureClass !== undefined && input.failureClass !== "provider_lane_unavailable" && input.failureClass !== "managed_runtime_unavailable")
|
|
1077
|
+
throw new Error("External event failure class is invalid");
|
|
1058
1078
|
if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1 || !Number.isSafeInteger(baseDelayMs) || baseDelayMs < 1)
|
|
1059
1079
|
throw new Error("External event retry policy is invalid");
|
|
1060
|
-
return commitMutation(recordPath, retryState(record, now, maxAttempts, baseDelayMs, input.error), now);
|
|
1080
|
+
return commitMutation(recordPath, retryState(record, now, maxAttempts, baseDelayMs, input.error, input.failureClass), now);
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
function exactLegacyProviderFailure(record) {
|
|
1084
|
+
const escapedAgent = record.agent.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
1085
|
+
const canonical = new RegExp(`^private-runtime wake denied for ${escapedAgent}: provider lane resolution failed$`, "u");
|
|
1086
|
+
return record.lastError && canonical.test(record.lastError)
|
|
1087
|
+
? { class: "provider_lane_unavailable", failedAt: record.updatedAt }
|
|
1088
|
+
: null;
|
|
1089
|
+
}
|
|
1090
|
+
function externalEventRecoveryFailure(record) {
|
|
1091
|
+
return record.failureProvenance ?? exactLegacyProviderFailure(record);
|
|
1092
|
+
}
|
|
1093
|
+
function recoveryIneligible(record, reason) {
|
|
1094
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1095
|
+
component: "daemon",
|
|
1096
|
+
event: "daemon.external_event_recovery_ineligible",
|
|
1097
|
+
message: "external event dead-letter recovery was ineligible or exhausted",
|
|
1098
|
+
meta: { agent: record.agent, source: record.source, eventId: record.eventId, generation: record.generation, reason },
|
|
1099
|
+
});
|
|
1100
|
+
return { revived: false, reason, record };
|
|
1101
|
+
}
|
|
1102
|
+
function reviveExternalEventAfterRecovery(recordPath, input) {
|
|
1103
|
+
return withRecordLock(recordPath, () => {
|
|
1104
|
+
const record = readExternalEventRecord(recordPath);
|
|
1105
|
+
assertCas(record, input);
|
|
1106
|
+
if (input.evidence.class !== "provider_lane_unavailable" && input.evidence.class !== "managed_runtime_unavailable")
|
|
1107
|
+
throw new Error("External event recovery evidence class is invalid");
|
|
1108
|
+
if (!canonicalIso(input.evidence.observedAt))
|
|
1109
|
+
throw new Error("External event recovery evidence time is invalid");
|
|
1110
|
+
if (record.executionState !== "dead_letter")
|
|
1111
|
+
return recoveryIneligible(record, "not_dead_letter");
|
|
1112
|
+
if (record.dispatchEnabled === false)
|
|
1113
|
+
return recoveryIneligible(record, "dispatch_disabled");
|
|
1114
|
+
if (record.recoveryGrant?.generation === record.generation)
|
|
1115
|
+
return recoveryIneligible(record, "grant_consumed");
|
|
1116
|
+
const failure = externalEventRecoveryFailure(record);
|
|
1117
|
+
if (!failure)
|
|
1118
|
+
return recoveryIneligible(record, "ineligible_failure");
|
|
1119
|
+
if (failure.class !== input.evidence.class)
|
|
1120
|
+
return recoveryIneligible(record, "evidence_mismatch");
|
|
1121
|
+
if (Date.parse(input.evidence.observedAt) <= Date.parse(failure.failedAt))
|
|
1122
|
+
return recoveryIneligible(record, "stale_evidence");
|
|
1123
|
+
const now = input.now?.() ?? new Date().toISOString();
|
|
1124
|
+
if (!canonicalIso(now))
|
|
1125
|
+
throw new Error("External event recovery grant consumed time is invalid");
|
|
1126
|
+
const revived = commitMutation(recordPath, {
|
|
1127
|
+
...record,
|
|
1128
|
+
executionState: "queued",
|
|
1129
|
+
claimOwner: null,
|
|
1130
|
+
claimExpiresAt: null,
|
|
1131
|
+
nextAttemptAt: null,
|
|
1132
|
+
shouldWake: true,
|
|
1133
|
+
failureProvenance: failure,
|
|
1134
|
+
recoveryGrant: { generation: record.generation, consumedAt: now },
|
|
1135
|
+
}, now);
|
|
1136
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1137
|
+
component: "daemon",
|
|
1138
|
+
event: "daemon.external_event_requeued",
|
|
1139
|
+
message: "requeued external event after infrastructure recovery",
|
|
1140
|
+
meta: { agent: revived.agent, source: revived.source, eventId: revived.eventId, generation: revived.generation, failureClass: failure.class },
|
|
1141
|
+
});
|
|
1142
|
+
return { revived: true, record: revived };
|
|
1061
1143
|
});
|
|
1062
1144
|
}
|
|
1063
1145
|
function reconcileExternalEvent(recordPath, options = {}) {
|
|
@@ -1084,6 +1166,8 @@ function advanceExternalEventFromAwait(recordPath, input) {
|
|
|
1084
1166
|
generation: record.generation + 1,
|
|
1085
1167
|
executionState: "queued",
|
|
1086
1168
|
attemptCount: 0,
|
|
1169
|
+
failureProvenance: undefined,
|
|
1170
|
+
recoveryGrant: undefined,
|
|
1087
1171
|
disposition: null,
|
|
1088
1172
|
shouldWake: true,
|
|
1089
1173
|
}, now);
|
|
@@ -57,6 +57,7 @@ function sanitizePrivateDecision(row, ledgerPath) {
|
|
|
57
57
|
? row
|
|
58
58
|
: {};
|
|
59
59
|
const deniedReason = stringField(record.deniedReason);
|
|
60
|
+
const denialCode = record.denialCode === "provider_lane_unavailable" ? record.denialCode : undefined;
|
|
60
61
|
const duplicateOf = stringField(record.duplicateOf);
|
|
61
62
|
const error = stringField(record.error);
|
|
62
63
|
return {
|
|
@@ -76,6 +77,7 @@ function sanitizePrivateDecision(row, ledgerPath) {
|
|
|
76
77
|
decidedAt: stringField(record.decidedAt),
|
|
77
78
|
ledgerLocator: ledgerLocatorField(record.ledgerLocator, ledgerPath),
|
|
78
79
|
...(deniedReason ? { deniedReason } : {}),
|
|
80
|
+
...(denialCode ? { denialCode } : {}),
|
|
79
81
|
...(duplicateOf ? { duplicateOf } : {}),
|
|
80
82
|
...(error ? { error } : {}),
|
|
81
83
|
};
|
|
@@ -137,6 +137,7 @@ function mismatchDecision(candidate, existing) {
|
|
|
137
137
|
result: "deny",
|
|
138
138
|
executable: false,
|
|
139
139
|
deniedReason: "idempotency-key fingerprint mismatch",
|
|
140
|
+
denialCode: undefined,
|
|
140
141
|
duplicateOf: existing.receiptId,
|
|
141
142
|
};
|
|
142
143
|
}
|
|
@@ -159,6 +160,7 @@ function ledgerWriteFailedDecision(candidate, ledgerPath, error) {
|
|
|
159
160
|
result: "deny",
|
|
160
161
|
executable: false,
|
|
161
162
|
deniedReason: "ledger write failed",
|
|
163
|
+
denialCode: undefined,
|
|
162
164
|
ledgerLocator: { path: ledgerPath },
|
|
163
165
|
error: String(error),
|
|
164
166
|
};
|
|
@@ -194,7 +196,8 @@ function recordPrivateTurnDecision(decision, deps = {}) {
|
|
|
194
196
|
if (latestSameFingerprint
|
|
195
197
|
&& latestSameFingerprint.result === candidate.result
|
|
196
198
|
&& latestSameFingerprint.executable === candidate.executable
|
|
197
|
-
&& latestSameFingerprint.deniedReason === candidate.deniedReason
|
|
199
|
+
&& latestSameFingerprint.deniedReason === candidate.deniedReason
|
|
200
|
+
&& latestSameFingerprint.denialCode === candidate.denialCode) {
|
|
198
201
|
return latestSameFingerprint;
|
|
199
202
|
}
|
|
200
203
|
if (priorExecutable && !candidate.executable) {
|
|
@@ -167,12 +167,6 @@ async function requestPrivateTurnDecision(request, deps = {}) {
|
|
|
167
167
|
let evaluation;
|
|
168
168
|
try {
|
|
169
169
|
providerLane = await resolveProviderLaneMetadata(normalizedRequest, deps);
|
|
170
|
-
requestFingerprint = createPrivateTurnRequestFingerprint(normalizedRequest, providerLane);
|
|
171
|
-
evaluation = await evaluatePolicy(normalizedRequest, {
|
|
172
|
-
requestFingerprint,
|
|
173
|
-
idempotencyKey,
|
|
174
|
-
providerLane,
|
|
175
|
-
}, deps);
|
|
176
170
|
}
|
|
177
171
|
catch (error) {
|
|
178
172
|
providerLane = {
|
|
@@ -181,13 +175,30 @@ async function requestPrivateTurnDecision(request, deps = {}) {
|
|
|
181
175
|
model: "-",
|
|
182
176
|
source: "agent.json",
|
|
183
177
|
};
|
|
184
|
-
requestFingerprint = createPrivateTurnRequestFingerprint(normalizedRequest, providerLane);
|
|
185
178
|
evaluation = {
|
|
186
179
|
result: "deny",
|
|
187
180
|
reason: error instanceof Error ? error.message : String(error),
|
|
188
181
|
deniedReason: "provider lane resolution failed",
|
|
182
|
+
denialCode: "provider_lane_unavailable",
|
|
189
183
|
};
|
|
190
184
|
}
|
|
185
|
+
requestFingerprint = createPrivateTurnRequestFingerprint(normalizedRequest, providerLane);
|
|
186
|
+
if (evaluation === undefined) {
|
|
187
|
+
try {
|
|
188
|
+
evaluation = await evaluatePolicy(normalizedRequest, {
|
|
189
|
+
requestFingerprint,
|
|
190
|
+
idempotencyKey,
|
|
191
|
+
providerLane,
|
|
192
|
+
}, deps);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
evaluation = {
|
|
196
|
+
result: "deny",
|
|
197
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
198
|
+
deniedReason: "private runtime policy evaluation failed",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
191
202
|
const result = evaluation.result;
|
|
192
203
|
emitPolicyEvaluated(deps, { request: normalizedRequest, result, requestFingerprint, idempotencyKey });
|
|
193
204
|
const reason = evaluation.reason ?? normalizedRequest.reason;
|
|
@@ -208,7 +219,10 @@ async function requestPrivateTurnDecision(request, deps = {}) {
|
|
|
208
219
|
executable: result === "allow",
|
|
209
220
|
decidedAt: nowIso(deps),
|
|
210
221
|
ledgerLocator: { path: deps.ledgerPath ?? "" },
|
|
211
|
-
...(result === "deny" ? {
|
|
222
|
+
...(result === "deny" ? {
|
|
223
|
+
deniedReason: evaluation.deniedReason ?? reason,
|
|
224
|
+
...(evaluation.denialCode ? { denialCode: evaluation.denialCode } : {}),
|
|
225
|
+
} : {}),
|
|
212
226
|
};
|
|
213
227
|
return (0, ledger_1.recordPrivateTurnDecision)(decision, deps);
|
|
214
228
|
}
|
|
@@ -42,6 +42,7 @@ const path = __importStar(require("path"));
|
|
|
42
42
|
const runtime_1 = require("../nerves/runtime");
|
|
43
43
|
const bundle_state_1 = require("./bundle-state");
|
|
44
44
|
const tempo_1 = require("./tempo");
|
|
45
|
+
const cares_1 = require("../arc/cares");
|
|
45
46
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
46
47
|
const context_loss_sentinel_1 = require("./context-loss-sentinel");
|
|
47
48
|
const orientation_frame_1 = require("./orientation-frame");
|
|
@@ -82,11 +83,14 @@ function buildObligationsSection(obligations) {
|
|
|
82
83
|
})
|
|
83
84
|
.join("\n");
|
|
84
85
|
}
|
|
85
|
-
function buildCaresSection(cares) {
|
|
86
|
+
function buildCaresSection(cares, now) {
|
|
86
87
|
if (cares.length === 0)
|
|
87
88
|
return "";
|
|
88
89
|
return cares
|
|
89
|
-
.map((
|
|
90
|
+
.map((care) => {
|
|
91
|
+
const c = (0, cares_1.projectCareEvidence)(care, now);
|
|
92
|
+
if ("recheckRequired" in c)
|
|
93
|
+
return `- system care [${c.salience}] evidence stale; recheck required`;
|
|
90
94
|
const parts = [`- ${c.label}`];
|
|
91
95
|
if (c.salience !== "low") {
|
|
92
96
|
parts.push(` [${c.salience}]`);
|
|
@@ -192,7 +196,7 @@ function buildStartOfTurnPacket(view, opts) {
|
|
|
192
196
|
const packet = {
|
|
193
197
|
plotLine: buildPlotLine(view.recentEpisodes, tempo),
|
|
194
198
|
obligations: buildObligationsSection(effectiveObligations),
|
|
195
|
-
cares: buildCaresSection(view.activeCares),
|
|
199
|
+
cares: buildCaresSection(view.activeCares, opts?.careEvidenceNow ?? Date.now()),
|
|
196
200
|
presence: buildPresenceSection(view.peerPresence),
|
|
197
201
|
arcResume: opts?.flightRecorderResume ? (0, flight_recorder_1.formatFlightRecorderResume)(opts.flightRecorderResume) : undefined,
|
|
198
202
|
recoverySentinel: opts?.recoverySentinel,
|
|
@@ -45,24 +45,6 @@ const presence_1 = require("../arc/presence");
|
|
|
45
45
|
const intentions_1 = require("../arc/intentions");
|
|
46
46
|
const steward_policy_1 = require("../heart/steward-policy");
|
|
47
47
|
const await_parser_1 = require("../heart/awaiting/await-parser");
|
|
48
|
-
function presentCare(care) {
|
|
49
|
-
const staleAt = care.nextCheckAt ? Date.parse(care.nextCheckAt) : Number.NaN;
|
|
50
|
-
if (care.kind !== "system" || !["active", "watching"].includes(care.status) || care.nextCheckAt === null)
|
|
51
|
-
return care;
|
|
52
|
-
if (Number.isFinite(staleAt) && staleAt >= Date.now())
|
|
53
|
-
return care;
|
|
54
|
-
return {
|
|
55
|
-
id: care.id,
|
|
56
|
-
kind: care.kind,
|
|
57
|
-
status: care.status,
|
|
58
|
-
salience: care.salience,
|
|
59
|
-
steward: care.steward,
|
|
60
|
-
evidenceStatus: "stale",
|
|
61
|
-
recheckRequired: true,
|
|
62
|
-
staleAt: care.nextCheckAt,
|
|
63
|
-
lastAssessedAt: care.updatedAt,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
48
|
exports.continuityToolDefinitions = [
|
|
67
49
|
// ── Continuity tools ──────────────────────────────────────────────
|
|
68
50
|
{
|
|
@@ -326,7 +308,8 @@ exports.continuityToolDefinitions = [
|
|
|
326
308
|
},
|
|
327
309
|
handler: (a) => {
|
|
328
310
|
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
329
|
-
const
|
|
311
|
+
const now = Date.now();
|
|
312
|
+
const cares = (a.status === "all" ? (0, cares_1.readCares)(agentRoot) : (0, cares_1.readActiveCares)(agentRoot)).map((care) => (0, cares_1.projectCareEvidence)(care, now));
|
|
330
313
|
(0, runtime_1.emitNervesEvent)({ component: "repertoire", event: "repertoire.query_cares", message: `queried ${cares.length} cares`, meta: { count: cares.length } });
|
|
331
314
|
return JSON.stringify(cares, null, 2);
|
|
332
315
|
},
|
|
@@ -346,6 +329,7 @@ exports.continuityToolDefinitions = [
|
|
|
346
329
|
why: { type: "string", description: "Why this matters" },
|
|
347
330
|
salience: { type: "string", description: "low, medium, high, or critical" },
|
|
348
331
|
kind: { type: "string", description: "person, agent, project, mission, or system" },
|
|
332
|
+
status: { type: "string", enum: ["active", "watching", "resolved", "dormant"], description: "active, watching, resolved, or dormant" },
|
|
349
333
|
stewardship: { type: "string", description: "mine, shared, or delegated" },
|
|
350
334
|
source: { type: "string", description: "Machine evidence source for an incident binding" },
|
|
351
335
|
incidentKey: { type: "string", description: "Stable incident key within the source" },
|
|
@@ -367,7 +351,7 @@ exports.continuityToolDefinitions = [
|
|
|
367
351
|
label: a.label ?? "untitled",
|
|
368
352
|
why: a.why ?? "",
|
|
369
353
|
kind: a.kind ?? "project",
|
|
370
|
-
status: "active",
|
|
354
|
+
status: a.status ?? "active",
|
|
371
355
|
salience: a.salience ?? "medium",
|
|
372
356
|
steward: a.stewardship ?? "mine",
|
|
373
357
|
relatedFriendIds: [],
|
|
@@ -412,22 +396,33 @@ exports.continuityToolDefinitions = [
|
|
|
412
396
|
source: a.source,
|
|
413
397
|
incidentKey: a.incidentKey,
|
|
414
398
|
expectedUpdatedAt: a.expectedUpdatedAt,
|
|
399
|
+
...((a.label !== undefined || a.why !== undefined || a.currentRisk !== undefined || a.nextCheckAt !== undefined) ? {
|
|
400
|
+
display: {
|
|
401
|
+
...(a.label !== undefined ? { label: String(a.label) } : {}),
|
|
402
|
+
...(a.why !== undefined ? { why: String(a.why) } : {}),
|
|
403
|
+
...(a.currentRisk !== undefined ? { currentRisk: a.currentRisk ? String(a.currentRisk) : null } : {}),
|
|
404
|
+
...(a.nextCheckAt !== undefined ? { nextCheckAt: a.nextCheckAt ? String(a.nextCheckAt) : null } : {}),
|
|
405
|
+
},
|
|
406
|
+
} : {}),
|
|
415
407
|
});
|
|
416
408
|
}
|
|
417
409
|
else if (a.action === "upsert_incident") {
|
|
418
410
|
result = (0, cares_1.upsertCareForIncident)(agentRoot, {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
411
|
+
...(a.id ? { id: String(a.id) } : {}),
|
|
412
|
+
...(!a.id ? {
|
|
413
|
+
label: a.label ?? "untitled", why: a.why ?? "", kind: a.kind ?? "system", status: a.status ?? "active",
|
|
414
|
+
salience: a.salience ?? "medium", steward: a.stewardship ?? "mine",
|
|
415
|
+
} : {
|
|
416
|
+
...(a.label !== undefined ? { label: String(a.label) } : {}), ...(a.why !== undefined ? { why: String(a.why) } : {}),
|
|
417
|
+
...(a.kind !== undefined ? { kind: a.kind } : {}), ...(a.status !== undefined ? { status: a.status } : {}),
|
|
418
|
+
...(a.salience !== undefined ? { salience: a.salience } : {}), ...(a.stewardship !== undefined ? { steward: a.stewardship } : {}),
|
|
419
|
+
}),
|
|
425
420
|
relatedFriendIds: [],
|
|
426
421
|
relatedAgentIds: [],
|
|
427
422
|
relatedObligationIds: [],
|
|
428
423
|
relatedEpisodeIds: [],
|
|
429
|
-
currentRisk: a.currentRisk ? String(a.currentRisk) : null,
|
|
430
|
-
nextCheckAt: a.nextCheckAt ? String(a.nextCheckAt) : null,
|
|
424
|
+
...(!a.id || a.currentRisk !== undefined ? { currentRisk: a.currentRisk ? String(a.currentRisk) : null } : {}),
|
|
425
|
+
...(!a.id || a.nextCheckAt !== undefined ? { nextCheckAt: a.nextCheckAt ? String(a.nextCheckAt) : null } : {}),
|
|
431
426
|
...(a.expectedUpdatedAt ? { expectedUpdatedAt: String(a.expectedUpdatedAt) } : {}),
|
|
432
427
|
incident: {
|
|
433
428
|
source: a.source,
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -72,6 +72,7 @@ const provider_visibility_1 = require("../heart/provider-visibility");
|
|
|
72
72
|
const orientation_frame_1 = require("../heart/orientation-frame");
|
|
73
73
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
74
74
|
const context_loss_sentinel_1 = require("../heart/context-loss-sentinel");
|
|
75
|
+
const cares_1 = require("../arc/cares");
|
|
75
76
|
const VOICE_PENDING_MAX_AGE_MS = 15 * 60 * 1_000;
|
|
76
77
|
function pendingExpirationReason(channel, message, now) {
|
|
77
78
|
/* v8 ignore start -- pending expiry edge permutations are covered by the stale voice queue tests; this helper keeps defensive non-voice fallbacks @preserve */
|
|
@@ -809,11 +810,14 @@ async function handleInboundTurn(input) {
|
|
|
809
810
|
: undefined);
|
|
810
811
|
// Step 4b: Continuity pipeline — derive tempo, build start-of-turn packet, snapshot obligations
|
|
811
812
|
let renderedStartOfTurnPacket;
|
|
813
|
+
const careEvidenceNow = Date.now();
|
|
814
|
+
const activeCaresSnapshot = ctx.activeCares;
|
|
812
815
|
const preTurnObligationIds = new Set(pendingObligations.map((ob) => `${ob.id}:${ob.status}`));
|
|
813
816
|
try {
|
|
814
817
|
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
815
818
|
const agentName = (0, identity_1.getAgentName)();
|
|
816
|
-
const { recentEpisodes
|
|
819
|
+
const { recentEpisodes } = ctx;
|
|
820
|
+
const projectedCares = activeCaresSnapshot.map((care) => (0, cares_1.projectCareEvidence)(care, careEvidenceNow));
|
|
817
821
|
const tempoState = (0, tempo_1.deriveTempo)({
|
|
818
822
|
activeSessions: sessionActivity.length + 1,
|
|
819
823
|
openObligations: pendingObligations.length,
|
|
@@ -823,15 +827,15 @@ async function handleInboundTurn(input) {
|
|
|
823
827
|
: 0,
|
|
824
828
|
hasBlockers: false, // obligations use specific statuses, not "blocked"
|
|
825
829
|
highSalienceEpisodes: recentEpisodes.filter((ep) => ep.salience === "high" || ep.salience === "critical").length,
|
|
826
|
-
activeCareCount:
|
|
827
|
-
atRiskCareCount:
|
|
830
|
+
activeCareCount: activeCaresSnapshot.length,
|
|
831
|
+
atRiskCareCount: projectedCares.filter((care) => !("recheckRequired" in care) && care.currentRisk != null).length,
|
|
828
832
|
});
|
|
829
833
|
const temporalView = (0, temporal_view_1.buildTemporalView)(agentRoot, {
|
|
830
834
|
tempo: tempoState.mode,
|
|
831
835
|
preloaded: {
|
|
832
836
|
recentEpisodes,
|
|
833
837
|
activeObligations: pendingObligations,
|
|
834
|
-
activeCares,
|
|
838
|
+
activeCares: activeCaresSnapshot,
|
|
835
839
|
},
|
|
836
840
|
});
|
|
837
841
|
const startOfTurnPacket = (0, start_of_turn_packet_1.buildStartOfTurnPacket)(temporalView, {
|
|
@@ -843,6 +847,7 @@ async function handleInboundTurn(input) {
|
|
|
843
847
|
friendContactTiming,
|
|
844
848
|
flightRecorderResume: ctx.flightRecorderResume,
|
|
845
849
|
recoverySentinel: ctx.recoverySentinel,
|
|
850
|
+
careEvidenceNow,
|
|
846
851
|
});
|
|
847
852
|
/* v8 ignore next 3 -- syncFailure propagation tested in sync.test.ts @preserve */
|
|
848
853
|
if (syncFailure) {
|
|
@@ -928,6 +933,8 @@ async function handleInboundTurn(input) {
|
|
|
928
933
|
currentUserMessages,
|
|
929
934
|
resolvedContext,
|
|
930
935
|
runAgentOptions,
|
|
936
|
+
activeCares: activeCaresSnapshot,
|
|
937
|
+
careEvidenceNow,
|
|
931
938
|
}));
|
|
932
939
|
const checkpointCurrentAsk = selectCheckpointCurrentAsk({
|
|
933
940
|
currentUserMessage: runAgentOptions.toolContext?.currentUserMessage ?? currentUserMessage,
|