@haaaiawd/second-nature 0.1.38 → 0.1.39
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/agent-inner-guide.md +18 -0
- package/index.js +1270 -1262
- package/openclaw.plugin.json +29 -29
- package/package.json +55 -55
- package/runtime/cli/ops/heartbeat-surface.d.ts +75 -60
- package/runtime/cli/ops/heartbeat-surface.js +97 -83
- package/runtime/cli/ops/ops-router.js +1428 -1282
- package/runtime/cli/ops/workspace-heartbeat-runner.js +236 -191
- package/runtime/core/second-nature/guidance/apply-guidance.d.ts +12 -10
- package/runtime/core/second-nature/guidance/apply-guidance.js +15 -10
- package/runtime/core/second-nature/guidance/user-reply-continuity.d.ts +50 -50
- package/runtime/core/second-nature/guidance/user-reply-continuity.js +89 -80
- package/runtime/core/second-nature/runtime/service-entry.d.ts +39 -36
- package/runtime/core/second-nature/runtime/service-entry.js +44 -45
- package/runtime/dream/dream-engine.d.ts +14 -0
- package/runtime/dream/dream-engine.js +306 -0
- package/runtime/dream/dream-input-loader.d.ts +37 -0
- package/runtime/dream/dream-input-loader.js +155 -0
- package/runtime/dream/dream-scheduler.d.ts +75 -0
- package/runtime/dream/dream-scheduler.js +131 -0
- package/runtime/dream/index.d.ts +16 -0
- package/runtime/dream/index.js +14 -0
- package/runtime/dream/insight-extractor.d.ts +32 -0
- package/runtime/dream/insight-extractor.js +135 -0
- package/runtime/dream/memory-consolidator.d.ts +45 -0
- package/runtime/dream/memory-consolidator.js +140 -0
- package/runtime/dream/narrative-update-proposal.d.ts +34 -0
- package/runtime/dream/narrative-update-proposal.js +83 -0
- package/runtime/dream/output-validator.d.ts +20 -0
- package/runtime/dream/output-validator.js +110 -0
- package/runtime/dream/redaction-gate.d.ts +31 -0
- package/runtime/dream/redaction-gate.js +109 -0
- package/runtime/dream/relationship-update-proposal.d.ts +27 -0
- package/runtime/dream/relationship-update-proposal.js +119 -0
- package/runtime/dream/sampler.d.ts +30 -0
- package/runtime/dream/sampler.js +65 -0
- package/runtime/dream/types.d.ts +187 -0
- package/runtime/dream/types.js +11 -0
- package/runtime/guidance/fallback.js +20 -17
- package/runtime/guidance/guidance-assembler.js +76 -74
- package/runtime/guidance/output-guard.d.ts +13 -10
- package/runtime/guidance/output-guard.js +53 -29
- package/runtime/guidance/template-registry.d.ts +20 -16
- package/runtime/guidance/template-registry.js +123 -82
- package/runtime/guidance/types.d.ts +98 -84
- package/runtime/observability/projections/guidance-audit.js +38 -35
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dream input sampler.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: when evidence count exceeds threshold, sample recent 7 days
|
|
5
|
+
* plus key events (outreach, owner reply, goal milestone, high-confidence refs).
|
|
6
|
+
* Goal: prevent token/cost explosion before LLM stage.
|
|
7
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
8
|
+
*/
|
|
9
|
+
export interface SamplerInput {
|
|
10
|
+
evidenceSummaries: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
summary: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
kind?: string;
|
|
15
|
+
confidence?: number;
|
|
16
|
+
}>;
|
|
17
|
+
chronicleSummaries: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
summary: string;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
}>;
|
|
22
|
+
evidenceLimit?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface SamplerResult {
|
|
25
|
+
sampledEvidenceIds: string[];
|
|
26
|
+
sampledChronicleIds: string[];
|
|
27
|
+
droppedCount: number;
|
|
28
|
+
reason: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function sampleDreamInput(input: SamplerInput): SamplerResult;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dream input sampler.
|
|
3
|
+
*
|
|
4
|
+
* Core logic: when evidence count exceeds threshold, sample recent 7 days
|
|
5
|
+
* plus key events (outreach, owner reply, goal milestone, high-confidence refs).
|
|
6
|
+
* Goal: prevent token/cost explosion before LLM stage.
|
|
7
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_EVIDENCE_LIMIT = 1000;
|
|
10
|
+
const RECENT_DAYS = 7;
|
|
11
|
+
function isWithinDays(createdAt, days) {
|
|
12
|
+
const then = new Date(createdAt).getTime();
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
return now - then <= days * 24 * 60 * 60 * 1000;
|
|
15
|
+
}
|
|
16
|
+
function isKeyEvent(item) {
|
|
17
|
+
if (!item.kind)
|
|
18
|
+
return false;
|
|
19
|
+
const keyKinds = [
|
|
20
|
+
"outreach",
|
|
21
|
+
"owner_reply",
|
|
22
|
+
"goal_milestone",
|
|
23
|
+
"delivery",
|
|
24
|
+
"quiet_reflection",
|
|
25
|
+
];
|
|
26
|
+
return keyKinds.includes(item.kind);
|
|
27
|
+
}
|
|
28
|
+
function isHighConfidence(item) {
|
|
29
|
+
return (item.confidence ?? 0) >= 0.7;
|
|
30
|
+
}
|
|
31
|
+
export function sampleDreamInput(input) {
|
|
32
|
+
const limit = input.evidenceLimit ?? DEFAULT_EVIDENCE_LIMIT;
|
|
33
|
+
// Priority: recent 7 days + key events + high confidence
|
|
34
|
+
const withPriority = input.evidenceSummaries.map((e) => ({
|
|
35
|
+
...e,
|
|
36
|
+
priority: (isWithinDays(e.createdAt, RECENT_DAYS) ? 4 : 0) +
|
|
37
|
+
(isKeyEvent(e) ? 2 : 0) +
|
|
38
|
+
(isHighConfidence(e) ? 1 : 0),
|
|
39
|
+
}));
|
|
40
|
+
// Sort by priority desc, then createdAt desc
|
|
41
|
+
withPriority.sort((a, b) => {
|
|
42
|
+
if (b.priority !== a.priority)
|
|
43
|
+
return b.priority - a.priority;
|
|
44
|
+
return b.createdAt.localeCompare(a.createdAt);
|
|
45
|
+
});
|
|
46
|
+
const sampledEvidence = withPriority.slice(0, limit);
|
|
47
|
+
const sampledEvidenceIds = sampledEvidence.map((e) => e.id);
|
|
48
|
+
const droppedCount = input.evidenceSummaries.length - sampledEvidence.length;
|
|
49
|
+
// Chronicle is usually small; keep all unless it also exceeds limit
|
|
50
|
+
let sampledChronicleIds = input.chronicleSummaries.map((c) => c.id);
|
|
51
|
+
if (sampledChronicleIds.length > limit) {
|
|
52
|
+
sampledChronicleIds = sampledChronicleIds
|
|
53
|
+
.sort((a, b) => b.localeCompare(a))
|
|
54
|
+
.slice(0, limit);
|
|
55
|
+
}
|
|
56
|
+
const reason = droppedCount > 0
|
|
57
|
+
? `sampled_${sampledEvidenceIds.length}_of_${input.evidenceSummaries.length}_evidence;priority_recent+key+confidence`
|
|
58
|
+
: "no_sampling_needed";
|
|
59
|
+
return {
|
|
60
|
+
sampledEvidenceIds,
|
|
61
|
+
sampledChronicleIds,
|
|
62
|
+
droppedCount,
|
|
63
|
+
reason,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dream System core types.
|
|
3
|
+
*
|
|
4
|
+
* Dream is an async memory consolidation job. It reads source-backed life evidence,
|
|
5
|
+
* session chronicle, and existing memory store, then produces a candidate MemoryStore
|
|
6
|
+
* with canonical entries, insights, and optional narrative/relationship update proposals.
|
|
7
|
+
*
|
|
8
|
+
* Contract: input store is immutable; output is always candidate until validated and accepted.
|
|
9
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
10
|
+
*/
|
|
11
|
+
import type { CanonicalMemoryEntry, DreamInsight } from "../storage/memory-store/memory-store-lifecycle.js";
|
|
12
|
+
export type { DreamInsight };
|
|
13
|
+
export type DreamTriggerKind = "scheduled" | "evidence_threshold" | "manual" | "maintenance" | "quiet_completion";
|
|
14
|
+
export type DreamRunStatus = "queued" | "running" | "completed" | "skipped" | "failed";
|
|
15
|
+
export type DreamOutputStatus = "candidate" | "accepted" | "archived" | "partial";
|
|
16
|
+
export type DreamMode = "rules_only" | "hybrid_llm" | "model_skipped";
|
|
17
|
+
export interface DreamRun {
|
|
18
|
+
runId: string;
|
|
19
|
+
traceId: string;
|
|
20
|
+
triggerKind: DreamTriggerKind;
|
|
21
|
+
status: DreamRunStatus;
|
|
22
|
+
mode: DreamMode;
|
|
23
|
+
startedAt: string;
|
|
24
|
+
finishedAt?: string;
|
|
25
|
+
inputMemoryStoreId?: string;
|
|
26
|
+
outputMemoryStoreId?: string;
|
|
27
|
+
fallbackReason?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ToolExperienceSummary {
|
|
30
|
+
connectorId: string;
|
|
31
|
+
capabilityId: string;
|
|
32
|
+
outcome: string;
|
|
33
|
+
count: number;
|
|
34
|
+
lastRecordedAt: string;
|
|
35
|
+
}
|
|
36
|
+
export interface DreamInputBundle {
|
|
37
|
+
evidenceRefs: string[];
|
|
38
|
+
chronicleEntryIds: string[];
|
|
39
|
+
activeMemoryStoreId?: string;
|
|
40
|
+
narrativeSnapshotId?: string;
|
|
41
|
+
relationshipSnapshotId?: string;
|
|
42
|
+
goalSnapshotIds: string[];
|
|
43
|
+
toolExperienceSummaries?: ToolExperienceSummary[];
|
|
44
|
+
inputCounts: {
|
|
45
|
+
evidence: number;
|
|
46
|
+
chronicle: number;
|
|
47
|
+
memoryEntries: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export interface DreamNarrativeUpdate {
|
|
51
|
+
focus: string;
|
|
52
|
+
progressAdditions: string[];
|
|
53
|
+
nextIntent: string;
|
|
54
|
+
confidenceDelta: number;
|
|
55
|
+
sourceRefs: string[];
|
|
56
|
+
unsupportedClaims: string[];
|
|
57
|
+
}
|
|
58
|
+
export interface DreamRelationshipUpdate {
|
|
59
|
+
toneDelta?: string;
|
|
60
|
+
timingDelta?: string;
|
|
61
|
+
topicDelta?: string;
|
|
62
|
+
sourceRefs: string[];
|
|
63
|
+
confidence: number;
|
|
64
|
+
}
|
|
65
|
+
export interface DreamOutputValidation {
|
|
66
|
+
schemaValid: boolean;
|
|
67
|
+
sourceGrounded: boolean;
|
|
68
|
+
sensitivityClean: boolean;
|
|
69
|
+
unsupportedClaims: string[];
|
|
70
|
+
errors: string[];
|
|
71
|
+
checkedAt: string;
|
|
72
|
+
}
|
|
73
|
+
export interface DreamOutput {
|
|
74
|
+
outputId: string;
|
|
75
|
+
runId: string;
|
|
76
|
+
status: DreamOutputStatus;
|
|
77
|
+
inputMemoryStoreId?: string;
|
|
78
|
+
canonicalEntries: CanonicalMemoryEntry[];
|
|
79
|
+
insights: DreamInsight[];
|
|
80
|
+
narrativeUpdate?: DreamNarrativeUpdate;
|
|
81
|
+
relationshipUpdate?: DreamRelationshipUpdate;
|
|
82
|
+
validation: DreamOutputValidation;
|
|
83
|
+
}
|
|
84
|
+
export interface DreamTrace {
|
|
85
|
+
traceId: string;
|
|
86
|
+
runId: string;
|
|
87
|
+
startedAt: string;
|
|
88
|
+
finishedAt: string;
|
|
89
|
+
durationMs: number;
|
|
90
|
+
llmCostUsd?: number;
|
|
91
|
+
inputCounts: DreamInputBundle["inputCounts"];
|
|
92
|
+
fallbackReason?: string;
|
|
93
|
+
validationErrors?: string[];
|
|
94
|
+
timeoutMs?: number;
|
|
95
|
+
sensitivityFailure?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface DreamRunResult {
|
|
98
|
+
runId: string;
|
|
99
|
+
status: DreamRunStatus;
|
|
100
|
+
output?: DreamOutput;
|
|
101
|
+
trace: DreamTrace;
|
|
102
|
+
fallbackReason?: string;
|
|
103
|
+
}
|
|
104
|
+
export interface DreamStatePort {
|
|
105
|
+
loadDreamInputs(query: {
|
|
106
|
+
timeWindowDays?: number;
|
|
107
|
+
evidenceLimit?: number;
|
|
108
|
+
}): Promise<DreamInputBundle>;
|
|
109
|
+
writeDreamOutput(output: DreamOutput): Promise<{
|
|
110
|
+
outputId: string;
|
|
111
|
+
status: "acknowledged" | "degraded";
|
|
112
|
+
}>;
|
|
113
|
+
markDreamOutputLifecycle(input: {
|
|
114
|
+
outputId: string;
|
|
115
|
+
newStatus: DreamOutputStatus;
|
|
116
|
+
validation?: DreamOutputValidation;
|
|
117
|
+
updatedAt: string;
|
|
118
|
+
}): Promise<{
|
|
119
|
+
outputId: string;
|
|
120
|
+
status: "acknowledged" | "degraded";
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Brand type: evidence bundle that has passed through RedactionGate.
|
|
125
|
+
* TypeScript prevents passing un-redacted data to ModelAssistPort.
|
|
126
|
+
*/
|
|
127
|
+
export interface RedactedEvidenceBundle {
|
|
128
|
+
readonly _brand: "redacted";
|
|
129
|
+
readonly evidence: readonly string[];
|
|
130
|
+
readonly chronicle: readonly string[];
|
|
131
|
+
readonly memory?: readonly string[];
|
|
132
|
+
}
|
|
133
|
+
export interface ModelAssistPort {
|
|
134
|
+
/** Only accepts RedactedEvidenceBundle — TypeScript enforces prior redaction (DR-027). */
|
|
135
|
+
extractInsights(input: RedactedEvidenceBundle): Promise<{
|
|
136
|
+
insights: DreamInsight[];
|
|
137
|
+
narrativeUpdate?: DreamNarrativeUpdate;
|
|
138
|
+
relationshipUpdate?: DreamRelationshipUpdate;
|
|
139
|
+
unsupportedClaims: string[];
|
|
140
|
+
costUsd?: number;
|
|
141
|
+
}>;
|
|
142
|
+
}
|
|
143
|
+
/** @deprecated Use ModelAssistPort with RedactedEvidenceBundle (DR-027). */
|
|
144
|
+
export interface DreamModelPort {
|
|
145
|
+
extractInsights(input: {
|
|
146
|
+
sampledEvidence: string[];
|
|
147
|
+
chronicleSummary: string;
|
|
148
|
+
activeMemorySummary?: string;
|
|
149
|
+
redacted: boolean;
|
|
150
|
+
}): Promise<{
|
|
151
|
+
insights: DreamInsight[];
|
|
152
|
+
narrativeUpdate?: DreamNarrativeUpdate;
|
|
153
|
+
relationshipUpdate?: DreamRelationshipUpdate;
|
|
154
|
+
unsupportedClaims: string[];
|
|
155
|
+
costUsd?: number;
|
|
156
|
+
}>;
|
|
157
|
+
}
|
|
158
|
+
export interface DreamTracePort {
|
|
159
|
+
recordDreamTrace(trace: DreamTrace): Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
export interface DreamBudgetPort {
|
|
162
|
+
checkBudget(costEstimateUsd: number): Promise<{
|
|
163
|
+
allowed: boolean;
|
|
164
|
+
remainingUsd: number;
|
|
165
|
+
}>;
|
|
166
|
+
}
|
|
167
|
+
export interface DreamEngineInput {
|
|
168
|
+
runId: string;
|
|
169
|
+
traceId: string;
|
|
170
|
+
triggerKind: DreamTriggerKind;
|
|
171
|
+
statePort: DreamStatePort;
|
|
172
|
+
/** @deprecated Use modelAssistPort with RedactedEvidenceBundle (DR-027). */
|
|
173
|
+
modelPort?: DreamModelPort;
|
|
174
|
+
/**
|
|
175
|
+
* v7 ModelAssistPort — requires RedactedEvidenceBundle (DR-027).
|
|
176
|
+
* If both modelAssistPort and modelPort are provided, modelAssistPort takes precedence.
|
|
177
|
+
*/
|
|
178
|
+
modelAssistPort?: ModelAssistPort;
|
|
179
|
+
tracePort?: DreamTracePort;
|
|
180
|
+
budgetPort?: DreamBudgetPort;
|
|
181
|
+
options?: {
|
|
182
|
+
timeWindowDays?: number;
|
|
183
|
+
evidenceLimit?: number;
|
|
184
|
+
maxCanonicalEntries?: number;
|
|
185
|
+
operatorTimeoutMs?: number;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dream System core types.
|
|
3
|
+
*
|
|
4
|
+
* Dream is an async memory consolidation job. It reads source-backed life evidence,
|
|
5
|
+
* session chronicle, and existing memory store, then produces a candidate MemoryStore
|
|
6
|
+
* with canonical entries, insights, and optional narrative/relationship update proposals.
|
|
7
|
+
*
|
|
8
|
+
* Contract: input store is immutable; output is always candidate until validated and accepted.
|
|
9
|
+
* Test coverage: tests/integration/dream/t7-1-1-dream-pipeline.test.ts
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { buildOutputGuard } from "./output-guard.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { buildOutputGuard, buildExpressionBoundary } from "./output-guard.js";
|
|
2
|
+
import { getShortAtmosphereTemplate } from "./template-registry.js";
|
|
3
|
+
export function buildMinimalGuidanceFallback(sceneContext) {
|
|
4
|
+
const atmosphereTemplate = getShortAtmosphereTemplate(sceneContext.mode, sceneContext.riskLevel);
|
|
5
|
+
return {
|
|
6
|
+
scene: sceneContext,
|
|
7
|
+
atmosphere: {
|
|
8
|
+
kind: "atmosphere",
|
|
9
|
+
text: atmosphereTemplate.text,
|
|
10
|
+
openness: sceneContext.mode === "quiet" ? "quiet" : sceneContext.riskLevel === "high" ? "narrow" : "open",
|
|
11
|
+
pressureLabels: [sceneContext.mode, sceneContext.riskLevel ?? "unknown_risk"],
|
|
12
|
+
reviewStatus: atmosphereTemplate.reviewStatus,
|
|
13
|
+
},
|
|
14
|
+
impulses: [],
|
|
15
|
+
personaReinforcement: [],
|
|
16
|
+
outputGuard: buildOutputGuard(sceneContext.sceneType),
|
|
17
|
+
expressionBoundary: buildExpressionBoundary(sceneContext.sceneType),
|
|
18
|
+
minimal: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -1,74 +1,76 @@
|
|
|
1
|
-
import { buildMinimalGuidanceFallback } from "./fallback.js";
|
|
2
|
-
import { buildOutputGuard } from "./output-guard.js";
|
|
3
|
-
import { selectPersonaSnippets } from "./persona-selection.js";
|
|
4
|
-
import {
|
|
5
|
-
import { assembleImpulse } from "./impulse-assembler.js";
|
|
6
|
-
async function buildAtmosphere(sceneContext) {
|
|
7
|
-
const template =
|
|
8
|
-
return {
|
|
9
|
-
kind: "atmosphere",
|
|
10
|
-
text: template.text,
|
|
11
|
-
openness: sceneContext.mode === "quiet" ? "quiet" : sceneContext.riskLevel === "high" ? "narrow" : "open",
|
|
12
|
-
pressureLabels: [sceneContext.mode, sceneContext.riskLevel ?? "unknown_risk"],
|
|
13
|
-
reviewStatus: template.reviewStatus,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Select impulses using the dual-axis capabilityClass assembler (T-V7C.C.4R).
|
|
18
|
-
*
|
|
19
|
-
* Fallback chain: platform-specific → capabilityClass preset → intentKind → []
|
|
20
|
-
*/
|
|
21
|
-
async function selectImpulses(sceneContext, deps) {
|
|
22
|
-
if (sceneContext.sceneType === "explain" || sceneContext.sceneType === "user_reply") {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
const result = await assembleImpulse({
|
|
26
|
-
sceneType: sceneContext.sceneType,
|
|
27
|
-
capabilityIntent: sceneContext.capabilityIntent,
|
|
28
|
-
platformId: sceneContext.platformId,
|
|
29
|
-
}, deps);
|
|
30
|
-
return result.impulse ? [result.impulse] : [];
|
|
31
|
-
}
|
|
32
|
-
export async function assembleGuidance(input) {
|
|
33
|
-
if (!input.sceneContext) {
|
|
34
|
-
return {
|
|
35
|
-
available: false,
|
|
36
|
-
reason: "missing_scene_context",
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const sceneContext = input.sceneContext;
|
|
40
|
-
const deps = { platformImpulsePort: input.platformImpulsePort };
|
|
41
|
-
try {
|
|
42
|
-
const [atmosphere, impulses] = await Promise.all([
|
|
43
|
-
buildAtmosphere(sceneContext),
|
|
44
|
-
selectImpulses(sceneContext, deps),
|
|
45
|
-
]);
|
|
46
|
-
const personaDecision = selectPersonaSnippets({
|
|
47
|
-
sceneContext,
|
|
48
|
-
candidates: input.personaCandidates ?? [],
|
|
49
|
-
});
|
|
50
|
-
return {
|
|
51
|
-
scene: sceneContext,
|
|
52
|
-
atmosphere,
|
|
53
|
-
impulses,
|
|
54
|
-
personaReinforcement: personaDecision.snippets,
|
|
55
|
-
outputGuard: buildOutputGuard(sceneContext.sceneType),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
1
|
+
import { buildMinimalGuidanceFallback } from "./fallback.js";
|
|
2
|
+
import { buildOutputGuard, buildExpressionBoundary } from "./output-guard.js";
|
|
3
|
+
import { selectPersonaSnippets } from "./persona-selection.js";
|
|
4
|
+
import { getShortAtmosphereTemplate } from "./template-registry.js";
|
|
5
|
+
import { assembleImpulse } from "./impulse-assembler.js";
|
|
6
|
+
async function buildAtmosphere(sceneContext) {
|
|
7
|
+
const template = getShortAtmosphereTemplate(sceneContext.mode, sceneContext.riskLevel);
|
|
8
|
+
return {
|
|
9
|
+
kind: "atmosphere",
|
|
10
|
+
text: template.text,
|
|
11
|
+
openness: sceneContext.mode === "quiet" ? "quiet" : sceneContext.riskLevel === "high" ? "narrow" : "open",
|
|
12
|
+
pressureLabels: [sceneContext.mode, sceneContext.riskLevel ?? "unknown_risk"],
|
|
13
|
+
reviewStatus: template.reviewStatus,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Select impulses using the dual-axis capabilityClass assembler (T-V7C.C.4R).
|
|
18
|
+
*
|
|
19
|
+
* Fallback chain: platform-specific → capabilityClass preset → intentKind → []
|
|
20
|
+
*/
|
|
21
|
+
async function selectImpulses(sceneContext, deps) {
|
|
22
|
+
if (sceneContext.sceneType === "explain" || sceneContext.sceneType === "user_reply") {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const result = await assembleImpulse({
|
|
26
|
+
sceneType: sceneContext.sceneType,
|
|
27
|
+
capabilityIntent: sceneContext.capabilityIntent,
|
|
28
|
+
platformId: sceneContext.platformId,
|
|
29
|
+
}, deps);
|
|
30
|
+
return result.impulse ? [result.impulse] : [];
|
|
31
|
+
}
|
|
32
|
+
export async function assembleGuidance(input) {
|
|
33
|
+
if (!input.sceneContext) {
|
|
34
|
+
return {
|
|
35
|
+
available: false,
|
|
36
|
+
reason: "missing_scene_context",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const sceneContext = input.sceneContext;
|
|
40
|
+
const deps = { platformImpulsePort: input.platformImpulsePort };
|
|
41
|
+
try {
|
|
42
|
+
const [atmosphere, impulses] = await Promise.all([
|
|
43
|
+
buildAtmosphere(sceneContext),
|
|
44
|
+
selectImpulses(sceneContext, deps),
|
|
45
|
+
]);
|
|
46
|
+
const personaDecision = selectPersonaSnippets({
|
|
47
|
+
sceneContext,
|
|
48
|
+
candidates: input.personaCandidates ?? [],
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
scene: sceneContext,
|
|
52
|
+
atmosphere,
|
|
53
|
+
impulses,
|
|
54
|
+
personaReinforcement: personaDecision.snippets,
|
|
55
|
+
outputGuard: buildOutputGuard(sceneContext.sceneType),
|
|
56
|
+
expressionBoundary: buildExpressionBoundary(sceneContext.sceneType),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
if ((input.personaCandidates ?? []).length === 0) {
|
|
61
|
+
const fallback = buildMinimalGuidanceFallback(sceneContext);
|
|
62
|
+
return {
|
|
63
|
+
scene: fallback.scene,
|
|
64
|
+
atmosphere: fallback.atmosphere,
|
|
65
|
+
impulses: fallback.impulses,
|
|
66
|
+
personaReinforcement: fallback.personaReinforcement,
|
|
67
|
+
outputGuard: fallback.outputGuard,
|
|
68
|
+
expressionBoundary: fallback.expressionBoundary,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
available: false,
|
|
73
|
+
reason: "missing_template",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { GuardBlock, GuidanceSceneType } from "./types.js";
|
|
2
|
-
export type OutputGuardConstraintId = "avoid_customer_service_tone" | "avoid_daily_report_tone" | "avoid_teaching_template_tone" | "avoid_fabricated_experience" | "avoid_repetitive_phrasing";
|
|
3
|
-
export interface OutputGuardDefinition {
|
|
4
|
-
sceneType: GuidanceSceneType;
|
|
5
|
-
constraints: OutputGuardConstraintId[];
|
|
6
|
-
hardGuardPriority: true;
|
|
7
|
-
note: "output_guard_only_shapes_expression";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export declare function
|
|
1
|
+
import type { GuardBlock, ExpressionBoundaryBlock, GuidanceSceneType } from "./types.js";
|
|
2
|
+
export type OutputGuardConstraintId = "avoid_customer_service_tone" | "avoid_daily_report_tone" | "avoid_teaching_template_tone" | "avoid_fabricated_experience" | "avoid_repetitive_phrasing";
|
|
3
|
+
export interface OutputGuardDefinition {
|
|
4
|
+
sceneType: GuidanceSceneType;
|
|
5
|
+
constraints: OutputGuardConstraintId[];
|
|
6
|
+
hardGuardPriority: true;
|
|
7
|
+
note: "output_guard_only_shapes_expression";
|
|
8
|
+
}
|
|
9
|
+
/** @deprecated Use buildExpressionBoundary for new code. Kept for backward compatibility. */
|
|
10
|
+
export declare function buildOutputGuard(sceneType: GuidanceSceneType): GuardBlock;
|
|
11
|
+
export declare function getOutputGuardDefinition(sceneType: GuidanceSceneType): OutputGuardDefinition;
|
|
12
|
+
export type ExpressionConstraintId = "avoid_customer_service_tone" | "avoid_daily_report_tone" | "avoid_teaching_template_tone" | "avoid_fabricated_experience" | "avoid_repetitive_phrasing";
|
|
13
|
+
export declare function buildExpressionBoundary(_sceneType: GuidanceSceneType): ExpressionBoundaryBlock;
|
|
@@ -1,29 +1,53 @@
|
|
|
1
|
-
const SHARED_CONSTRAINTS = [
|
|
2
|
-
"avoid_customer_service_tone",
|
|
3
|
-
"avoid_daily_report_tone",
|
|
4
|
-
"avoid_teaching_template_tone",
|
|
5
|
-
"avoid_fabricated_experience",
|
|
6
|
-
"avoid_repetitive_phrasing",
|
|
7
|
-
];
|
|
8
|
-
const SCENE_NOTES = {
|
|
9
|
-
avoid_customer_service_tone: "不要把自己说成客服或通知系统。",
|
|
10
|
-
avoid_daily_report_tone: "不要把表达压扁成日报、周报或例行播报。",
|
|
11
|
-
avoid_teaching_template_tone: "不要把表达写成教程、步骤说明或培训手册。",
|
|
12
|
-
avoid_fabricated_experience: "不要虚构经历、关系、情绪事件或未发生的观察。",
|
|
13
|
-
avoid_repetitive_phrasing: "不要滑进高重复、硬模板化或近似复读的措辞。",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
const SHARED_CONSTRAINTS = [
|
|
2
|
+
"avoid_customer_service_tone",
|
|
3
|
+
"avoid_daily_report_tone",
|
|
4
|
+
"avoid_teaching_template_tone",
|
|
5
|
+
"avoid_fabricated_experience",
|
|
6
|
+
"avoid_repetitive_phrasing",
|
|
7
|
+
];
|
|
8
|
+
const SCENE_NOTES = {
|
|
9
|
+
avoid_customer_service_tone: "不要把自己说成客服或通知系统。",
|
|
10
|
+
avoid_daily_report_tone: "不要把表达压扁成日报、周报或例行播报。",
|
|
11
|
+
avoid_teaching_template_tone: "不要把表达写成教程、步骤说明或培训手册。",
|
|
12
|
+
avoid_fabricated_experience: "不要虚构经历、关系、情绪事件或未发生的观察。",
|
|
13
|
+
avoid_repetitive_phrasing: "不要滑进高重复、硬模板化或近似复读的措辞。",
|
|
14
|
+
};
|
|
15
|
+
/** @deprecated Use buildExpressionBoundary for new code. Kept for backward compatibility. */
|
|
16
|
+
export function buildOutputGuard(sceneType) {
|
|
17
|
+
return {
|
|
18
|
+
kind: "output_guard",
|
|
19
|
+
constraints: SHARED_CONSTRAINTS.map((constraint) => SCENE_NOTES[constraint]),
|
|
20
|
+
hardGuardPriority: true,
|
|
21
|
+
_semanticNote: "output_guard_only_shapes_expression",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function getOutputGuardDefinition(sceneType) {
|
|
25
|
+
return {
|
|
26
|
+
sceneType,
|
|
27
|
+
constraints: [...SHARED_CONSTRAINTS],
|
|
28
|
+
hardGuardPriority: true,
|
|
29
|
+
note: "output_guard_only_shapes_expression",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const EXPRESSION_CONSTRAINTS = [
|
|
33
|
+
"avoid_customer_service_tone",
|
|
34
|
+
"avoid_daily_report_tone",
|
|
35
|
+
"avoid_teaching_template_tone",
|
|
36
|
+
"avoid_fabricated_experience",
|
|
37
|
+
"avoid_repetitive_phrasing",
|
|
38
|
+
];
|
|
39
|
+
const EXPRESSION_NOTES = {
|
|
40
|
+
avoid_customer_service_tone: "避免客服腔或通知系统语气。",
|
|
41
|
+
avoid_daily_report_tone: "避免日报、周报或例行播报腔。",
|
|
42
|
+
avoid_teaching_template_tone: "避免教程、步骤说明或培训手册腔。",
|
|
43
|
+
avoid_fabricated_experience: "避免虚构经历、关系、情绪事件或未发生的观察。",
|
|
44
|
+
avoid_repetitive_phrasing: "避免高重复、硬模板化或近似复读的措辞。",
|
|
45
|
+
};
|
|
46
|
+
export function buildExpressionBoundary(_sceneType) {
|
|
47
|
+
return {
|
|
48
|
+
kind: "expression_boundary",
|
|
49
|
+
constraints: EXPRESSION_CONSTRAINTS.map((c) => EXPRESSION_NOTES[c]),
|
|
50
|
+
style: "avoid_prefer",
|
|
51
|
+
ownership: "behavioral_guidance_system",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import type { AtmosphereBlock, GuidanceSceneType, ImpulseBlock, ImpulseKind } from "./types.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import type { AtmosphereBlock, GuidanceSceneType, ImpulseBlock, ImpulseKind, GuidanceMode, GuidanceRiskLevel } from "./types.js";
|
|
2
|
+
export declare function getShortAtmosphereText(mode: GuidanceMode, riskLevel: GuidanceRiskLevel | undefined): string;
|
|
3
|
+
type CoreSceneKind = Exclude<GuidanceSceneType, "explain" | "user_reply">;
|
|
4
|
+
/** @deprecated Use getShortAtmosphereTemplate for production contexts. Kept for compatibility. */
|
|
5
|
+
export declare function getBaselineAtmosphereTemplate(): Pick<AtmosphereBlock, "kind" | "text" | "reviewStatus">;
|
|
6
|
+
/** T-V7C.C.7: Short constraint atmosphere (production default). */
|
|
7
|
+
export declare function getShortAtmosphereTemplate(mode: GuidanceMode, riskLevel: GuidanceRiskLevel | undefined): Pick<AtmosphereBlock, "kind" | "text" | "reviewStatus">;
|
|
8
|
+
export declare function getImpulseTemplate(sceneType: CoreSceneKind): ImpulseBlock;
|
|
9
|
+
/**
|
|
10
|
+
* Get impulse template for capability-class-derived ImpulseKinds (explore / work).
|
|
11
|
+
*
|
|
12
|
+
* Returns null when:
|
|
13
|
+
* - The kind has no registered text (pending_human_review state)
|
|
14
|
+
* - The text is explicitly marked as pending review
|
|
15
|
+
*
|
|
16
|
+
* Callers (ImpulseAssembler) must fall back gracefully to intentKind impulse
|
|
17
|
+
* or baseline atmosphere when null is returned.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getCapabilityClassImpulseTemplate(kind: ImpulseKind): ImpulseBlock | null;
|
|
20
|
+
export {};
|