@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,37 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DreamInputLoader — T-DQS.C.2 (DR-026: Idempotent Claim Loading)
|
|
3
|
-
*
|
|
4
|
-
* Core logic: Load unreferenced QuietClaims as Dream inputs.
|
|
5
|
-
*
|
|
6
|
-
* Idempotent mechanism (DR-026):
|
|
7
|
-
* - Queries daily_diary_index + life_evidence_index for candidate source refs.
|
|
8
|
-
* - Excludes refs already consumed by accepted dream_output_index projections.
|
|
9
|
-
* - When Dream lock is held, claims are queued; on next Dream run after lock release,
|
|
10
|
-
* they are automatically included (no separate "skipped" tracking needed).
|
|
11
|
-
* - Subsequent Dream runs exclude already-accepted refs, preventing re-processing.
|
|
12
|
-
*
|
|
13
|
-
* Lock semantics:
|
|
14
|
-
* - Lock TTL is 35min (enforced by DreamScheduler, not this module).
|
|
15
|
-
* - This loader only reads; lock enforcement is upstream.
|
|
16
|
-
*
|
|
17
|
-
* ToolExperience summaries:
|
|
18
|
-
* - Loads recent tool_experience records aggregated by (connector_id, capability_id, outcome).
|
|
19
|
-
* - Provides frequency count and last recorded time for Dream insight extraction.
|
|
20
|
-
*
|
|
21
|
-
* Contract:
|
|
22
|
-
* - Returns empty evidenceRefs when no unreferenced claims exist.
|
|
23
|
-
* - Never fabricates inputs; only reads from existing DB state.
|
|
24
|
-
*
|
|
25
|
-
* Performance: O(n) where n = life_evidence_index rows (capped by LIMIT).
|
|
26
|
-
* Memory: O(m) where m = deduplicated ref count (typically < evidenceLimit).
|
|
27
|
-
*
|
|
28
|
-
* Test coverage: tests/unit/dream/dream-input-loader.test.ts
|
|
29
|
-
*/
|
|
30
|
-
import type { Database } from "sql.js";
|
|
31
|
-
import type { DreamStatePort } from "./types.js";
|
|
32
|
-
export interface DreamInputLoaderOptions {
|
|
33
|
-
database: {
|
|
34
|
-
sqlite: Database;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export declare function createDreamInputLoader(options: DreamInputLoaderOptions): Pick<DreamStatePort, "loadDreamInputs">;
|
|
1
|
+
/**
|
|
2
|
+
* DreamInputLoader — T-DQS.C.2 (DR-026: Idempotent Claim Loading)
|
|
3
|
+
*
|
|
4
|
+
* Core logic: Load unreferenced QuietClaims as Dream inputs.
|
|
5
|
+
*
|
|
6
|
+
* Idempotent mechanism (DR-026):
|
|
7
|
+
* - Queries daily_diary_index + life_evidence_index for candidate source refs.
|
|
8
|
+
* - Excludes refs already consumed by accepted dream_output_index projections.
|
|
9
|
+
* - When Dream lock is held, claims are queued; on next Dream run after lock release,
|
|
10
|
+
* they are automatically included (no separate "skipped" tracking needed).
|
|
11
|
+
* - Subsequent Dream runs exclude already-accepted refs, preventing re-processing.
|
|
12
|
+
*
|
|
13
|
+
* Lock semantics:
|
|
14
|
+
* - Lock TTL is 35min (enforced by DreamScheduler, not this module).
|
|
15
|
+
* - This loader only reads; lock enforcement is upstream.
|
|
16
|
+
*
|
|
17
|
+
* ToolExperience summaries:
|
|
18
|
+
* - Loads recent tool_experience records aggregated by (connector_id, capability_id, outcome).
|
|
19
|
+
* - Provides frequency count and last recorded time for Dream insight extraction.
|
|
20
|
+
*
|
|
21
|
+
* Contract:
|
|
22
|
+
* - Returns empty evidenceRefs when no unreferenced claims exist.
|
|
23
|
+
* - Never fabricates inputs; only reads from existing DB state.
|
|
24
|
+
*
|
|
25
|
+
* Performance: O(n) where n = life_evidence_index rows (capped by LIMIT).
|
|
26
|
+
* Memory: O(m) where m = deduplicated ref count (typically < evidenceLimit).
|
|
27
|
+
*
|
|
28
|
+
* Test coverage: tests/unit/dream/dream-input-loader.test.ts
|
|
29
|
+
*/
|
|
30
|
+
import type { Database } from "sql.js";
|
|
31
|
+
import type { DreamStatePort } from "./types.js";
|
|
32
|
+
export interface DreamInputLoaderOptions {
|
|
33
|
+
database: {
|
|
34
|
+
sqlite: Database;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export declare function createDreamInputLoader(options: DreamInputLoaderOptions): Pick<DreamStatePort, "loadDreamInputs">;
|
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DreamInputLoader — T-DQS.C.2 (DR-026: Idempotent Claim Loading)
|
|
3
|
-
*
|
|
4
|
-
* Core logic: Load unreferenced QuietClaims as Dream inputs.
|
|
5
|
-
*
|
|
6
|
-
* Idempotent mechanism (DR-026):
|
|
7
|
-
* - Queries daily_diary_index + life_evidence_index for candidate source refs.
|
|
8
|
-
* - Excludes refs already consumed by accepted dream_output_index projections.
|
|
9
|
-
* - When Dream lock is held, claims are queued; on next Dream run after lock release,
|
|
10
|
-
* they are automatically included (no separate "skipped" tracking needed).
|
|
11
|
-
* - Subsequent Dream runs exclude already-accepted refs, preventing re-processing.
|
|
12
|
-
*
|
|
13
|
-
* Lock semantics:
|
|
14
|
-
* - Lock TTL is 35min (enforced by DreamScheduler, not this module).
|
|
15
|
-
* - This loader only reads; lock enforcement is upstream.
|
|
16
|
-
*
|
|
17
|
-
* ToolExperience summaries:
|
|
18
|
-
* - Loads recent tool_experience records aggregated by (connector_id, capability_id, outcome).
|
|
19
|
-
* - Provides frequency count and last recorded time for Dream insight extraction.
|
|
20
|
-
*
|
|
21
|
-
* Contract:
|
|
22
|
-
* - Returns empty evidenceRefs when no unreferenced claims exist.
|
|
23
|
-
* - Never fabricates inputs; only reads from existing DB state.
|
|
24
|
-
*
|
|
25
|
-
* Performance: O(n) where n = life_evidence_index rows (capped by LIMIT).
|
|
26
|
-
* Memory: O(m) where m = deduplicated ref count (typically < evidenceLimit).
|
|
27
|
-
*
|
|
28
|
-
* Test coverage: tests/unit/dream/dream-input-loader.test.ts
|
|
29
|
-
*/
|
|
30
|
-
function safeParseJson(json, fallback) {
|
|
31
|
-
try {
|
|
32
|
-
const parsed = JSON.parse(json);
|
|
33
|
-
return parsed ?? fallback;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return fallback;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/** Extract ref ids from JSON that may be string[] or {id?, sourceId?}[] */
|
|
40
|
-
function extractRefIdsFromJson(json) {
|
|
41
|
-
const parsed = safeParseJson(json, []);
|
|
42
|
-
if (!Array.isArray(parsed))
|
|
43
|
-
return [];
|
|
44
|
-
const ids = [];
|
|
45
|
-
for (const item of parsed) {
|
|
46
|
-
if (typeof item === "string") {
|
|
47
|
-
ids.push(item);
|
|
48
|
-
}
|
|
49
|
-
else if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
50
|
-
const obj = item;
|
|
51
|
-
if (typeof obj.id === "string")
|
|
52
|
-
ids.push(obj.id);
|
|
53
|
-
if (typeof obj.sourceId === "string")
|
|
54
|
-
ids.push(obj.sourceId);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return ids;
|
|
58
|
-
}
|
|
59
|
-
/** Extract consumed ref ids from canonical_entries_json (CanonicalMemoryEntry[]) */
|
|
60
|
-
function extractConsumedRefIdsFromEntriesJson(json) {
|
|
61
|
-
const entries = safeParseJson(json, []);
|
|
62
|
-
if (!Array.isArray(entries))
|
|
63
|
-
return [];
|
|
64
|
-
const ids = [];
|
|
65
|
-
for (const entry of entries) {
|
|
66
|
-
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
67
|
-
const sourceRefs = entry.sourceRefs;
|
|
68
|
-
if (Array.isArray(sourceRefs)) {
|
|
69
|
-
for (const sr of sourceRefs) {
|
|
70
|
-
if (typeof sr === "string") {
|
|
71
|
-
ids.push(sr);
|
|
72
|
-
}
|
|
73
|
-
else if (sr && typeof sr === "object" && !Array.isArray(sr)) {
|
|
74
|
-
const obj = sr;
|
|
75
|
-
if (typeof obj.sourceId === "string")
|
|
76
|
-
ids.push(obj.sourceId);
|
|
77
|
-
if (typeof obj.id === "string")
|
|
78
|
-
ids.push(obj.id);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return ids;
|
|
85
|
-
}
|
|
86
|
-
export function createDreamInputLoader(options) {
|
|
87
|
-
const { sqlite } = options.database;
|
|
88
|
-
return {
|
|
89
|
-
// async aligns with DreamStatePort.loadDreamInputs signature (Promise<DreamInputBundle>).
|
|
90
|
-
// All current operations are synchronous (sql.js in-memory), but the contract
|
|
91
|
-
// reserves the right to use async DB drivers in the future.
|
|
92
|
-
async loadDreamInputs(query = {}) {
|
|
93
|
-
// Defaults from 05A_TASKS.md T-DQS.C.2 and dream-quiet-system.md §10.2
|
|
94
|
-
const timeWindowDays = query.timeWindowDays ?? 30;
|
|
95
|
-
const evidenceLimit = query.evidenceLimit ?? 1000;
|
|
96
|
-
const since = new Date(Date.now() - timeWindowDays * 24 * 60 * 60 * 1000).toISOString();
|
|
97
|
-
// ─── 1. Collect candidate ref ids from daily_diary_index ─────────────────
|
|
98
|
-
const candidateRefs = new Set();
|
|
99
|
-
const diaryResult = sqlite.exec(`SELECT source_refs_json FROM daily_diary_index WHERE created_at >= ? ORDER BY created_at DESC`, [since]);
|
|
100
|
-
for (const row of diaryResult[0]?.values ?? []) {
|
|
101
|
-
for (const id of extractRefIdsFromJson(String(row[0]))) {
|
|
102
|
-
candidateRefs.add(id);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
// ─── 2. Collect candidate ref ids from life_evidence_index ───────────────
|
|
106
|
-
const evidenceResult = sqlite.exec(`SELECT source_refs_json FROM life_evidence_index WHERE timestamp >= ? ORDER BY timestamp DESC LIMIT ?`, [since, evidenceLimit]);
|
|
107
|
-
for (const row of evidenceResult[0]?.values ?? []) {
|
|
108
|
-
for (const id of extractRefIdsFromJson(String(row[0]))) {
|
|
109
|
-
candidateRefs.add(id);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// ─── 3. Collect consumed refs from accepted dream outputs ────────────────
|
|
113
|
-
const consumedRefs = new Set();
|
|
114
|
-
const acceptedResult = sqlite.exec(`SELECT canonical_entries_json FROM dream_output_index WHERE status = 'accepted'`);
|
|
115
|
-
for (const row of acceptedResult[0]?.values ?? []) {
|
|
116
|
-
for (const id of extractConsumedRefIdsFromEntriesJson(String(row[0]))) {
|
|
117
|
-
consumedRefs.add(id);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// ─── 4. Filter: keep only refs not consumed by accepted projections ──────
|
|
121
|
-
const evidenceRefs = [...candidateRefs].filter((ref) => !consumedRefs.has(ref));
|
|
122
|
-
// ─── 5. Load ToolExperience summaries (aggregated by connector/capability/outcome) ─
|
|
1
|
+
/**
|
|
2
|
+
* DreamInputLoader — T-DQS.C.2 (DR-026: Idempotent Claim Loading)
|
|
3
|
+
*
|
|
4
|
+
* Core logic: Load unreferenced QuietClaims as Dream inputs.
|
|
5
|
+
*
|
|
6
|
+
* Idempotent mechanism (DR-026):
|
|
7
|
+
* - Queries daily_diary_index + life_evidence_index for candidate source refs.
|
|
8
|
+
* - Excludes refs already consumed by accepted dream_output_index projections.
|
|
9
|
+
* - When Dream lock is held, claims are queued; on next Dream run after lock release,
|
|
10
|
+
* they are automatically included (no separate "skipped" tracking needed).
|
|
11
|
+
* - Subsequent Dream runs exclude already-accepted refs, preventing re-processing.
|
|
12
|
+
*
|
|
13
|
+
* Lock semantics:
|
|
14
|
+
* - Lock TTL is 35min (enforced by DreamScheduler, not this module).
|
|
15
|
+
* - This loader only reads; lock enforcement is upstream.
|
|
16
|
+
*
|
|
17
|
+
* ToolExperience summaries:
|
|
18
|
+
* - Loads recent tool_experience records aggregated by (connector_id, capability_id, outcome).
|
|
19
|
+
* - Provides frequency count and last recorded time for Dream insight extraction.
|
|
20
|
+
*
|
|
21
|
+
* Contract:
|
|
22
|
+
* - Returns empty evidenceRefs when no unreferenced claims exist.
|
|
23
|
+
* - Never fabricates inputs; only reads from existing DB state.
|
|
24
|
+
*
|
|
25
|
+
* Performance: O(n) where n = life_evidence_index rows (capped by LIMIT).
|
|
26
|
+
* Memory: O(m) where m = deduplicated ref count (typically < evidenceLimit).
|
|
27
|
+
*
|
|
28
|
+
* Test coverage: tests/unit/dream/dream-input-loader.test.ts
|
|
29
|
+
*/
|
|
30
|
+
function safeParseJson(json, fallback) {
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(json);
|
|
33
|
+
return parsed ?? fallback;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return fallback;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Extract ref ids from JSON that may be string[] or {id?, sourceId?}[] */
|
|
40
|
+
function extractRefIdsFromJson(json) {
|
|
41
|
+
const parsed = safeParseJson(json, []);
|
|
42
|
+
if (!Array.isArray(parsed))
|
|
43
|
+
return [];
|
|
44
|
+
const ids = [];
|
|
45
|
+
for (const item of parsed) {
|
|
46
|
+
if (typeof item === "string") {
|
|
47
|
+
ids.push(item);
|
|
48
|
+
}
|
|
49
|
+
else if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
50
|
+
const obj = item;
|
|
51
|
+
if (typeof obj.id === "string")
|
|
52
|
+
ids.push(obj.id);
|
|
53
|
+
if (typeof obj.sourceId === "string")
|
|
54
|
+
ids.push(obj.sourceId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return ids;
|
|
58
|
+
}
|
|
59
|
+
/** Extract consumed ref ids from canonical_entries_json (CanonicalMemoryEntry[]) */
|
|
60
|
+
function extractConsumedRefIdsFromEntriesJson(json) {
|
|
61
|
+
const entries = safeParseJson(json, []);
|
|
62
|
+
if (!Array.isArray(entries))
|
|
63
|
+
return [];
|
|
64
|
+
const ids = [];
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
67
|
+
const sourceRefs = entry.sourceRefs;
|
|
68
|
+
if (Array.isArray(sourceRefs)) {
|
|
69
|
+
for (const sr of sourceRefs) {
|
|
70
|
+
if (typeof sr === "string") {
|
|
71
|
+
ids.push(sr);
|
|
72
|
+
}
|
|
73
|
+
else if (sr && typeof sr === "object" && !Array.isArray(sr)) {
|
|
74
|
+
const obj = sr;
|
|
75
|
+
if (typeof obj.sourceId === "string")
|
|
76
|
+
ids.push(obj.sourceId);
|
|
77
|
+
if (typeof obj.id === "string")
|
|
78
|
+
ids.push(obj.id);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return ids;
|
|
85
|
+
}
|
|
86
|
+
export function createDreamInputLoader(options) {
|
|
87
|
+
const { sqlite } = options.database;
|
|
88
|
+
return {
|
|
89
|
+
// async aligns with DreamStatePort.loadDreamInputs signature (Promise<DreamInputBundle>).
|
|
90
|
+
// All current operations are synchronous (sql.js in-memory), but the contract
|
|
91
|
+
// reserves the right to use async DB drivers in the future.
|
|
92
|
+
async loadDreamInputs(query = {}) {
|
|
93
|
+
// Defaults from 05A_TASKS.md T-DQS.C.2 and dream-quiet-system.md §10.2
|
|
94
|
+
const timeWindowDays = query.timeWindowDays ?? 30;
|
|
95
|
+
const evidenceLimit = query.evidenceLimit ?? 1000;
|
|
96
|
+
const since = new Date(Date.now() - timeWindowDays * 24 * 60 * 60 * 1000).toISOString();
|
|
97
|
+
// ─── 1. Collect candidate ref ids from daily_diary_index ─────────────────
|
|
98
|
+
const candidateRefs = new Set();
|
|
99
|
+
const diaryResult = sqlite.exec(`SELECT source_refs_json FROM daily_diary_index WHERE created_at >= ? ORDER BY created_at DESC`, [since]);
|
|
100
|
+
for (const row of diaryResult[0]?.values ?? []) {
|
|
101
|
+
for (const id of extractRefIdsFromJson(String(row[0]))) {
|
|
102
|
+
candidateRefs.add(id);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ─── 2. Collect candidate ref ids from life_evidence_index ───────────────
|
|
106
|
+
const evidenceResult = sqlite.exec(`SELECT source_refs_json FROM life_evidence_index WHERE timestamp >= ? ORDER BY timestamp DESC LIMIT ?`, [since, evidenceLimit]);
|
|
107
|
+
for (const row of evidenceResult[0]?.values ?? []) {
|
|
108
|
+
for (const id of extractRefIdsFromJson(String(row[0]))) {
|
|
109
|
+
candidateRefs.add(id);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// ─── 3. Collect consumed refs from accepted dream outputs ────────────────
|
|
113
|
+
const consumedRefs = new Set();
|
|
114
|
+
const acceptedResult = sqlite.exec(`SELECT canonical_entries_json FROM dream_output_index WHERE status = 'accepted'`);
|
|
115
|
+
for (const row of acceptedResult[0]?.values ?? []) {
|
|
116
|
+
for (const id of extractConsumedRefIdsFromEntriesJson(String(row[0]))) {
|
|
117
|
+
consumedRefs.add(id);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// ─── 4. Filter: keep only refs not consumed by accepted projections ──────
|
|
121
|
+
const evidenceRefs = [...candidateRefs].filter((ref) => !consumedRefs.has(ref));
|
|
122
|
+
// ─── 5. Load ToolExperience summaries (aggregated by connector/capability/outcome) ─
|
|
123
123
|
const toolExpResult = sqlite.exec(`SELECT connector_id, capability_id, outcome, COUNT(*) as count, MAX(created_at) as last_recorded_at
|
|
124
124
|
FROM tool_experience
|
|
125
125
|
WHERE created_at >= ?
|
|
126
126
|
GROUP BY connector_id, capability_id, outcome
|
|
127
127
|
ORDER BY last_recorded_at DESC
|
|
128
|
-
LIMIT ?`, [since, evidenceLimit]);
|
|
129
|
-
const toolExperienceSummaries = [];
|
|
130
|
-
for (const row of toolExpResult[0]?.values ?? []) {
|
|
131
|
-
toolExperienceSummaries.push({
|
|
132
|
-
connectorId: String(row[0]),
|
|
133
|
-
capabilityId: String(row[1]),
|
|
134
|
-
outcome: String(row[2]),
|
|
135
|
-
count: Number(row[3]),
|
|
136
|
-
lastRecordedAt: String(row[4]),
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
evidenceRefs,
|
|
141
|
-
chronicleEntryIds: [],
|
|
142
|
-
activeMemoryStoreId: undefined,
|
|
143
|
-
narrativeSnapshotId: undefined,
|
|
144
|
-
relationshipSnapshotId: undefined,
|
|
145
|
-
goalSnapshotIds: [],
|
|
146
|
-
toolExperienceSummaries,
|
|
147
|
-
inputCounts: {
|
|
148
|
-
evidence: evidenceRefs.length,
|
|
149
|
-
chronicle: 0, // T-DQS.C.2 scope: evidence only; chronicle loaded separately
|
|
150
|
-
memoryEntries: 0, // T-DQS.C.2 scope: evidence only; memory loaded separately
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
}
|
|
128
|
+
LIMIT ?`, [since, evidenceLimit]);
|
|
129
|
+
const toolExperienceSummaries = [];
|
|
130
|
+
for (const row of toolExpResult[0]?.values ?? []) {
|
|
131
|
+
toolExperienceSummaries.push({
|
|
132
|
+
connectorId: String(row[0]),
|
|
133
|
+
capabilityId: String(row[1]),
|
|
134
|
+
outcome: String(row[2]),
|
|
135
|
+
count: Number(row[3]),
|
|
136
|
+
lastRecordedAt: String(row[4]),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
evidenceRefs,
|
|
141
|
+
chronicleEntryIds: [],
|
|
142
|
+
activeMemoryStoreId: undefined,
|
|
143
|
+
narrativeSnapshotId: undefined,
|
|
144
|
+
relationshipSnapshotId: undefined,
|
|
145
|
+
goalSnapshotIds: [],
|
|
146
|
+
toolExperienceSummaries,
|
|
147
|
+
inputCounts: {
|
|
148
|
+
evidence: evidenceRefs.length,
|
|
149
|
+
chronicle: 0, // T-DQS.C.2 scope: evidence only; chronicle loaded separately
|
|
150
|
+
memoryEntries: 0, // T-DQS.C.2 scope: evidence only; memory loaded separately
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dream Scheduler
|
|
3
|
-
*
|
|
4
|
-
* Core logic: trigger Dream runs via cron schedule, evidence threshold, or manual
|
|
5
|
-
* request. Uses DreamRunLock to prevent concurrent runs on the same workspace/input
|
|
6
|
-
* window. Operator timeout is enforced via options in the engine call.
|
|
7
|
-
*
|
|
8
|
-
* - Cron: simplified — checks if a scheduled window is due (last run + interval).
|
|
9
|
-
* - Evidence threshold: triggers when evidence count exceeds threshold since last run.
|
|
10
|
-
* - Manual: always allowed if no active lock.
|
|
11
|
-
* - Lock: in-memory or port-backed; released after run completes or times out.
|
|
12
|
-
* Test coverage: tests/integration/dream/t7-1-2-dream-scheduler.test.ts
|
|
13
|
-
*/
|
|
14
|
-
import type { DreamEngineInput } from "./types.js";
|
|
15
|
-
import type { DreamTriggerKind, DreamTracePort, DreamStatePort, DreamModelPort, DreamBudgetPort, ModelAssistPort } from "./types.js";
|
|
16
|
-
export interface SchedulerInput {
|
|
17
|
-
triggerKind: DreamTriggerKind;
|
|
18
|
-
runId: string;
|
|
19
|
-
traceId: string;
|
|
20
|
-
statePort: DreamStatePort;
|
|
21
|
-
/** @deprecated Use modelAssistPort (DR-027). */
|
|
22
|
-
modelPort?: DreamModelPort;
|
|
23
|
-
modelAssistPort?: ModelAssistPort;
|
|
24
|
-
tracePort?: DreamTracePort;
|
|
25
|
-
budgetPort?: DreamBudgetPort;
|
|
26
|
-
options?: DreamEngineInput["options"];
|
|
27
|
-
lockPort?: DreamRunLockPort;
|
|
28
|
-
windowKey?: string;
|
|
29
|
-
}
|
|
30
|
-
export interface DreamRunLockPort {
|
|
31
|
-
acquireLock(input: {
|
|
32
|
-
runId: string;
|
|
33
|
-
windowKey: string;
|
|
34
|
-
ttlMs: number;
|
|
35
|
-
}): Promise<{
|
|
36
|
-
acquired: boolean;
|
|
37
|
-
existingRunId?: string;
|
|
38
|
-
}>;
|
|
39
|
-
releaseLock(input: {
|
|
40
|
-
runId: string;
|
|
41
|
-
windowKey: string;
|
|
42
|
-
}): Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
export interface ScheduleResult {
|
|
45
|
-
runId: string;
|
|
46
|
-
status: "started" | "skipped" | "queued";
|
|
47
|
-
reason?: string;
|
|
48
|
-
}
|
|
49
|
-
export declare function memoryLockPort(): DreamRunLockPort;
|
|
50
|
-
export declare function scheduleDream(input: SchedulerInput): Promise<ScheduleResult>;
|
|
51
|
-
export interface CronPolicy {
|
|
52
|
-
type: "cron";
|
|
53
|
-
intervalHours: number;
|
|
54
|
-
lastRunAt?: string;
|
|
55
|
-
}
|
|
56
|
-
export interface EvidenceThresholdPolicy {
|
|
57
|
-
type: "evidence_threshold";
|
|
58
|
-
threshold: number;
|
|
59
|
-
currentEvidenceCount: number;
|
|
60
|
-
lastRunEvidenceCount: number;
|
|
61
|
-
}
|
|
62
|
-
export interface ManualPolicy {
|
|
63
|
-
type: "manual";
|
|
64
|
-
}
|
|
65
|
-
export interface QuietCompletionPolicy {
|
|
66
|
-
type: "quiet_completion";
|
|
67
|
-
quietCompletedAt: string;
|
|
68
|
-
windowStartHour: number;
|
|
69
|
-
windowEndHour: number;
|
|
70
|
-
}
|
|
71
|
-
export type TriggerPolicy = CronPolicy | EvidenceThresholdPolicy | ManualPolicy | QuietCompletionPolicy;
|
|
72
|
-
export declare function shouldTrigger(policy: TriggerPolicy): {
|
|
73
|
-
shouldRun: boolean;
|
|
74
|
-
reason?: string;
|
|
75
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Dream Scheduler
|
|
3
|
+
*
|
|
4
|
+
* Core logic: trigger Dream runs via cron schedule, evidence threshold, or manual
|
|
5
|
+
* request. Uses DreamRunLock to prevent concurrent runs on the same workspace/input
|
|
6
|
+
* window. Operator timeout is enforced via options in the engine call.
|
|
7
|
+
*
|
|
8
|
+
* - Cron: simplified — checks if a scheduled window is due (last run + interval).
|
|
9
|
+
* - Evidence threshold: triggers when evidence count exceeds threshold since last run.
|
|
10
|
+
* - Manual: always allowed if no active lock.
|
|
11
|
+
* - Lock: in-memory or port-backed; released after run completes or times out.
|
|
12
|
+
* Test coverage: tests/integration/dream/t7-1-2-dream-scheduler.test.ts
|
|
13
|
+
*/
|
|
14
|
+
import type { DreamEngineInput } from "./types.js";
|
|
15
|
+
import type { DreamTriggerKind, DreamTracePort, DreamStatePort, DreamModelPort, DreamBudgetPort, ModelAssistPort } from "./types.js";
|
|
16
|
+
export interface SchedulerInput {
|
|
17
|
+
triggerKind: DreamTriggerKind;
|
|
18
|
+
runId: string;
|
|
19
|
+
traceId: string;
|
|
20
|
+
statePort: DreamStatePort;
|
|
21
|
+
/** @deprecated Use modelAssistPort (DR-027). */
|
|
22
|
+
modelPort?: DreamModelPort;
|
|
23
|
+
modelAssistPort?: ModelAssistPort;
|
|
24
|
+
tracePort?: DreamTracePort;
|
|
25
|
+
budgetPort?: DreamBudgetPort;
|
|
26
|
+
options?: DreamEngineInput["options"];
|
|
27
|
+
lockPort?: DreamRunLockPort;
|
|
28
|
+
windowKey?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DreamRunLockPort {
|
|
31
|
+
acquireLock(input: {
|
|
32
|
+
runId: string;
|
|
33
|
+
windowKey: string;
|
|
34
|
+
ttlMs: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
acquired: boolean;
|
|
37
|
+
existingRunId?: string;
|
|
38
|
+
}>;
|
|
39
|
+
releaseLock(input: {
|
|
40
|
+
runId: string;
|
|
41
|
+
windowKey: string;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export interface ScheduleResult {
|
|
45
|
+
runId: string;
|
|
46
|
+
status: "started" | "skipped" | "queued";
|
|
47
|
+
reason?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function memoryLockPort(): DreamRunLockPort;
|
|
50
|
+
export declare function scheduleDream(input: SchedulerInput): Promise<ScheduleResult>;
|
|
51
|
+
export interface CronPolicy {
|
|
52
|
+
type: "cron";
|
|
53
|
+
intervalHours: number;
|
|
54
|
+
lastRunAt?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface EvidenceThresholdPolicy {
|
|
57
|
+
type: "evidence_threshold";
|
|
58
|
+
threshold: number;
|
|
59
|
+
currentEvidenceCount: number;
|
|
60
|
+
lastRunEvidenceCount: number;
|
|
61
|
+
}
|
|
62
|
+
export interface ManualPolicy {
|
|
63
|
+
type: "manual";
|
|
64
|
+
}
|
|
65
|
+
export interface QuietCompletionPolicy {
|
|
66
|
+
type: "quiet_completion";
|
|
67
|
+
quietCompletedAt: string;
|
|
68
|
+
windowStartHour: number;
|
|
69
|
+
windowEndHour: number;
|
|
70
|
+
}
|
|
71
|
+
export type TriggerPolicy = CronPolicy | EvidenceThresholdPolicy | ManualPolicy | QuietCompletionPolicy;
|
|
72
|
+
export declare function shouldTrigger(policy: TriggerPolicy): {
|
|
73
|
+
shouldRun: boolean;
|
|
74
|
+
reason?: string;
|
|
75
|
+
};
|