@haaaiawd/second-nature 0.2.9 → 0.2.12
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/index.js +6 -0
- package/openclaw.plugin.json +2 -5
- package/package.json +1 -1
- package/runtime/cli/host-capability/probe-host-capability.js +1 -1
- package/runtime/cli/host-capability/types.d.ts +2 -7
- package/runtime/cli/host-capability/types.js +0 -5
- package/runtime/cli/ops/heartbeat-surface.d.ts +2 -0
- package/runtime/cli/ops/heartbeat-surface.js +32 -3
- package/runtime/cli/ops/ops-router.js +3 -3
- package/runtime/cli/ops/workspace-heartbeat-runner.js +2 -5
- package/runtime/connectors/manifest/manifest-schema.d.ts +2 -2
- package/runtime/connectors/registry/dynamic-connector-registry.js +16 -1
- package/runtime/connectors/services/connector-executor-adapter.js +54 -35
- package/runtime/core/second-nature/action/action-closure-recorder.d.ts +2 -0
- package/runtime/core/second-nature/action/action-closure-recorder.js +2 -4
- package/runtime/core/second-nature/action/action-proposal-builder.js +5 -32
- package/runtime/core/second-nature/action/policy-bound-dispatch.js +4 -3
- package/runtime/core/second-nature/control-plane/accepted-projection-loader.js +1 -11
- package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.d.ts +1 -0
- package/runtime/core/second-nature/control-plane/heartbeat-orchestrator.js +10 -6
- package/runtime/core/second-nature/control-plane/real-runtime-spine.d.ts +2 -0
- package/runtime/core/second-nature/control-plane/real-runtime-spine.js +1 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +4 -3
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +3 -2
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +3 -2
- package/runtime/core/second-nature/orchestrator/intent-planner.js +4 -2
- package/runtime/core/second-nature/orchestrator/narrative-update.js +1 -2
- package/runtime/core/second-nature/orchestrator/platform-capability-router.d.ts +2 -2
- package/runtime/core/second-nature/orchestrator/platform-capability-router.js +1 -1
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +2 -3
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +2 -2
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +6 -1
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +3 -14
- package/runtime/core/second-nature/outreach/judge-outreach.d.ts +6 -5
- package/runtime/core/second-nature/perception/judgment-engine.js +2 -12
- package/runtime/core/second-nature/perception/perception-builder.js +1 -9
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +13 -15
- package/runtime/core/second-nature/quiet-dream/daily-rhythm-scheduler.js +10 -13
- package/runtime/core/second-nature/quiet-dream/dream-scheduler.js +0 -2
- package/runtime/core/second-nature/quiet-dream/memory-projection-lifecycle.js +0 -12
- package/runtime/core/second-nature/quiet-dream/quiet-daily-review-builder.js +1 -11
- package/runtime/core/second-nature/types.d.ts +2 -9
- package/runtime/dream/dream-engine.js +11 -4
- package/runtime/guidance/outreach-draft-schema.d.ts +12 -12
- package/runtime/guidance/persona-selection.js +5 -0
- package/runtime/guidance/template-registry.js +6 -1
- package/runtime/guidance/types.d.ts +2 -2
- package/runtime/observability/living-loop-health-gate.js +2 -8
- package/runtime/observability/loop-stage-event-sink.js +0 -1
- package/runtime/observability/services/lived-experience-audit.d.ts +7 -7
- package/runtime/shared/serialization.d.ts +17 -0
- package/runtime/shared/serialization.js +27 -0
- package/runtime/shared/source-ref-compat.d.ts +26 -0
- package/runtime/shared/source-ref-compat.js +61 -0
- package/runtime/shared/types/goal.d.ts +4 -4
- package/runtime/shared/types/goal.js +1 -1
- package/runtime/shared/types/index.d.ts +1 -0
- package/runtime/shared/types/index.js +1 -3
- package/runtime/shared/types/source-ref.d.ts +2 -2
- package/runtime/shared/types/v7-entities.d.ts +5 -5
- package/runtime/shared/types/v7-entities.js +1 -1
- package/runtime/shared/types/v8-contracts.d.ts +1 -1
- package/runtime/storage/db/index.js +31 -26
- package/runtime/storage/db/migrations/index.js +4 -0
- package/runtime/storage/db/migrations/v8-004-schema-closure.d.ts +19 -0
- package/runtime/storage/db/migrations/v8-004-schema-closure.js +74 -0
- package/runtime/storage/db/migrations/v8-005-single-status-schema.d.ts +11 -0
- package/runtime/storage/db/migrations/v8-005-single-status-schema.js +16 -0
- package/runtime/storage/db/schema/v8-entities.d.ts +0 -95
- package/runtime/storage/db/schema/v8-entities.js +4 -7
- package/runtime/storage/delivery/types.d.ts +2 -2
- package/runtime/storage/fallback/load-operator-fallback.d.ts +2 -2
- package/runtime/storage/fallback/operator-fallback-types.d.ts +2 -2
- package/runtime/storage/fallback/operator-fallback-view.d.ts +2 -2
- package/runtime/storage/index.d.ts +1 -1
- package/runtime/storage/life-evidence/types.d.ts +5 -5
- package/runtime/storage/quiet/quiet-artifact-types.d.ts +4 -4
- package/runtime/storage/quiet/quiet-artifact-writer.d.ts +2 -2
- package/runtime/storage/services/write-validation-gate.d.ts +1 -1
- package/runtime/storage/services/write-validation-gate.js +16 -4
- package/runtime/storage/snapshots/types.d.ts +8 -8
- package/runtime/storage/user-interest/types.d.ts +3 -3
- package/runtime/storage/v8-state-stores.d.ts +8 -1
- package/runtime/storage/v8-state-stores.js +23 -20
|
@@ -191,7 +191,7 @@ export async function runHeartbeatCycle(db, request) {
|
|
|
191
191
|
reason: degradedReason,
|
|
192
192
|
sourceRefs: degradedClosureRef ? [degradedClosureRef, cycleRef] : [cycleRef],
|
|
193
193
|
});
|
|
194
|
-
const { rhythmState } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
194
|
+
const { rhythmState, rhythmDegraded } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
195
195
|
return {
|
|
196
196
|
cycleId,
|
|
197
197
|
cycleSequence,
|
|
@@ -206,7 +206,8 @@ export async function runHeartbeatCycle(db, request) {
|
|
|
206
206
|
operatorNextAction: "Retry heartbeat after perception recovery",
|
|
207
207
|
retryable: true,
|
|
208
208
|
}
|
|
209
|
-
:
|
|
209
|
+
: rhythmDegraded,
|
|
210
|
+
rhythmDegraded,
|
|
210
211
|
rhythmState,
|
|
211
212
|
};
|
|
212
213
|
}
|
|
@@ -245,12 +246,14 @@ export async function runHeartbeatCycle(db, request) {
|
|
|
245
246
|
reason: "evidence_batch_empty",
|
|
246
247
|
sourceRefs: emptyClosureRef ? [emptyClosureRef, cycleRef] : [cycleRef],
|
|
247
248
|
});
|
|
248
|
-
const { rhythmState } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
249
|
+
const { rhythmState, rhythmDegraded } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
249
250
|
return {
|
|
250
251
|
cycleId,
|
|
251
252
|
cycleSequence,
|
|
252
253
|
closureRef: emptyClosureRef,
|
|
253
254
|
noActionReason: "evidence_batch_empty",
|
|
255
|
+
degraded: rhythmDegraded,
|
|
256
|
+
rhythmDegraded,
|
|
254
257
|
rhythmState,
|
|
255
258
|
};
|
|
256
259
|
}
|
|
@@ -365,7 +368,7 @@ export async function runHeartbeatCycle(db, request) {
|
|
|
365
368
|
}
|
|
366
369
|
else if (proposalResult.status === "remember_for_review") {
|
|
367
370
|
const remember = proposalResult;
|
|
368
|
-
const closureResult = await recordRememberClosure(db, cycleId, remember.memoryReviewCandidate, { now });
|
|
371
|
+
const closureResult = await recordRememberClosure(db, cycleId, remember.memoryReviewCandidate, { now, platformId: "heartbeat" });
|
|
369
372
|
if ("closureId" in closureResult) {
|
|
370
373
|
closureRef = {
|
|
371
374
|
uri: `sn://closure/${closureResult.closureId}`,
|
|
@@ -540,13 +543,14 @@ export async function runHeartbeatCycle(db, request) {
|
|
|
540
543
|
noActionReason = "proposal_no_action";
|
|
541
544
|
}
|
|
542
545
|
// T-CP.R.3: Advance daily rhythm after closure/no-action
|
|
543
|
-
const { rhythmState } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
546
|
+
const { rhythmState, rhythmDegraded } = await advanceAndRecordDailyRhythm(db, cycleId, cycleSequence, cycleRef, now);
|
|
544
547
|
return {
|
|
545
548
|
cycleId,
|
|
546
549
|
cycleSequence,
|
|
547
550
|
closureRef,
|
|
548
551
|
noActionReason,
|
|
549
|
-
degraded: closureDegraded,
|
|
552
|
+
degraded: closureDegraded ?? rhythmDegraded,
|
|
553
|
+
rhythmDegraded,
|
|
550
554
|
rhythmState,
|
|
551
555
|
};
|
|
552
556
|
}
|
|
@@ -31,5 +31,7 @@ export interface RealRuntimeSpineResult {
|
|
|
31
31
|
noActionReason?: V8ReasonCode;
|
|
32
32
|
degraded?: DegradedOperationResult;
|
|
33
33
|
rhythmState?: DailyRhythmState;
|
|
34
|
+
rhythmDegraded?: DegradedOperationResult;
|
|
35
|
+
impulseContextArtifactId?: string;
|
|
34
36
|
}
|
|
35
37
|
export declare function runRealRuntimeHeartbeatCycle(options: RealRuntimeSpineOptions): Promise<RealRuntimeSpineResult | DegradedOperationResult>;
|
|
@@ -38,5 +38,6 @@ export async function runRealRuntimeHeartbeatCycle(options) {
|
|
|
38
38
|
noActionReason: orchestrationResult.noActionReason,
|
|
39
39
|
degraded: orchestrationResult.degraded,
|
|
40
40
|
rhythmState: orchestrationResult.rhythmState,
|
|
41
|
+
rhythmDegraded: orchestrationResult.rhythmDegraded,
|
|
41
42
|
};
|
|
42
43
|
}
|
|
@@ -12,6 +12,7 @@ import { mapLifeEvidence } from "../../../connectors/base/map-life-evidence.js";
|
|
|
12
12
|
import { appendLifeEvidence } from "../../../storage/life-evidence/append-life-evidence.js";
|
|
13
13
|
import { normalizeConnectorEvidence } from "../../../connectors/evidence-normalizer.js";
|
|
14
14
|
import { recordConnectorAttemptAudit } from "../../../observability/services/audit-closure-recorders.js";
|
|
15
|
+
import { makeCanonicalSourceRef } from "../../../shared/source-ref-compat.js";
|
|
15
16
|
/**
|
|
16
17
|
* Resolves the heartbeat outcome for a guard-allowed intent (outreach dispatch, quiet orchestration, or default).
|
|
17
18
|
* Exported for unit tests (CR-M1 wiring).
|
|
@@ -302,11 +303,11 @@ export async function ingestRhythmSignal(signal, deps) {
|
|
|
302
303
|
effectClass: "connector_action",
|
|
303
304
|
capabilityIntent: idleResult.candidate.capabilityId,
|
|
304
305
|
sourceRefs: [
|
|
305
|
-
{
|
|
306
|
+
makeCanonicalSourceRef({
|
|
306
307
|
id: "idle_curiosity",
|
|
307
|
-
|
|
308
|
+
family: "audit",
|
|
308
309
|
uri: `idle://${idleResult.candidate.platformId}`,
|
|
309
|
-
},
|
|
310
|
+
}),
|
|
310
311
|
],
|
|
311
312
|
idempotencyKey: `idle:${idleResult.candidate.platformId}:${idleResult.candidate.capabilityId}`,
|
|
312
313
|
goalInfluenceRefs: [],
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HeartbeatRuntimeSnapshot assembly for candidate planner + hard guards (T2.1.3, T2.2.1).
|
|
3
3
|
*/
|
|
4
|
-
import type { ContinuitySnapshot
|
|
4
|
+
import type { ContinuitySnapshot } from "../types.js";
|
|
5
|
+
import type { SourceRef } from "../../../shared/types/v8-contracts.js";
|
|
5
6
|
import type { RhythmPolicy } from "../rhythm/rhythm-policy.js";
|
|
6
7
|
import { type PlannerRhythmWindowSlice } from "../rhythm/planner-rhythm-window.js";
|
|
7
8
|
import type { SnapshotInputs } from "./snapshot-builder.js";
|
|
8
9
|
import type { AffordanceMap } from "../../../shared/types/v7-entities.js";
|
|
9
10
|
export interface PlannerLifeEvidenceSlice {
|
|
10
|
-
evidenceRefs:
|
|
11
|
+
evidenceRefs: SourceRef[];
|
|
11
12
|
platformEventCount: number;
|
|
12
13
|
workEventCount: number;
|
|
13
14
|
emptyReason?: "no_sources" | "state_unavailable" | "redacted_only";
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Per design doc §4.2: SnapshotBuilder prepares inputs for the Rhythm Engine.
|
|
8
8
|
*/
|
|
9
|
-
import type { ContinuitySnapshot,
|
|
9
|
+
import type { ContinuitySnapshot, TopLevelMode } from "../types.js";
|
|
10
|
+
import type { SourceRef } from "../../../shared/types/v8-contracts.js";
|
|
10
11
|
import type { RhythmPolicy } from "../rhythm/rhythm-policy.js";
|
|
11
12
|
import type { DeliveryCapabilitySnapshot } from "../outreach/delivery-target.js";
|
|
12
13
|
import type { UserInterestSnapshot } from "../../../storage/user-interest/types.js";
|
|
@@ -30,7 +31,7 @@ export interface SnapshotInputs {
|
|
|
30
31
|
awaitingUserInput?: boolean;
|
|
31
32
|
riskSuppressed?: boolean;
|
|
32
33
|
/** Evidence refs for source-backed planner/guards (T2.1.3 / T2.2.1). */
|
|
33
|
-
lifeEvidenceRefs?:
|
|
34
|
+
lifeEvidenceRefs?: SourceRef[];
|
|
34
35
|
platformEventCount?: number;
|
|
35
36
|
workEventCount?: number;
|
|
36
37
|
lifeEvidenceEmptyReason?: "no_sources" | "state_unavailable" | "redacted_only";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { makeCanonicalSourceRef } from "../../../shared/source-ref-compat.js";
|
|
1
2
|
import { isLifeEvidenceSliceEmpty } from "../heartbeat/runtime-snapshot.js";
|
|
2
3
|
import { buildHeartbeatRuntimeSnapshot } from "../heartbeat/runtime-snapshot.js";
|
|
3
4
|
import { resolvePlatformForIntent, } from "./platform-capability-router.js";
|
|
4
5
|
import { isGoalRelatedToCandidate } from "./goal-priority.js";
|
|
5
6
|
const MAX_CANDIDATE_INTENTS = 6;
|
|
6
7
|
const OBLIGATION_SOURCE = [
|
|
7
|
-
{ id: "obligation-anchor",
|
|
8
|
+
makeCanonicalSourceRef({ id: "obligation-anchor", family: "audit", uri: "workspace://obligations/pending" }),
|
|
8
9
|
];
|
|
9
10
|
function evidenceRefsForConnector(runtime) {
|
|
10
11
|
if (!isLifeEvidenceSliceEmpty(runtime.lifeEvidence) && runtime.lifeEvidence.evidenceRefs.length > 0) {
|
|
@@ -253,8 +254,9 @@ export function planCandidateIntents(runtime, options) {
|
|
|
253
254
|
if (intent.sourceRefs.length === 0 && related.length > 0) {
|
|
254
255
|
intent.sourceRefs = related.slice(0, 4).map((g) => ({
|
|
255
256
|
id: g.goalId,
|
|
256
|
-
|
|
257
|
+
family: "audit",
|
|
257
258
|
uri: `goal://${g.goalId}`,
|
|
259
|
+
redactionClass: "none",
|
|
258
260
|
}));
|
|
259
261
|
}
|
|
260
262
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - Optional registry: when absent, resolution is best-effort from goals/evidence.
|
|
13
13
|
*/
|
|
14
14
|
import type { IntentKind } from "../types.js";
|
|
15
|
-
import type {
|
|
15
|
+
import type { SourceRef } from "../../../shared/types/v8-contracts.js";
|
|
16
16
|
import type { CapabilityContractRegistry } from "../../../connectors/base/manifest.js";
|
|
17
17
|
/** Minimal goal shape accepted by the router to avoid coupling to AgentGoal. M-03 decoupling. */
|
|
18
18
|
interface GoalRouterContext {
|
|
@@ -24,7 +24,7 @@ export interface PlatformResolutionContext {
|
|
|
24
24
|
/** Accepted goals that may name a platform or capability. */
|
|
25
25
|
acceptedGoals?: GoalRouterContext[];
|
|
26
26
|
/** Evidence refs that may embed platform identity. */
|
|
27
|
-
evidenceRefs?:
|
|
27
|
+
evidenceRefs?: SourceRef[];
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Resolve an explicit platformId for a candidate intent kind.
|
|
@@ -48,7 +48,7 @@ function extractPlatformIdsFromGoals(goals, kind, platformIds) {
|
|
|
48
48
|
function extractPlatformIdsFromEvidence(refs, platformIds) {
|
|
49
49
|
const results = new Set();
|
|
50
50
|
for (const ref of refs) {
|
|
51
|
-
if (ref.
|
|
51
|
+
if (ref.family === "connector_result" && ref.id) {
|
|
52
52
|
for (const pid of platformIds) {
|
|
53
53
|
if (ref.id.includes(pid)) {
|
|
54
54
|
results.add(pid);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Aligns with control-plane-system.detail §3.9 buildOutreachDraftRequest.
|
|
4
4
|
*/
|
|
5
5
|
import * as crypto from "node:crypto";
|
|
6
|
+
import { legacyKindFromSourceRef } from "../../../shared/source-ref-compat.js";
|
|
6
7
|
function inferRhythmWindowKind(windowId) {
|
|
7
8
|
const id = windowId.toLowerCase();
|
|
8
9
|
if (id.includes("work"))
|
|
@@ -20,10 +21,8 @@ function inferRhythmWindowKind(windowId) {
|
|
|
20
21
|
function toGuidanceRefs(refs) {
|
|
21
22
|
return refs.map((r) => ({
|
|
22
23
|
id: r.id,
|
|
23
|
-
kind: r
|
|
24
|
+
kind: legacyKindFromSourceRef(r),
|
|
24
25
|
uri: r.uri,
|
|
25
|
-
excerptHash: r.excerptHash,
|
|
26
|
-
observedAt: r.observedAt,
|
|
27
26
|
}));
|
|
28
27
|
}
|
|
29
28
|
function mapDeliveryVerdict(verdict) {
|
|
@@ -7,7 +7,7 @@ import type { CandidateIntent } from "../types.js";
|
|
|
7
7
|
import type { HeartbeatRuntimeSnapshot } from "../heartbeat/runtime-snapshot.js";
|
|
8
8
|
import type { HeartbeatCycleResult } from "../heartbeat/signal.js";
|
|
9
9
|
import type { StateDatabase } from "../../../storage/db/index.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type { LifeEvidenceSourceRef } from "../../../storage/life-evidence/types.js";
|
|
11
11
|
import { type JudgeOutreachInput } from "./judge-outreach.js";
|
|
12
12
|
import { type DeliveryTargetResolution } from "./delivery-target.js";
|
|
13
13
|
export interface OpenClawDeliverySendResult {
|
|
@@ -16,7 +16,7 @@ export interface OpenClawDeliverySendResult {
|
|
|
16
16
|
errorClass?: string;
|
|
17
17
|
messageId?: string;
|
|
18
18
|
/** Host-reported delivery proof when messageId is absent (T4.3.1). */
|
|
19
|
-
hostProofRef?:
|
|
19
|
+
hostProofRef?: LifeEvidenceSourceRef;
|
|
20
20
|
}
|
|
21
21
|
export interface OpenClawDeliveryPort {
|
|
22
22
|
sendDeliveryRequest(input: {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { legacyKindFromSourceRef } from "../../../shared/source-ref-compat.js";
|
|
1
2
|
import { writeDeliveryAttempt } from "../../../storage/delivery/write-delivery-attempt.js";
|
|
2
3
|
import { writeOperatorFallback } from "../../../storage/fallback/write-operator-fallback.js";
|
|
3
4
|
import { judgeOutreach } from "./judge-outreach.js";
|
|
@@ -6,7 +7,11 @@ import { buildOutreachDraftRequest } from "./build-outreach-draft-request.js";
|
|
|
6
7
|
import { createNarrativeStateStore } from "../../../storage/narrative/narrative-state-store.js";
|
|
7
8
|
import { createRelationshipMemoryStore } from "../../../storage/relationship/relationship-memory-store.js";
|
|
8
9
|
function toSourceRefs(refs) {
|
|
9
|
-
return refs.map((r) => ({
|
|
10
|
+
return refs.map((r) => ({
|
|
11
|
+
id: r.id,
|
|
12
|
+
kind: legacyKindFromSourceRef(r),
|
|
13
|
+
uri: r.uri,
|
|
14
|
+
}));
|
|
10
15
|
}
|
|
11
16
|
function hasDeliveryProof(attempt) {
|
|
12
17
|
return Boolean(attempt.messageId?.trim()) || Boolean(attempt.hostProofRef);
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
import { toCanonicalSourceRef } from "../../../shared/source-ref-compat.js";
|
|
1
2
|
import { isLifeEvidenceSliceEmpty } from "../heartbeat/runtime-snapshot.js";
|
|
2
3
|
function toControlPlaneRefs(refs) {
|
|
3
|
-
return refs.map((r) => (
|
|
4
|
-
id: r.id,
|
|
5
|
-
kind: r.kind,
|
|
6
|
-
uri: r.uri,
|
|
7
|
-
excerptHash: r.excerptHash,
|
|
8
|
-
observedAt: r.observedAt,
|
|
9
|
-
}));
|
|
4
|
+
return refs.map((r) => toCanonicalSourceRef(r));
|
|
10
5
|
}
|
|
11
6
|
export function userInterestSnapshotToJudge(snapshot) {
|
|
12
7
|
if (!snapshot) {
|
|
@@ -18,13 +13,7 @@ export function userInterestSnapshotToJudge(snapshot) {
|
|
|
18
13
|
signals: snapshot.signals.map((s) => ({
|
|
19
14
|
topic: s.topic,
|
|
20
15
|
confidence: s.confidence,
|
|
21
|
-
sourceRefs: s.sourceRefs.map((r) => (
|
|
22
|
-
id: r.id,
|
|
23
|
-
kind: r.kind,
|
|
24
|
-
uri: r.uri,
|
|
25
|
-
excerptHash: r.excerptHash,
|
|
26
|
-
observedAt: r.observedAt,
|
|
27
|
-
})),
|
|
16
|
+
sourceRefs: s.sourceRefs.map((r) => toCanonicalSourceRef(r)),
|
|
28
17
|
})),
|
|
29
18
|
sourceRefs: toControlPlaneRefs(snapshot.sourceRefs),
|
|
30
19
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { CandidateIntent
|
|
1
|
+
import type { CandidateIntent } from "../types.js";
|
|
2
|
+
import type { SourceRef } from "../../../shared/types/v8-contracts.js";
|
|
2
3
|
import { type DeliveryCapabilitySnapshot, type DeliveryTargetResolution } from "./delivery-target.js";
|
|
3
4
|
export type OutreachJudgmentVerdict = "allow" | "deny" | "defer";
|
|
4
5
|
export type CooldownState = "clear" | "cooling_down" | "duplicate";
|
|
@@ -8,9 +9,9 @@ export interface JudgeOutreachUserInterest {
|
|
|
8
9
|
signals: Array<{
|
|
9
10
|
topic: string;
|
|
10
11
|
confidence: number;
|
|
11
|
-
sourceRefs:
|
|
12
|
+
sourceRefs: SourceRef[];
|
|
12
13
|
}>;
|
|
13
|
-
sourceRefs:
|
|
14
|
+
sourceRefs: SourceRef[];
|
|
14
15
|
}
|
|
15
16
|
export interface JudgeOutreachLifeEvidence {
|
|
16
17
|
empty: boolean;
|
|
@@ -31,8 +32,8 @@ export interface OutreachJudgment {
|
|
|
31
32
|
valueScore: number;
|
|
32
33
|
userRelevance: number;
|
|
33
34
|
actionability: number;
|
|
34
|
-
interestRefs:
|
|
35
|
-
sourceRefs:
|
|
35
|
+
interestRefs: SourceRef[];
|
|
36
|
+
sourceRefs: SourceRef[];
|
|
36
37
|
cooldownState: CooldownState;
|
|
37
38
|
deliveryVerdict: DeliveryTargetResolution["verdict"];
|
|
38
39
|
reasons: string[];
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* Test coverage: tests/unit/judgment/judgment-engine.test.ts
|
|
23
23
|
*/
|
|
24
24
|
import { readPerceptionCardById, writeJudgmentVerdict, } from "../../../storage/v8-state-stores.js";
|
|
25
|
+
import { parseSourceRefs } from "../../../shared/serialization.js";
|
|
25
26
|
import { ACTION_KIND_REGISTRY } from "../../../shared/types/v8-contracts.js";
|
|
26
27
|
// ───────────────────────────────────────────────────────────────
|
|
27
28
|
// Config
|
|
@@ -42,17 +43,6 @@ function inferRiskPosture(sensitivityClass, riskFlags) {
|
|
|
42
43
|
}
|
|
43
44
|
return "low";
|
|
44
45
|
}
|
|
45
|
-
function parseCardSourceRefs(json) {
|
|
46
|
-
if (!json)
|
|
47
|
-
return [];
|
|
48
|
-
try {
|
|
49
|
-
const parsed = JSON.parse(json);
|
|
50
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
46
|
function selectVerdict(relevance, confidence, riskPosture, hasSourceRefs, possibleIntents) {
|
|
57
47
|
// Missing source refs → ignore/watch only
|
|
58
48
|
if (!hasSourceRefs) {
|
|
@@ -125,7 +115,7 @@ export async function runAgentJudgment(db, perceptionCardId, options) {
|
|
|
125
115
|
retryable: false,
|
|
126
116
|
};
|
|
127
117
|
}
|
|
128
|
-
const sourceRefs =
|
|
118
|
+
const sourceRefs = parseSourceRefs(card.sourceRefsJson);
|
|
129
119
|
const hasSourceRefs = sourceRefs.length > 0;
|
|
130
120
|
// Parse sensitivity class from payload (stored there by perception-builder)
|
|
131
121
|
let sensitivityClass = "public_general";
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* Test coverage: tests/unit/perception/perception-builder.test.ts
|
|
23
23
|
*/
|
|
24
24
|
import { readEvidenceItemsByStatus, writePerceptionCard, updateEvidenceItemLifecycleStatus, } from "../../../storage/v8-state-stores.js";
|
|
25
|
+
import { parseSourceRefs } from "../../../shared/serialization.js";
|
|
25
26
|
// ───────────────────────────────────────────────────────────────
|
|
26
27
|
// Config
|
|
27
28
|
// ───────────────────────────────────────────────────────────────
|
|
@@ -29,15 +30,6 @@ const PERCEPTION_MAX_EVIDENCE_PER_CYCLE = 50;
|
|
|
29
30
|
// ───────────────────────────────────────────────────────────────
|
|
30
31
|
// Helpers
|
|
31
32
|
// ───────────────────────────────────────────────────────────────
|
|
32
|
-
function parseSourceRefs(json) {
|
|
33
|
-
try {
|
|
34
|
-
const parsed = JSON.parse(json);
|
|
35
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
33
|
function parsePayload(json) {
|
|
42
34
|
if (!json)
|
|
43
35
|
return undefined;
|
|
@@ -3,13 +3,21 @@ import { writeQuietArtifact } from "../../../storage/quiet/quiet-artifact-writer
|
|
|
3
3
|
import { persistQuietArtifactToWorkspace } from "../../../storage/quiet/persist-quiet-artifact.js";
|
|
4
4
|
import { buildEvidencePack, buildQuietNarrativeGuidance, selectInterestBasis } from "../../../guidance/evidence-guidance.js";
|
|
5
5
|
import { recordQuietArtifactAudit } from "../../../observability/services/audit-closure-recorders.js";
|
|
6
|
+
import { legacyKindFromSourceRef } from "../../../shared/source-ref-compat.js";
|
|
6
7
|
function toGuidanceRef(r) {
|
|
7
8
|
return {
|
|
8
9
|
id: r.id,
|
|
9
|
-
kind: r
|
|
10
|
+
kind: legacyKindFromSourceRef(r),
|
|
10
11
|
uri: r.uri,
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function toLifeEvidenceRef(ref) {
|
|
15
|
+
return {
|
|
16
|
+
id: ref.id,
|
|
17
|
+
kind: ref.kind,
|
|
18
|
+
uri: ref.uri,
|
|
19
|
+
excerptHash: ref.excerptHash,
|
|
20
|
+
observedAt: ref.observedAt,
|
|
13
21
|
};
|
|
14
22
|
}
|
|
15
23
|
/**
|
|
@@ -116,24 +124,14 @@ export async function runSourceBackedQuiet(params) {
|
|
|
116
124
|
confidence: userInterestSnapshot?.confidence ?? 0,
|
|
117
125
|
signalCount: userInterestSnapshot?.signals.length ?? 0,
|
|
118
126
|
});
|
|
119
|
-
const groundedSourceRefs = ep.pack.groundedRefs.map(
|
|
120
|
-
id: g.id,
|
|
121
|
-
kind: g.kind,
|
|
122
|
-
uri: g.uri,
|
|
123
|
-
excerptHash: g.excerptHash,
|
|
124
|
-
observedAt: g.observedAt,
|
|
125
|
-
}));
|
|
127
|
+
const groundedSourceRefs = ep.pack.groundedRefs.map(toLifeEvidenceRef);
|
|
126
128
|
const claims = ep.pack.groundedRefs.map((g, i) => ({
|
|
127
129
|
id: `fact:${g.id}`,
|
|
128
130
|
text: `Evidence-backed note ${i + 1}`,
|
|
129
131
|
claimType: "fact",
|
|
130
132
|
sourceRefs: [
|
|
131
133
|
{
|
|
132
|
-
|
|
133
|
-
kind: g.kind,
|
|
134
|
-
uri: g.uri,
|
|
135
|
-
excerptHash: g.excerptHash,
|
|
136
|
-
observedAt: g.observedAt,
|
|
134
|
+
...toLifeEvidenceRef(g),
|
|
137
135
|
},
|
|
138
136
|
],
|
|
139
137
|
}));
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* so `dreamStatus` reaches completed/blocked.
|
|
23
23
|
* - Does not bypass Dream runner; only records due/completed/blocked.
|
|
24
24
|
*/
|
|
25
|
-
import { writeDailyRhythmState, readDailyRhythmStateByDay, readActionClosuresByDay, readDreamConsolidationRunById, readDreamConsolidationRunsByQuietId, updateDreamConsolidationRunStatus, } from "../../../storage/v8-state-stores.js";
|
|
25
|
+
import { writeDailyRhythmState, readDailyRhythmStateByDay, readActionClosuresByDay, readDreamConsolidationRunById, readDreamConsolidationRunsByQuietId, readLatestDreamConsolidationRunByStatus, updateDreamConsolidationRunStatus, } from "../../../storage/v8-state-stores.js";
|
|
26
26
|
import { buildQuietDailyReview } from "./quiet-daily-review-builder.js";
|
|
27
27
|
import { scheduleDreamAfterQuiet } from "./dream-scheduler.js";
|
|
28
28
|
import { runDreamConsolidation } from "./dream-consolidation-runner.js";
|
|
@@ -112,7 +112,6 @@ async function executeStaleScheduledDreams(db, state, now) {
|
|
|
112
112
|
const finalReason = dreamResult.reason ?? undefined;
|
|
113
113
|
const updateResult = await updateDreamConsolidationRunStatus(db, runId, finalStatus, {
|
|
114
114
|
reason: finalReason ?? null,
|
|
115
|
-
lifecycleStatus: finalStatus === "completed" ? "completed" : "archived",
|
|
116
115
|
payloadJson: JSON.stringify({
|
|
117
116
|
...parsePayloadJson(run.payloadJson),
|
|
118
117
|
consolidatedAt: now,
|
|
@@ -226,18 +225,17 @@ export async function checkDailyRhythm(db, options) {
|
|
|
226
225
|
// Already handled; do not re-schedule
|
|
227
226
|
}
|
|
228
227
|
else {
|
|
228
|
+
// Global 7-day interval check: look across all quiet reviews, not just today's.
|
|
229
229
|
const quietId = `quiet_${day}`;
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
232
|
-
return
|
|
230
|
+
const globalLatest = await readLatestDreamConsolidationRunByStatus(db, ["completed", "blocked"]);
|
|
231
|
+
if (globalLatest.degraded) {
|
|
232
|
+
return globalLatest.degraded;
|
|
233
233
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
state.dreamReason = latestRun.row.reason ?? "dream_completed";
|
|
240
|
-
if (latestRun.row.status === "completed") {
|
|
234
|
+
if (globalLatest.row &&
|
|
235
|
+
isWithinDays(globalLatest.row.createdAt, now, DREAM_DEFAULT_INTERVAL_DAYS)) {
|
|
236
|
+
state.dreamStatus = globalLatest.row.status;
|
|
237
|
+
state.dreamReason = "dream_interval_active";
|
|
238
|
+
if (globalLatest.row.status === "completed") {
|
|
241
239
|
state.dreamCompletedAt = now;
|
|
242
240
|
}
|
|
243
241
|
}
|
|
@@ -268,7 +266,6 @@ export async function checkDailyRhythm(db, options) {
|
|
|
268
266
|
const dreamOutcome = consolidateResult;
|
|
269
267
|
const updateResult = await updateDreamConsolidationRunStatus(db, dreamResult.id, dreamOutcome.status, {
|
|
270
268
|
reason: dreamOutcome.reason ?? null,
|
|
271
|
-
lifecycleStatus: dreamOutcome.status === "completed" ? "completed" : "archived",
|
|
272
269
|
payloadJson: JSON.stringify({
|
|
273
270
|
consolidatedAt: now,
|
|
274
271
|
candidateCount: dreamOutcome.candidates.length,
|
|
@@ -60,7 +60,6 @@ export async function scheduleDreamAfterQuiet(db, quietReviewId, options) {
|
|
|
60
60
|
},
|
|
61
61
|
],
|
|
62
62
|
redactionClass: "none",
|
|
63
|
-
lifecycleStatus: "pending",
|
|
64
63
|
payloadJson: JSON.stringify({ scheduledAt: now, blocked: true }),
|
|
65
64
|
});
|
|
66
65
|
if ("reason" in writeResult) {
|
|
@@ -90,7 +89,6 @@ export async function scheduleDreamAfterQuiet(db, quietReviewId, options) {
|
|
|
90
89
|
},
|
|
91
90
|
],
|
|
92
91
|
redactionClass: "none",
|
|
93
|
-
lifecycleStatus: "pending",
|
|
94
92
|
payloadJson: JSON.stringify({ scheduledAt: now }),
|
|
95
93
|
});
|
|
96
94
|
if ("reason" in writeResult) {
|
|
@@ -65,7 +65,6 @@ export async function acceptMemoryProjection(db, candidateId, topicKey, memoryTe
|
|
|
65
65
|
status: "active",
|
|
66
66
|
sourceRefs,
|
|
67
67
|
redactionClass: "none",
|
|
68
|
-
lifecycleStatus: "active",
|
|
69
68
|
payloadJson: JSON.stringify({
|
|
70
69
|
memoryText,
|
|
71
70
|
acceptedAt: now,
|
|
@@ -111,17 +110,6 @@ export async function retireMemoryProjection(db, projectionId, _candidateId, _to
|
|
|
111
110
|
// ───────────────────────────────────────────────────────────────
|
|
112
111
|
// Helpers
|
|
113
112
|
// ───────────────────────────────────────────────────────────────
|
|
114
|
-
function parseSourceRefs(json) {
|
|
115
|
-
if (!json)
|
|
116
|
-
return [];
|
|
117
|
-
try {
|
|
118
|
-
const parsed = JSON.parse(json);
|
|
119
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
113
|
function parsePayloadJson(json) {
|
|
126
114
|
if (!json)
|
|
127
115
|
return {};
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* Test coverage: tests/unit/quiet/quiet-daily-review-builder.test.ts
|
|
23
23
|
*/
|
|
24
24
|
import { readActionClosuresByDay, writeQuietDailyReview, readPerceptionCardById, readEvidenceItemsByDay, readPerceptionCardsByDay, } from "../../../storage/v8-state-stores.js";
|
|
25
|
+
import { parseSourceRefs } from "../../../shared/serialization.js";
|
|
25
26
|
// ───────────────────────────────────────────────────────────────
|
|
26
27
|
// Config
|
|
27
28
|
// ───────────────────────────────────────────────────────────────
|
|
@@ -52,17 +53,6 @@ function buildSourceRefFromClosure(closure) {
|
|
|
52
53
|
resolveStatus: "resolvable",
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
|
-
function parseSourceRefs(json) {
|
|
56
|
-
if (!json)
|
|
57
|
-
return [];
|
|
58
|
-
try {
|
|
59
|
-
const parsed = JSON.parse(json);
|
|
60
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
56
|
function buildSourceRefFromEvidence(evidence) {
|
|
67
57
|
const refs = parseSourceRefs(evidence.sourceRefsJson);
|
|
68
58
|
return (refs[0] ?? {
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
+
import type { SourceRef } from "../../shared/types/v8-contracts.js";
|
|
1
2
|
export type TopLevelMode = "active" | "quiet" | "maintenance_only" | "paused_for_interrupt";
|
|
2
3
|
/** Control-plane candidate kinds; includes `quiet` for quiet-window–biased intents (L0 alignment). */
|
|
3
4
|
export type IntentKind = "work" | "exploration" | "social" | "quiet" | "reflection" | "outreach" | "maintenance";
|
|
4
5
|
export type DecisionBasis = "rule_only" | "score_based" | "model_assisted";
|
|
5
6
|
export type GuardVerdict = "allow" | "defer" | "deny" | "escalate";
|
|
6
|
-
/** Minimal source ref for planner / guards (matches state-system `SourceRef` subset). */
|
|
7
|
-
export interface ControlPlaneSourceRef {
|
|
8
|
-
id: string;
|
|
9
|
-
kind: "platform_item" | "workspace_artifact" | "decision_record" | "user_anchor" | "connector_result" | "host_report" | "fallback_artifact";
|
|
10
|
-
uri: string;
|
|
11
|
-
excerptHash?: string;
|
|
12
|
-
observedAt?: string;
|
|
13
|
-
}
|
|
14
7
|
export interface ContinuitySnapshot {
|
|
15
8
|
mode: TopLevelMode;
|
|
16
9
|
currentWindowId: string;
|
|
@@ -40,7 +33,7 @@ export interface CandidateIntent {
|
|
|
40
33
|
summary: string;
|
|
41
34
|
effectClass: CandidateEffectClass;
|
|
42
35
|
/** Required for source-backed guard; may be empty when planner expects hard-guard deny. */
|
|
43
|
-
sourceRefs:
|
|
36
|
+
sourceRefs: SourceRef[];
|
|
44
37
|
/** Dedupe / cooldown key; defaults to stable fingerprint in guard layer when omitted. */
|
|
45
38
|
idempotencyKey?: string;
|
|
46
39
|
/** T2.1.4: IDs of accepted AgentGoals that influenced this candidate's priority. */
|
|
@@ -165,12 +165,19 @@ export async function runDream(input) {
|
|
|
165
165
|
});
|
|
166
166
|
}
|
|
167
167
|
if (!fallbackReason) {
|
|
168
|
+
let timeoutHandle;
|
|
168
169
|
const timeoutPromise = new Promise((_, reject) => {
|
|
169
|
-
setTimeout(() => reject(new Error("model_timeout")), operatorTimeoutMs);
|
|
170
|
+
timeoutHandle = setTimeout(() => reject(new Error("model_timeout")), operatorTimeoutMs);
|
|
170
171
|
});
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
try {
|
|
173
|
+
modelResult = await Promise.race([modelPromise, timeoutPromise]);
|
|
174
|
+
mode = "hybrid_llm";
|
|
175
|
+
llmCostUsd = modelResult.costUsd;
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
if (timeoutHandle)
|
|
179
|
+
clearTimeout(timeoutHandle);
|
|
180
|
+
}
|
|
174
181
|
}
|
|
175
182
|
}
|
|
176
183
|
catch (err) {
|