@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.
Files changed (49) hide show
  1. package/index.js +1270 -1270
  2. package/openclaw.plugin.json +29 -29
  3. package/package.json +55 -55
  4. package/runtime/cli/commands/connector-init.js +11 -4
  5. package/runtime/cli/index.js +6 -1
  6. package/runtime/cli/ops/heartbeat-surface.d.ts +75 -75
  7. package/runtime/cli/ops/heartbeat-surface.js +97 -97
  8. package/runtime/cli/ops/ops-router.js +1428 -1428
  9. package/runtime/cli/ops/workspace-heartbeat-runner.js +236 -236
  10. package/runtime/connectors/services/connector-executor-adapter.js +192 -41
  11. package/runtime/core/second-nature/guidance/apply-guidance.d.ts +12 -12
  12. package/runtime/core/second-nature/guidance/apply-guidance.js +15 -15
  13. package/runtime/core/second-nature/guidance/user-reply-continuity.d.ts +50 -50
  14. package/runtime/core/second-nature/guidance/user-reply-continuity.js +89 -89
  15. package/runtime/core/second-nature/orchestrator/intent-planner.js +15 -0
  16. package/runtime/core/second-nature/runtime/service-entry.d.ts +39 -39
  17. package/runtime/core/second-nature/runtime/service-entry.js +44 -44
  18. package/runtime/dream/dream-engine.d.ts +14 -14
  19. package/runtime/dream/dream-engine.js +306 -306
  20. package/runtime/dream/dream-input-loader.d.ts +37 -37
  21. package/runtime/dream/dream-input-loader.js +150 -150
  22. package/runtime/dream/dream-scheduler.d.ts +75 -75
  23. package/runtime/dream/dream-scheduler.js +131 -131
  24. package/runtime/dream/index.d.ts +16 -16
  25. package/runtime/dream/index.js +14 -14
  26. package/runtime/dream/insight-extractor.d.ts +32 -32
  27. package/runtime/dream/insight-extractor.js +135 -135
  28. package/runtime/dream/memory-consolidator.d.ts +45 -45
  29. package/runtime/dream/memory-consolidator.js +140 -140
  30. package/runtime/dream/narrative-update-proposal.d.ts +34 -34
  31. package/runtime/dream/narrative-update-proposal.js +83 -83
  32. package/runtime/dream/output-validator.d.ts +20 -20
  33. package/runtime/dream/output-validator.js +110 -110
  34. package/runtime/dream/redaction-gate.d.ts +31 -31
  35. package/runtime/dream/redaction-gate.js +109 -109
  36. package/runtime/dream/relationship-update-proposal.d.ts +27 -27
  37. package/runtime/dream/relationship-update-proposal.js +119 -119
  38. package/runtime/dream/sampler.d.ts +30 -30
  39. package/runtime/dream/sampler.js +65 -65
  40. package/runtime/dream/types.d.ts +187 -187
  41. package/runtime/dream/types.js +11 -11
  42. package/runtime/guidance/fallback.js +20 -20
  43. package/runtime/guidance/guidance-assembler.js +76 -76
  44. package/runtime/guidance/output-guard.d.ts +13 -13
  45. package/runtime/guidance/output-guard.js +53 -53
  46. package/runtime/guidance/template-registry.d.ts +20 -20
  47. package/runtime/guidance/template-registry.js +93 -93
  48. package/runtime/guidance/types.d.ts +98 -98
  49. 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
+ };