@haaaiawd/second-nature 0.1.39 → 0.1.40
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 +1270 -1270
- package/openclaw.plugin.json +29 -29
- package/package.json +55 -55
- package/runtime/cli/commands/connector-init.js +11 -4
- package/runtime/cli/index.js +6 -1
- package/runtime/cli/ops/heartbeat-surface.d.ts +75 -75
- package/runtime/cli/ops/heartbeat-surface.js +97 -97
- package/runtime/cli/ops/ops-router.js +1428 -1428
- package/runtime/cli/ops/workspace-heartbeat-runner.js +236 -236
- package/runtime/connectors/services/connector-executor-adapter.js +192 -41
- package/runtime/core/second-nature/guidance/apply-guidance.d.ts +12 -12
- package/runtime/core/second-nature/guidance/apply-guidance.js +15 -15
- package/runtime/core/second-nature/guidance/user-reply-continuity.d.ts +50 -50
- package/runtime/core/second-nature/guidance/user-reply-continuity.js +89 -89
- package/runtime/core/second-nature/orchestrator/intent-planner.js +15 -0
- package/runtime/core/second-nature/runtime/service-entry.d.ts +39 -39
- package/runtime/core/second-nature/runtime/service-entry.js +44 -44
- package/runtime/dream/dream-engine.d.ts +14 -14
- package/runtime/dream/dream-engine.js +306 -306
- package/runtime/dream/dream-input-loader.d.ts +37 -37
- package/runtime/dream/dream-input-loader.js +150 -150
- package/runtime/dream/dream-scheduler.d.ts +75 -75
- package/runtime/dream/dream-scheduler.js +131 -131
- package/runtime/dream/index.d.ts +16 -16
- package/runtime/dream/index.js +14 -14
- package/runtime/dream/insight-extractor.d.ts +32 -32
- package/runtime/dream/insight-extractor.js +135 -135
- package/runtime/dream/memory-consolidator.d.ts +45 -45
- package/runtime/dream/memory-consolidator.js +140 -140
- package/runtime/dream/narrative-update-proposal.d.ts +34 -34
- package/runtime/dream/narrative-update-proposal.js +83 -83
- package/runtime/dream/output-validator.d.ts +20 -20
- package/runtime/dream/output-validator.js +110 -110
- package/runtime/dream/redaction-gate.d.ts +31 -31
- package/runtime/dream/redaction-gate.js +109 -109
- package/runtime/dream/relationship-update-proposal.d.ts +27 -27
- package/runtime/dream/relationship-update-proposal.js +119 -119
- package/runtime/dream/sampler.d.ts +30 -30
- package/runtime/dream/sampler.js +65 -65
- package/runtime/dream/types.d.ts +187 -187
- package/runtime/dream/types.js +11 -11
- package/runtime/guidance/fallback.js +20 -20
- package/runtime/guidance/guidance-assembler.js +76 -76
- package/runtime/guidance/output-guard.d.ts +13 -13
- package/runtime/guidance/output-guard.js +53 -53
- package/runtime/guidance/template-registry.d.ts +20 -20
- package/runtime/guidance/template-registry.js +93 -93
- package/runtime/guidance/types.d.ts +98 -98
- package/runtime/observability/projections/guidance-audit.js +38 -38
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Narrative Update Proposal
|
|
3
|
-
*
|
|
4
|
-
* Core logic: generate a narrative update proposal based on evidence and
|
|
5
|
-
* extracted insights. Claims must be source-backed; unsupported claims are
|
|
6
|
-
* flagged and the proposal is degraded or blocked.
|
|
7
|
-
*
|
|
8
|
-
* - Focus: most prominent theme from insights or evidence.
|
|
9
|
-
* - Progress: learning and observation insights mapped to progress entries.
|
|
10
|
-
* - NextIntent: inferred from unresolved conflicts or high-priority patterns.
|
|
11
|
-
* Test coverage: tests/unit/dream/t7-1-4-narrative-update.test.ts
|
|
12
|
-
*/
|
|
13
|
-
import type { DreamNarrativeUpdate } from "./types.js";
|
|
14
|
-
export interface NarrativeProposalInput {
|
|
15
|
-
evidenceSummaries: Array<{
|
|
16
|
-
id: string;
|
|
17
|
-
summary: string;
|
|
18
|
-
createdAt: string;
|
|
19
|
-
}>;
|
|
20
|
-
insights: Array<{
|
|
21
|
-
id: string;
|
|
22
|
-
type: "pattern" | "learning" | "observation" | "conflict";
|
|
23
|
-
summary: string;
|
|
24
|
-
sourceRefs: string[];
|
|
25
|
-
confidence: number;
|
|
26
|
-
}>;
|
|
27
|
-
priorFocus?: string;
|
|
28
|
-
}
|
|
29
|
-
export interface NarrativeProposalResult {
|
|
30
|
-
proposal?: DreamNarrativeUpdate;
|
|
31
|
-
unsupportedClaims: string[];
|
|
32
|
-
blocked: boolean;
|
|
33
|
-
}
|
|
34
|
-
export declare function draftNarrativeFromDream(input: NarrativeProposalInput): NarrativeProposalResult;
|
|
1
|
+
/**
|
|
2
|
+
* Narrative Update Proposal
|
|
3
|
+
*
|
|
4
|
+
* Core logic: generate a narrative update proposal based on evidence and
|
|
5
|
+
* extracted insights. Claims must be source-backed; unsupported claims are
|
|
6
|
+
* flagged and the proposal is degraded or blocked.
|
|
7
|
+
*
|
|
8
|
+
* - Focus: most prominent theme from insights or evidence.
|
|
9
|
+
* - Progress: learning and observation insights mapped to progress entries.
|
|
10
|
+
* - NextIntent: inferred from unresolved conflicts or high-priority patterns.
|
|
11
|
+
* Test coverage: tests/unit/dream/t7-1-4-narrative-update.test.ts
|
|
12
|
+
*/
|
|
13
|
+
import type { DreamNarrativeUpdate } from "./types.js";
|
|
14
|
+
export interface NarrativeProposalInput {
|
|
15
|
+
evidenceSummaries: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
summary: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
}>;
|
|
20
|
+
insights: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
type: "pattern" | "learning" | "observation" | "conflict";
|
|
23
|
+
summary: string;
|
|
24
|
+
sourceRefs: string[];
|
|
25
|
+
confidence: number;
|
|
26
|
+
}>;
|
|
27
|
+
priorFocus?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface NarrativeProposalResult {
|
|
30
|
+
proposal?: DreamNarrativeUpdate;
|
|
31
|
+
unsupportedClaims: string[];
|
|
32
|
+
blocked: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function draftNarrativeFromDream(input: NarrativeProposalInput): NarrativeProposalResult;
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Narrative Update Proposal
|
|
3
|
-
*
|
|
4
|
-
* Core logic: generate a narrative update proposal based on evidence and
|
|
5
|
-
* extracted insights. Claims must be source-backed; unsupported claims are
|
|
6
|
-
* flagged and the proposal is degraded or blocked.
|
|
7
|
-
*
|
|
8
|
-
* - Focus: most prominent theme from insights or evidence.
|
|
9
|
-
* - Progress: learning and observation insights mapped to progress entries.
|
|
10
|
-
* - NextIntent: inferred from unresolved conflicts or high-priority patterns.
|
|
11
|
-
* Test coverage: tests/unit/dream/t7-1-4-narrative-update.test.ts
|
|
12
|
-
*/
|
|
13
|
-
export function draftNarrativeFromDream(input) {
|
|
14
|
-
const unsupportedClaims = [];
|
|
15
|
-
if (input.evidenceSummaries.length === 0 && input.insights.length === 0) {
|
|
16
|
-
return {
|
|
17
|
-
unsupportedClaims: ["no_evidence_for_narrative"],
|
|
18
|
-
blocked: true,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
// Focus: highest-confidence insight summary, or first evidence if no insights
|
|
22
|
-
let focus = input.priorFocus ?? "continue exploration";
|
|
23
|
-
const highConfidenceInsights = input.insights.filter((i) => i.confidence >= 0.6);
|
|
24
|
-
if (highConfidenceInsights.length > 0) {
|
|
25
|
-
// Pick the insight with highest confidence
|
|
26
|
-
const top = highConfidenceInsights.sort((a, b) => b.confidence - a.confidence)[0];
|
|
27
|
-
focus = top.summary.slice(0, 120);
|
|
28
|
-
}
|
|
29
|
-
else if (input.evidenceSummaries.length > 0) {
|
|
30
|
-
focus = input.evidenceSummaries[0].summary.slice(0, 120);
|
|
31
|
-
}
|
|
32
|
-
// Progress: learning + observation insights become progress entries
|
|
33
|
-
const progressAdditions = [];
|
|
34
|
-
for (const insight of input.insights) {
|
|
35
|
-
if (insight.type === "learning" || insight.type === "observation") {
|
|
36
|
-
progressAdditions.push(insight.summary.slice(0, 200));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (progressAdditions.length === 0 && input.evidenceSummaries.length > 0) {
|
|
40
|
-
// Fallback: use most recent evidence as progress
|
|
41
|
-
const recent = [...input.evidenceSummaries].sort((a, b) => b.createdAt.localeCompare(a.createdAt))[0];
|
|
42
|
-
if (recent) {
|
|
43
|
-
progressAdditions.push(recent.summary.slice(0, 200));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// NextIntent: if conflicts exist, intent is to resolve; otherwise continue
|
|
47
|
-
const hasConflict = input.insights.some((i) => i.type === "conflict");
|
|
48
|
-
const nextIntent = hasConflict
|
|
49
|
-
? "resolve_conflicts_and_validate"
|
|
50
|
-
: "continue_current_focus";
|
|
51
|
-
// Source refs: collect all insight source refs + evidence ids
|
|
52
|
-
const sourceRefs = new Set();
|
|
53
|
-
for (const insight of input.insights) {
|
|
54
|
-
for (const ref of insight.sourceRefs) {
|
|
55
|
-
sourceRefs.add(ref);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
for (const ev of input.evidenceSummaries) {
|
|
59
|
-
sourceRefs.add(ev.id);
|
|
60
|
-
}
|
|
61
|
-
// Confidence: average of insight confidences, or 0.5 fallback
|
|
62
|
-
const avgConfidence = input.insights.length > 0
|
|
63
|
-
? input.insights.reduce((sum, i) => sum + i.confidence, 0) /
|
|
64
|
-
input.insights.length
|
|
65
|
-
: 0.5;
|
|
66
|
-
// Degrade if confidence too low
|
|
67
|
-
if (avgConfidence < 0.3) {
|
|
68
|
-
unsupportedClaims.push("low_average_confidence_for_narrative");
|
|
69
|
-
}
|
|
70
|
-
const blocked = unsupportedClaims.length > 0 && avgConfidence < 0.2;
|
|
71
|
-
return {
|
|
72
|
-
proposal: {
|
|
73
|
-
focus,
|
|
74
|
-
progressAdditions: progressAdditions.slice(0, 20),
|
|
75
|
-
nextIntent,
|
|
76
|
-
confidenceDelta: Number(avgConfidence.toFixed(2)),
|
|
77
|
-
sourceRefs: Array.from(sourceRefs).slice(0, 50),
|
|
78
|
-
unsupportedClaims,
|
|
79
|
-
},
|
|
80
|
-
unsupportedClaims,
|
|
81
|
-
blocked,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Narrative Update Proposal
|
|
3
|
+
*
|
|
4
|
+
* Core logic: generate a narrative update proposal based on evidence and
|
|
5
|
+
* extracted insights. Claims must be source-backed; unsupported claims are
|
|
6
|
+
* flagged and the proposal is degraded or blocked.
|
|
7
|
+
*
|
|
8
|
+
* - Focus: most prominent theme from insights or evidence.
|
|
9
|
+
* - Progress: learning and observation insights mapped to progress entries.
|
|
10
|
+
* - NextIntent: inferred from unresolved conflicts or high-priority patterns.
|
|
11
|
+
* Test coverage: tests/unit/dream/t7-1-4-narrative-update.test.ts
|
|
12
|
+
*/
|
|
13
|
+
export function draftNarrativeFromDream(input) {
|
|
14
|
+
const unsupportedClaims = [];
|
|
15
|
+
if (input.evidenceSummaries.length === 0 && input.insights.length === 0) {
|
|
16
|
+
return {
|
|
17
|
+
unsupportedClaims: ["no_evidence_for_narrative"],
|
|
18
|
+
blocked: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Focus: highest-confidence insight summary, or first evidence if no insights
|
|
22
|
+
let focus = input.priorFocus ?? "continue exploration";
|
|
23
|
+
const highConfidenceInsights = input.insights.filter((i) => i.confidence >= 0.6);
|
|
24
|
+
if (highConfidenceInsights.length > 0) {
|
|
25
|
+
// Pick the insight with highest confidence
|
|
26
|
+
const top = highConfidenceInsights.sort((a, b) => b.confidence - a.confidence)[0];
|
|
27
|
+
focus = top.summary.slice(0, 120);
|
|
28
|
+
}
|
|
29
|
+
else if (input.evidenceSummaries.length > 0) {
|
|
30
|
+
focus = input.evidenceSummaries[0].summary.slice(0, 120);
|
|
31
|
+
}
|
|
32
|
+
// Progress: learning + observation insights become progress entries
|
|
33
|
+
const progressAdditions = [];
|
|
34
|
+
for (const insight of input.insights) {
|
|
35
|
+
if (insight.type === "learning" || insight.type === "observation") {
|
|
36
|
+
progressAdditions.push(insight.summary.slice(0, 200));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (progressAdditions.length === 0 && input.evidenceSummaries.length > 0) {
|
|
40
|
+
// Fallback: use most recent evidence as progress
|
|
41
|
+
const recent = [...input.evidenceSummaries].sort((a, b) => b.createdAt.localeCompare(a.createdAt))[0];
|
|
42
|
+
if (recent) {
|
|
43
|
+
progressAdditions.push(recent.summary.slice(0, 200));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// NextIntent: if conflicts exist, intent is to resolve; otherwise continue
|
|
47
|
+
const hasConflict = input.insights.some((i) => i.type === "conflict");
|
|
48
|
+
const nextIntent = hasConflict
|
|
49
|
+
? "resolve_conflicts_and_validate"
|
|
50
|
+
: "continue_current_focus";
|
|
51
|
+
// Source refs: collect all insight source refs + evidence ids
|
|
52
|
+
const sourceRefs = new Set();
|
|
53
|
+
for (const insight of input.insights) {
|
|
54
|
+
for (const ref of insight.sourceRefs) {
|
|
55
|
+
sourceRefs.add(ref);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const ev of input.evidenceSummaries) {
|
|
59
|
+
sourceRefs.add(ev.id);
|
|
60
|
+
}
|
|
61
|
+
// Confidence: average of insight confidences, or 0.5 fallback
|
|
62
|
+
const avgConfidence = input.insights.length > 0
|
|
63
|
+
? input.insights.reduce((sum, i) => sum + i.confidence, 0) /
|
|
64
|
+
input.insights.length
|
|
65
|
+
: 0.5;
|
|
66
|
+
// Degrade if confidence too low
|
|
67
|
+
if (avgConfidence < 0.3) {
|
|
68
|
+
unsupportedClaims.push("low_average_confidence_for_narrative");
|
|
69
|
+
}
|
|
70
|
+
const blocked = unsupportedClaims.length > 0 && avgConfidence < 0.2;
|
|
71
|
+
return {
|
|
72
|
+
proposal: {
|
|
73
|
+
focus,
|
|
74
|
+
progressAdditions: progressAdditions.slice(0, 20),
|
|
75
|
+
nextIntent,
|
|
76
|
+
confidenceDelta: Number(avgConfidence.toFixed(2)),
|
|
77
|
+
sourceRefs: Array.from(sourceRefs).slice(0, 50),
|
|
78
|
+
unsupportedClaims,
|
|
79
|
+
},
|
|
80
|
+
unsupportedClaims,
|
|
81
|
+
blocked,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dream output validator.
|
|
3
|
-
*
|
|
4
|
-
* Core logic: schema, source grounding, sensitivity, and unsupported claim
|
|
5
|
-
* checks on candidate DreamOutput. Decides accepted eligibility or archive reason.
|
|
6
|
-
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
7
|
-
*/
|
|
8
|
-
import type { DreamOutput, DreamOutputValidation } from "./types.js";
|
|
9
|
-
export interface ValidationInput {
|
|
10
|
-
output: DreamOutput;
|
|
11
|
-
inputEvidenceIds: string[];
|
|
12
|
-
inputChronicleIds: string[];
|
|
13
|
-
inputToolExperienceIds?: string[];
|
|
14
|
-
}
|
|
15
|
-
export interface ValidationResult {
|
|
16
|
-
eligible: boolean;
|
|
17
|
-
validation: DreamOutputValidation;
|
|
18
|
-
archiveReasons: string[];
|
|
19
|
-
}
|
|
20
|
-
export declare function validateDreamOutput(input: ValidationInput): ValidationResult;
|
|
1
|
+
/**
|
|
2
|
+
* Dream output validator.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: schema, source grounding, sensitivity, and unsupported claim
|
|
5
|
+
* checks on candidate DreamOutput. Decides accepted eligibility or archive reason.
|
|
6
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
7
|
+
*/
|
|
8
|
+
import type { DreamOutput, DreamOutputValidation } from "./types.js";
|
|
9
|
+
export interface ValidationInput {
|
|
10
|
+
output: DreamOutput;
|
|
11
|
+
inputEvidenceIds: string[];
|
|
12
|
+
inputChronicleIds: string[];
|
|
13
|
+
inputToolExperienceIds?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface ValidationResult {
|
|
16
|
+
eligible: boolean;
|
|
17
|
+
validation: DreamOutputValidation;
|
|
18
|
+
archiveReasons: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function validateDreamOutput(input: ValidationInput): ValidationResult;
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dream output validator.
|
|
3
|
-
*
|
|
4
|
-
* Core logic: schema, source grounding, sensitivity, and unsupported claim
|
|
5
|
-
* checks on candidate DreamOutput. Decides accepted eligibility or archive reason.
|
|
6
|
-
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
7
|
-
*/
|
|
8
|
-
function hasUnsupportedClaims(output) {
|
|
9
|
-
const claims = [];
|
|
10
|
-
for (const insight of output.insights) {
|
|
11
|
-
if (insight.confidence < 0.3) {
|
|
12
|
-
claims.push(`insight_low_confidence:${insight.id}`);
|
|
13
|
-
}
|
|
14
|
-
if (insight.sourceRefs.length === 0) {
|
|
15
|
-
claims.push(`insight_no_source:${insight.id}`);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
if (output.narrativeUpdate) {
|
|
19
|
-
if (output.narrativeUpdate.unsupportedClaims.length > 0) {
|
|
20
|
-
claims.push(...output.narrativeUpdate.unsupportedClaims);
|
|
21
|
-
}
|
|
22
|
-
if (output.narrativeUpdate.sourceRefs.length === 0) {
|
|
23
|
-
claims.push("narrative_update_no_source");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (output.relationshipUpdate) {
|
|
27
|
-
if (output.relationshipUpdate.sourceRefs.length === 0) {
|
|
28
|
-
claims.push("relationship_update_no_source");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return claims;
|
|
32
|
-
}
|
|
33
|
-
function isSourceGrounded(output, inputEvidenceIds, inputChronicleIds, inputToolExperienceIds) {
|
|
34
|
-
const validSourceIds = new Set([
|
|
35
|
-
...inputEvidenceIds,
|
|
36
|
-
...inputChronicleIds,
|
|
37
|
-
...(inputToolExperienceIds ?? []),
|
|
38
|
-
]);
|
|
39
|
-
for (const entry of output.canonicalEntries) {
|
|
40
|
-
for (const ref of entry.sourceRefs) {
|
|
41
|
-
if (!validSourceIds.has(ref.sourceId)) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
for (const insight of output.insights) {
|
|
47
|
-
for (const refId of insight.sourceRefs) {
|
|
48
|
-
if (!validSourceIds.has(refId)) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
function hasSensitivityIssues(output) {
|
|
56
|
-
const issues = [];
|
|
57
|
-
for (const entry of output.canonicalEntries) {
|
|
58
|
-
const text = JSON.stringify(entry).toLowerCase();
|
|
59
|
-
if (text.includes("password") || text.includes("token") || text.includes("secret")) {
|
|
60
|
-
issues.push(`sensitivity_in_entry:${entry.entryId}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return issues;
|
|
64
|
-
}
|
|
65
|
-
export function validateDreamOutput(input) {
|
|
66
|
-
const errors = [];
|
|
67
|
-
const archiveReasons = [];
|
|
68
|
-
// Schema: basic structural checks
|
|
69
|
-
const schemaValid = typeof input.output.outputId === "string" &&
|
|
70
|
-
input.output.outputId.length > 0 &&
|
|
71
|
-
typeof input.output.runId === "string" &&
|
|
72
|
-
Array.isArray(input.output.canonicalEntries) &&
|
|
73
|
-
Array.isArray(input.output.insights);
|
|
74
|
-
if (!schemaValid) {
|
|
75
|
-
errors.push("schema_invalid");
|
|
76
|
-
archiveReasons.push("schema_invalid");
|
|
77
|
-
}
|
|
78
|
-
// Source grounding
|
|
79
|
-
const sourceGrounded = isSourceGrounded(input.output, input.inputEvidenceIds, input.inputChronicleIds, input.inputToolExperienceIds);
|
|
80
|
-
if (!sourceGrounded) {
|
|
81
|
-
errors.push("source_not_grounded");
|
|
82
|
-
archiveReasons.push("source_not_grounded");
|
|
83
|
-
}
|
|
84
|
-
// Sensitivity
|
|
85
|
-
const sensitivityIssues = hasSensitivityIssues(input.output);
|
|
86
|
-
const sensitivityClean = sensitivityIssues.length === 0;
|
|
87
|
-
if (!sensitivityClean) {
|
|
88
|
-
errors.push(...sensitivityIssues);
|
|
89
|
-
archiveReasons.push(...sensitivityIssues);
|
|
90
|
-
}
|
|
91
|
-
// Unsupported claims
|
|
92
|
-
const unsupportedClaims = hasUnsupportedClaims(input.output);
|
|
93
|
-
if (unsupportedClaims.length > 0) {
|
|
94
|
-
errors.push(...unsupportedClaims);
|
|
95
|
-
archiveReasons.push("unsupported_claims_present");
|
|
96
|
-
}
|
|
97
|
-
const eligible = schemaValid && sourceGrounded && sensitivityClean && unsupportedClaims.length === 0;
|
|
98
|
-
return {
|
|
99
|
-
eligible,
|
|
100
|
-
validation: {
|
|
101
|
-
schemaValid,
|
|
102
|
-
sourceGrounded,
|
|
103
|
-
sensitivityClean,
|
|
104
|
-
unsupportedClaims,
|
|
105
|
-
errors,
|
|
106
|
-
checkedAt: new Date().toISOString(),
|
|
107
|
-
},
|
|
108
|
-
archiveReasons,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Dream output validator.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: schema, source grounding, sensitivity, and unsupported claim
|
|
5
|
+
* checks on candidate DreamOutput. Decides accepted eligibility or archive reason.
|
|
6
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
7
|
+
*/
|
|
8
|
+
function hasUnsupportedClaims(output) {
|
|
9
|
+
const claims = [];
|
|
10
|
+
for (const insight of output.insights) {
|
|
11
|
+
if (insight.confidence < 0.3) {
|
|
12
|
+
claims.push(`insight_low_confidence:${insight.id}`);
|
|
13
|
+
}
|
|
14
|
+
if (insight.sourceRefs.length === 0) {
|
|
15
|
+
claims.push(`insight_no_source:${insight.id}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (output.narrativeUpdate) {
|
|
19
|
+
if (output.narrativeUpdate.unsupportedClaims.length > 0) {
|
|
20
|
+
claims.push(...output.narrativeUpdate.unsupportedClaims);
|
|
21
|
+
}
|
|
22
|
+
if (output.narrativeUpdate.sourceRefs.length === 0) {
|
|
23
|
+
claims.push("narrative_update_no_source");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (output.relationshipUpdate) {
|
|
27
|
+
if (output.relationshipUpdate.sourceRefs.length === 0) {
|
|
28
|
+
claims.push("relationship_update_no_source");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return claims;
|
|
32
|
+
}
|
|
33
|
+
function isSourceGrounded(output, inputEvidenceIds, inputChronicleIds, inputToolExperienceIds) {
|
|
34
|
+
const validSourceIds = new Set([
|
|
35
|
+
...inputEvidenceIds,
|
|
36
|
+
...inputChronicleIds,
|
|
37
|
+
...(inputToolExperienceIds ?? []),
|
|
38
|
+
]);
|
|
39
|
+
for (const entry of output.canonicalEntries) {
|
|
40
|
+
for (const ref of entry.sourceRefs) {
|
|
41
|
+
if (!validSourceIds.has(ref.sourceId)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const insight of output.insights) {
|
|
47
|
+
for (const refId of insight.sourceRefs) {
|
|
48
|
+
if (!validSourceIds.has(refId)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
function hasSensitivityIssues(output) {
|
|
56
|
+
const issues = [];
|
|
57
|
+
for (const entry of output.canonicalEntries) {
|
|
58
|
+
const text = JSON.stringify(entry).toLowerCase();
|
|
59
|
+
if (text.includes("password") || text.includes("token") || text.includes("secret")) {
|
|
60
|
+
issues.push(`sensitivity_in_entry:${entry.entryId}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
export function validateDreamOutput(input) {
|
|
66
|
+
const errors = [];
|
|
67
|
+
const archiveReasons = [];
|
|
68
|
+
// Schema: basic structural checks
|
|
69
|
+
const schemaValid = typeof input.output.outputId === "string" &&
|
|
70
|
+
input.output.outputId.length > 0 &&
|
|
71
|
+
typeof input.output.runId === "string" &&
|
|
72
|
+
Array.isArray(input.output.canonicalEntries) &&
|
|
73
|
+
Array.isArray(input.output.insights);
|
|
74
|
+
if (!schemaValid) {
|
|
75
|
+
errors.push("schema_invalid");
|
|
76
|
+
archiveReasons.push("schema_invalid");
|
|
77
|
+
}
|
|
78
|
+
// Source grounding
|
|
79
|
+
const sourceGrounded = isSourceGrounded(input.output, input.inputEvidenceIds, input.inputChronicleIds, input.inputToolExperienceIds);
|
|
80
|
+
if (!sourceGrounded) {
|
|
81
|
+
errors.push("source_not_grounded");
|
|
82
|
+
archiveReasons.push("source_not_grounded");
|
|
83
|
+
}
|
|
84
|
+
// Sensitivity
|
|
85
|
+
const sensitivityIssues = hasSensitivityIssues(input.output);
|
|
86
|
+
const sensitivityClean = sensitivityIssues.length === 0;
|
|
87
|
+
if (!sensitivityClean) {
|
|
88
|
+
errors.push(...sensitivityIssues);
|
|
89
|
+
archiveReasons.push(...sensitivityIssues);
|
|
90
|
+
}
|
|
91
|
+
// Unsupported claims
|
|
92
|
+
const unsupportedClaims = hasUnsupportedClaims(input.output);
|
|
93
|
+
if (unsupportedClaims.length > 0) {
|
|
94
|
+
errors.push(...unsupportedClaims);
|
|
95
|
+
archiveReasons.push("unsupported_claims_present");
|
|
96
|
+
}
|
|
97
|
+
const eligible = schemaValid && sourceGrounded && sensitivityClean && unsupportedClaims.length === 0;
|
|
98
|
+
return {
|
|
99
|
+
eligible,
|
|
100
|
+
validation: {
|
|
101
|
+
schemaValid,
|
|
102
|
+
sourceGrounded,
|
|
103
|
+
sensitivityClean,
|
|
104
|
+
unsupportedClaims,
|
|
105
|
+
errors,
|
|
106
|
+
checkedAt: new Date().toISOString(),
|
|
107
|
+
},
|
|
108
|
+
archiveReasons,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dream redaction gate.
|
|
3
|
-
*
|
|
4
|
-
* Core logic: before sending evidence to LLM, strip credential-like fields,
|
|
5
|
-
* PII patterns, and sensitive platform payload. If redaction fails or
|
|
6
|
-
* sensitivity is too high, block the LLM stage and record reason.
|
|
7
|
-
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
8
|
-
*/
|
|
9
|
-
import type { RedactedEvidenceBundle } from "./types.js";
|
|
10
|
-
export interface RedactionInput {
|
|
11
|
-
evidenceSummaries: string[];
|
|
12
|
-
chronicleSummaries: string[];
|
|
13
|
-
activeMemorySummaries?: string[];
|
|
14
|
-
sensitivityFlags?: string[];
|
|
15
|
-
}
|
|
16
|
-
export interface RedactionResult {
|
|
17
|
-
allowed: boolean;
|
|
18
|
-
redactedEvidence: string[];
|
|
19
|
-
redactedChronicle: string[];
|
|
20
|
-
redactedMemory: string[];
|
|
21
|
-
blockedReason?: string;
|
|
22
|
-
credentialHits: number;
|
|
23
|
-
piiHits: number;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Produce a RedactedEvidenceBundle brand type (DR-027).
|
|
27
|
-
* Must be called before passing evidence to ModelAssistPort.
|
|
28
|
-
* Returns null if redaction gate blocks the bundle.
|
|
29
|
-
*/
|
|
30
|
-
export declare function redactBundle(evidence: string[], chronicle: string[], memory?: string[]): RedactedEvidenceBundle | null;
|
|
31
|
-
export declare function redactDreamInput(input: RedactionInput): RedactionResult;
|
|
1
|
+
/**
|
|
2
|
+
* Dream redaction gate.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: before sending evidence to LLM, strip credential-like fields,
|
|
5
|
+
* PII patterns, and sensitive platform payload. If redaction fails or
|
|
6
|
+
* sensitivity is too high, block the LLM stage and record reason.
|
|
7
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
8
|
+
*/
|
|
9
|
+
import type { RedactedEvidenceBundle } from "./types.js";
|
|
10
|
+
export interface RedactionInput {
|
|
11
|
+
evidenceSummaries: string[];
|
|
12
|
+
chronicleSummaries: string[];
|
|
13
|
+
activeMemorySummaries?: string[];
|
|
14
|
+
sensitivityFlags?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface RedactionResult {
|
|
17
|
+
allowed: boolean;
|
|
18
|
+
redactedEvidence: string[];
|
|
19
|
+
redactedChronicle: string[];
|
|
20
|
+
redactedMemory: string[];
|
|
21
|
+
blockedReason?: string;
|
|
22
|
+
credentialHits: number;
|
|
23
|
+
piiHits: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Produce a RedactedEvidenceBundle brand type (DR-027).
|
|
27
|
+
* Must be called before passing evidence to ModelAssistPort.
|
|
28
|
+
* Returns null if redaction gate blocks the bundle.
|
|
29
|
+
*/
|
|
30
|
+
export declare function redactBundle(evidence: string[], chronicle: string[], memory?: string[]): RedactedEvidenceBundle | null;
|
|
31
|
+
export declare function redactDreamInput(input: RedactionInput): RedactionResult;
|