@haaaiawd/second-nature 0.1.22 → 0.1.24
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/runtime/cli/commands/connector-init.d.ts +19 -0
- package/runtime/cli/commands/connector-init.js +168 -0
- package/runtime/cli/commands/connector-status.d.ts +12 -0
- package/runtime/cli/commands/connector-status.js +156 -0
- package/runtime/cli/commands/index.js +40 -0
- package/runtime/cli/index.js +52 -0
- package/runtime/cli/ops/ops-router.d.ts +5 -0
- package/runtime/cli/ops/ops-router.js +34 -0
- package/runtime/cli/ops/workspace-heartbeat-runner.js +22 -0
- package/runtime/connectors/agent-network/agent-world/adapter.d.ts +11 -0
- package/runtime/connectors/agent-network/agent-world/adapter.js +58 -0
- package/runtime/connectors/agent-network/agent-world/index.d.ts +2 -0
- package/runtime/connectors/agent-network/agent-world/index.js +2 -0
- package/runtime/connectors/agent-network/agent-world/manifest.d.ts +2 -0
- package/runtime/connectors/agent-network/agent-world/manifest.js +7 -0
- package/runtime/connectors/base/manifest.d.ts +13 -0
- package/runtime/connectors/base/manifest.js +47 -0
- package/runtime/connectors/manifest/manifest-parser.d.ts +16 -0
- package/runtime/connectors/manifest/manifest-parser.js +35 -0
- package/runtime/connectors/manifest/manifest-schema.d.ts +145 -0
- package/runtime/connectors/manifest/manifest-schema.js +51 -0
- package/runtime/connectors/registry/dynamic-connector-registry.d.ts +29 -0
- package/runtime/connectors/registry/dynamic-connector-registry.js +123 -0
- package/runtime/connectors/registry/index.d.ts +3 -0
- package/runtime/connectors/registry/index.js +3 -0
- package/runtime/connectors/registry/manifest-scanner.d.ts +9 -0
- package/runtime/connectors/registry/manifest-scanner.js +29 -0
- package/runtime/connectors/registry/trust-policy.d.ts +13 -0
- package/runtime/connectors/registry/trust-policy.js +37 -0
- package/runtime/connectors/services/connector-executor-adapter.js +49 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +3 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +52 -1
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +3 -0
- package/runtime/core/second-nature/orchestrator/goal-priority.d.ts +19 -0
- package/runtime/core/second-nature/orchestrator/goal-priority.js +67 -0
- package/runtime/core/second-nature/orchestrator/intent-planner.js +8 -0
- package/runtime/core/second-nature/orchestrator/narrative-update.d.ts +27 -0
- package/runtime/core/second-nature/orchestrator/narrative-update.js +107 -0
- package/runtime/core/second-nature/types.d.ts +4 -0
- package/runtime/guidance/draft-narrative-outreach.d.ts +36 -0
- package/runtime/guidance/draft-narrative-outreach.js +84 -0
- package/runtime/guidance/index.d.ts +1 -0
- package/runtime/guidance/index.js +1 -0
- package/runtime/guidance/outreach-draft-schema.d.ts +3 -3
- package/runtime/observability/connector-inventory-ledger.d.ts +45 -0
- package/runtime/observability/connector-inventory-ledger.js +72 -0
- package/runtime/observability/db/index.js +13 -0
- package/runtime/observability/db/schema/connector-inventory.d.ts +174 -0
- package/runtime/observability/db/schema/connector-inventory.js +15 -0
- package/runtime/observability/db/schema/index.d.ts +1 -0
- package/runtime/observability/db/schema/index.js +1 -0
- package/runtime/storage/chronicle/session-chronicle-store.d.ts +42 -0
- package/runtime/storage/chronicle/session-chronicle-store.js +66 -0
- package/runtime/storage/db/index.js +75 -0
- package/runtime/storage/db/schema/agent-goal.d.ts +235 -0
- package/runtime/storage/db/schema/agent-goal.js +19 -0
- package/runtime/storage/db/schema/index.d.ts +5 -0
- package/runtime/storage/db/schema/index.js +5 -0
- package/runtime/storage/db/schema/memory-store.d.ts +199 -0
- package/runtime/storage/db/schema/memory-store.js +18 -0
- package/runtime/storage/db/schema/narrative-state.d.ts +195 -0
- package/runtime/storage/db/schema/narrative-state.js +16 -0
- package/runtime/storage/db/schema/relationship-memory.d.ts +174 -0
- package/runtime/storage/db/schema/relationship-memory.js +14 -0
- package/runtime/storage/db/schema/session-chronicle.d.ts +199 -0
- package/runtime/storage/db/schema/session-chronicle.js +18 -0
- package/runtime/storage/goal/agent-goal-store.d.ts +57 -0
- package/runtime/storage/goal/agent-goal-store.js +109 -0
- package/runtime/storage/index.d.ts +5 -0
- package/runtime/storage/index.js +5 -0
- package/runtime/storage/memory-store/memory-store-lifecycle.d.ts +70 -0
- package/runtime/storage/memory-store/memory-store-lifecycle.js +113 -0
- package/runtime/storage/narrative/narrative-state-store.d.ts +40 -0
- package/runtime/storage/narrative/narrative-state-store.js +79 -0
- package/runtime/storage/relationship/relationship-memory-store.d.ts +42 -0
- package/runtime/storage/relationship/relationship-memory-store.js +76 -0
- package/workspace-ops-bridge.js +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { StateDatabase } from "../db/index.js";
|
|
2
|
+
export interface SourceRef {
|
|
3
|
+
sourceId: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
snippet?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CanonicalMemoryEntry {
|
|
9
|
+
entryId: string;
|
|
10
|
+
kind: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
sourceRefs: SourceRef[];
|
|
13
|
+
createdAt: string;
|
|
14
|
+
}
|
|
15
|
+
export interface DreamInsight {
|
|
16
|
+
id: string;
|
|
17
|
+
type: "pattern" | "learning" | "observation" | "conflict";
|
|
18
|
+
summary: string;
|
|
19
|
+
sourceRefs: string[];
|
|
20
|
+
confidence: number;
|
|
21
|
+
}
|
|
22
|
+
export interface MemoryStoreValidation {
|
|
23
|
+
passed: boolean;
|
|
24
|
+
summary: string;
|
|
25
|
+
checkedAt: string;
|
|
26
|
+
unsupportedClaims?: string[];
|
|
27
|
+
redactionIssues?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface MemoryStore {
|
|
30
|
+
memoryStoreId: string;
|
|
31
|
+
lifecycleStatus: "candidate" | "accepted" | "archived" | "partial" | "superseded";
|
|
32
|
+
createdAt: string;
|
|
33
|
+
inputMemoryStoreId?: string;
|
|
34
|
+
dreamRunId?: string;
|
|
35
|
+
canonicalEntries: CanonicalMemoryEntry[];
|
|
36
|
+
insights: DreamInsight[];
|
|
37
|
+
narrativeSnapshot?: Record<string, unknown>;
|
|
38
|
+
relationshipSnapshot?: Record<string, unknown>;
|
|
39
|
+
validation: MemoryStoreValidation;
|
|
40
|
+
}
|
|
41
|
+
export interface MemoryStoreWrite {
|
|
42
|
+
memoryStoreId: string;
|
|
43
|
+
lifecycleStatus: "candidate" | "accepted" | "archived" | "partial" | "superseded";
|
|
44
|
+
createdAt: string;
|
|
45
|
+
inputMemoryStoreId?: string;
|
|
46
|
+
dreamRunId?: string;
|
|
47
|
+
canonicalEntries: CanonicalMemoryEntry[];
|
|
48
|
+
insights: DreamInsight[];
|
|
49
|
+
narrativeSnapshot?: Record<string, unknown>;
|
|
50
|
+
relationshipSnapshot?: Record<string, unknown>;
|
|
51
|
+
validation: MemoryStoreValidation;
|
|
52
|
+
}
|
|
53
|
+
export interface MemoryStoreLifecycleTransition {
|
|
54
|
+
memoryStoreId: string;
|
|
55
|
+
newStatus: "candidate" | "accepted" | "archived" | "partial" | "superseded";
|
|
56
|
+
validation?: MemoryStoreValidation;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
}
|
|
59
|
+
export interface MemoryStoreAck {
|
|
60
|
+
memoryStoreId: string;
|
|
61
|
+
status: "acknowledged" | "degraded";
|
|
62
|
+
}
|
|
63
|
+
export interface MemoryStorePort {
|
|
64
|
+
writeMemoryStore(output: MemoryStoreWrite): Promise<MemoryStoreAck>;
|
|
65
|
+
loadMemoryStore(memoryStoreId: string): Promise<MemoryStore | null>;
|
|
66
|
+
transitionMemoryStoreLifecycle(input: MemoryStoreLifecycleTransition): Promise<MemoryStoreAck>;
|
|
67
|
+
loadAcceptedMemoryProjection(): Promise<MemoryStore | null>;
|
|
68
|
+
listMemoryStoresByStatus(status: MemoryStore["lifecycleStatus"]): Promise<MemoryStore[]>;
|
|
69
|
+
}
|
|
70
|
+
export declare function createMemoryStoreLifecycle(database: StateDatabase): MemoryStorePort;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { eq, desc } from "drizzle-orm";
|
|
2
|
+
import { memoryStore } from "../db/schema/memory-store.js";
|
|
3
|
+
function safeParseJson(json, fallback) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(json);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return fallback;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function rowToStore(row) {
|
|
12
|
+
return {
|
|
13
|
+
memoryStoreId: row.memoryStoreId,
|
|
14
|
+
lifecycleStatus: row.lifecycleStatus,
|
|
15
|
+
createdAt: row.createdAt,
|
|
16
|
+
inputMemoryStoreId: row.inputMemoryStoreId ?? undefined,
|
|
17
|
+
dreamRunId: row.dreamRunId ?? undefined,
|
|
18
|
+
canonicalEntries: safeParseJson(row.canonicalEntriesJson, []),
|
|
19
|
+
insights: safeParseJson(row.insightsJson, []),
|
|
20
|
+
narrativeSnapshot: row.narrativeSnapshotJson ? safeParseJson(row.narrativeSnapshotJson, undefined) : undefined,
|
|
21
|
+
relationshipSnapshot: row.relationshipSnapshotJson ? safeParseJson(row.relationshipSnapshotJson, undefined) : undefined,
|
|
22
|
+
validation: safeParseJson(row.validationJson, { passed: false, summary: "", checkedAt: "" }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function createMemoryStoreLifecycle(database) {
|
|
26
|
+
const db = database.db;
|
|
27
|
+
return {
|
|
28
|
+
async writeMemoryStore(output) {
|
|
29
|
+
const existing = await db
|
|
30
|
+
.select()
|
|
31
|
+
.from(memoryStore)
|
|
32
|
+
.where(eq(memoryStore.memoryStoreId, output.memoryStoreId))
|
|
33
|
+
.limit(1);
|
|
34
|
+
if (existing.length > 0) {
|
|
35
|
+
await db
|
|
36
|
+
.update(memoryStore)
|
|
37
|
+
.set({
|
|
38
|
+
lifecycleStatus: output.lifecycleStatus,
|
|
39
|
+
inputMemoryStoreId: output.inputMemoryStoreId ?? null,
|
|
40
|
+
dreamRunId: output.dreamRunId ?? null,
|
|
41
|
+
canonicalEntriesJson: JSON.stringify(output.canonicalEntries),
|
|
42
|
+
insightsJson: JSON.stringify(output.insights),
|
|
43
|
+
narrativeSnapshotJson: output.narrativeSnapshot ? JSON.stringify(output.narrativeSnapshot) : null,
|
|
44
|
+
relationshipSnapshotJson: output.relationshipSnapshot ? JSON.stringify(output.relationshipSnapshot) : null,
|
|
45
|
+
validationJson: JSON.stringify(output.validation),
|
|
46
|
+
})
|
|
47
|
+
.where(eq(memoryStore.memoryStoreId, output.memoryStoreId));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await db.insert(memoryStore).values({
|
|
51
|
+
memoryStoreId: output.memoryStoreId,
|
|
52
|
+
lifecycleStatus: output.lifecycleStatus,
|
|
53
|
+
createdAt: output.createdAt,
|
|
54
|
+
inputMemoryStoreId: output.inputMemoryStoreId ?? null,
|
|
55
|
+
dreamRunId: output.dreamRunId ?? null,
|
|
56
|
+
canonicalEntriesJson: JSON.stringify(output.canonicalEntries),
|
|
57
|
+
insightsJson: JSON.stringify(output.insights),
|
|
58
|
+
narrativeSnapshotJson: output.narrativeSnapshot ? JSON.stringify(output.narrativeSnapshot) : null,
|
|
59
|
+
relationshipSnapshotJson: output.relationshipSnapshot ? JSON.stringify(output.relationshipSnapshot) : null,
|
|
60
|
+
validationJson: JSON.stringify(output.validation),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { memoryStoreId: output.memoryStoreId, status: "acknowledged" };
|
|
64
|
+
},
|
|
65
|
+
async loadMemoryStore(memoryStoreId) {
|
|
66
|
+
const rows = await db
|
|
67
|
+
.select()
|
|
68
|
+
.from(memoryStore)
|
|
69
|
+
.where(eq(memoryStore.memoryStoreId, memoryStoreId))
|
|
70
|
+
.limit(1);
|
|
71
|
+
if (rows.length === 0)
|
|
72
|
+
return null;
|
|
73
|
+
return rowToStore(rows[0]);
|
|
74
|
+
},
|
|
75
|
+
async transitionMemoryStoreLifecycle(input) {
|
|
76
|
+
const existing = await db
|
|
77
|
+
.select()
|
|
78
|
+
.from(memoryStore)
|
|
79
|
+
.where(eq(memoryStore.memoryStoreId, input.memoryStoreId))
|
|
80
|
+
.limit(1);
|
|
81
|
+
if (existing.length === 0) {
|
|
82
|
+
return { memoryStoreId: input.memoryStoreId, status: "degraded" };
|
|
83
|
+
}
|
|
84
|
+
const updates = { lifecycleStatus: input.newStatus };
|
|
85
|
+
if (input.validation) {
|
|
86
|
+
updates.validationJson = JSON.stringify(input.validation);
|
|
87
|
+
}
|
|
88
|
+
await db
|
|
89
|
+
.update(memoryStore)
|
|
90
|
+
.set(updates)
|
|
91
|
+
.where(eq(memoryStore.memoryStoreId, input.memoryStoreId));
|
|
92
|
+
return { memoryStoreId: input.memoryStoreId, status: "acknowledged" };
|
|
93
|
+
},
|
|
94
|
+
async loadAcceptedMemoryProjection() {
|
|
95
|
+
const rows = await db
|
|
96
|
+
.select()
|
|
97
|
+
.from(memoryStore)
|
|
98
|
+
.where(eq(memoryStore.lifecycleStatus, "accepted"))
|
|
99
|
+
.orderBy(desc(memoryStore.createdAt))
|
|
100
|
+
.limit(1);
|
|
101
|
+
if (rows.length === 0)
|
|
102
|
+
return null;
|
|
103
|
+
return rowToStore(rows[0]);
|
|
104
|
+
},
|
|
105
|
+
async listMemoryStoresByStatus(status) {
|
|
106
|
+
const rows = await db
|
|
107
|
+
.select()
|
|
108
|
+
.from(memoryStore)
|
|
109
|
+
.where(eq(memoryStore.lifecycleStatus, status));
|
|
110
|
+
return rows.map(rowToStore);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { StateDatabase } from "../db/index.js";
|
|
2
|
+
export interface SourceRef {
|
|
3
|
+
sourceId: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
snippet?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface NarrativeState {
|
|
9
|
+
narrativeId: string;
|
|
10
|
+
revision: number;
|
|
11
|
+
focus: string;
|
|
12
|
+
progress: string[];
|
|
13
|
+
nextIntent: string;
|
|
14
|
+
confidence: number;
|
|
15
|
+
sourceRefs: SourceRef[];
|
|
16
|
+
unsupportedClaims: string[];
|
|
17
|
+
status: "active" | "insufficient_sources" | "awaiting_sources";
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
export interface NarrativeStateUpdate {
|
|
21
|
+
narrativeId: string;
|
|
22
|
+
revision: number;
|
|
23
|
+
focus: string;
|
|
24
|
+
progress: string[];
|
|
25
|
+
nextIntent: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
sourceRefs: SourceRef[];
|
|
28
|
+
unsupportedClaims: string[];
|
|
29
|
+
status: "active" | "insufficient_sources" | "awaiting_sources";
|
|
30
|
+
updatedAt: string;
|
|
31
|
+
}
|
|
32
|
+
export interface NarrativeStateWriteAck {
|
|
33
|
+
narrativeId: string;
|
|
34
|
+
status: "acknowledged" | "degraded";
|
|
35
|
+
}
|
|
36
|
+
export interface NarrativeStateStore {
|
|
37
|
+
updateNarrativeState(input: NarrativeStateUpdate): Promise<NarrativeStateWriteAck>;
|
|
38
|
+
loadNarrativeState(narrativeId?: string): Promise<NarrativeState | null>;
|
|
39
|
+
}
|
|
40
|
+
export declare function createNarrativeStateStore(database: StateDatabase): NarrativeStateStore;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { narrativeState } from "../db/schema/narrative-state.js";
|
|
3
|
+
function safeParseJson(json, fallback) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(json);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return fallback;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function rowToState(row) {
|
|
12
|
+
return {
|
|
13
|
+
narrativeId: row.narrativeId,
|
|
14
|
+
revision: row.revision,
|
|
15
|
+
focus: row.focus,
|
|
16
|
+
progress: safeParseJson(row.progressJson, []),
|
|
17
|
+
nextIntent: row.nextIntent,
|
|
18
|
+
confidence: row.confidence,
|
|
19
|
+
sourceRefs: safeParseJson(row.sourceRefsJson, []),
|
|
20
|
+
unsupportedClaims: safeParseJson(row.unsupportedClaimsJson, []),
|
|
21
|
+
status: row.status,
|
|
22
|
+
updatedAt: row.updatedAt,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const DEFAULT_NARRATIVE_ID = "default";
|
|
26
|
+
export function createNarrativeStateStore(database) {
|
|
27
|
+
const db = database.db;
|
|
28
|
+
return {
|
|
29
|
+
async updateNarrativeState(input) {
|
|
30
|
+
const existing = await db
|
|
31
|
+
.select()
|
|
32
|
+
.from(narrativeState)
|
|
33
|
+
.where(eq(narrativeState.narrativeId, input.narrativeId))
|
|
34
|
+
.limit(1);
|
|
35
|
+
if (existing.length > 0) {
|
|
36
|
+
await db
|
|
37
|
+
.update(narrativeState)
|
|
38
|
+
.set({
|
|
39
|
+
revision: input.revision,
|
|
40
|
+
focus: input.focus,
|
|
41
|
+
progressJson: JSON.stringify(input.progress),
|
|
42
|
+
nextIntent: input.nextIntent,
|
|
43
|
+
confidence: input.confidence,
|
|
44
|
+
sourceRefsJson: JSON.stringify(input.sourceRefs),
|
|
45
|
+
unsupportedClaimsJson: JSON.stringify(input.unsupportedClaims),
|
|
46
|
+
status: input.status,
|
|
47
|
+
updatedAt: input.updatedAt,
|
|
48
|
+
})
|
|
49
|
+
.where(eq(narrativeState.narrativeId, input.narrativeId));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await db.insert(narrativeState).values({
|
|
53
|
+
narrativeId: input.narrativeId,
|
|
54
|
+
revision: input.revision,
|
|
55
|
+
focus: input.focus,
|
|
56
|
+
progressJson: JSON.stringify(input.progress),
|
|
57
|
+
nextIntent: input.nextIntent,
|
|
58
|
+
confidence: input.confidence,
|
|
59
|
+
sourceRefsJson: JSON.stringify(input.sourceRefs),
|
|
60
|
+
unsupportedClaimsJson: JSON.stringify(input.unsupportedClaims),
|
|
61
|
+
status: input.status,
|
|
62
|
+
updatedAt: input.updatedAt,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return { narrativeId: input.narrativeId, status: "acknowledged" };
|
|
66
|
+
},
|
|
67
|
+
async loadNarrativeState(narrativeId) {
|
|
68
|
+
const id = narrativeId ?? DEFAULT_NARRATIVE_ID;
|
|
69
|
+
const rows = await db
|
|
70
|
+
.select()
|
|
71
|
+
.from(narrativeState)
|
|
72
|
+
.where(eq(narrativeState.narrativeId, id))
|
|
73
|
+
.limit(1);
|
|
74
|
+
if (rows.length === 0)
|
|
75
|
+
return null;
|
|
76
|
+
return rowToState(rows[0]);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { StateDatabase } from "../db/index.js";
|
|
2
|
+
export interface SourceRef {
|
|
3
|
+
sourceId: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
snippet?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TopicAffinity {
|
|
9
|
+
topic: string;
|
|
10
|
+
affinity: number;
|
|
11
|
+
}
|
|
12
|
+
export interface RelationshipMemory {
|
|
13
|
+
relationshipId: string;
|
|
14
|
+
revision: number;
|
|
15
|
+
tonePreference: "casual" | "direct" | "quiet" | "unknown";
|
|
16
|
+
averageReplyDelayMinutes?: number;
|
|
17
|
+
noReplyCount: number;
|
|
18
|
+
topicAffinities: TopicAffinity[];
|
|
19
|
+
lastInteractionAt?: string;
|
|
20
|
+
sourceRefs: SourceRef[];
|
|
21
|
+
updatedAt: string;
|
|
22
|
+
}
|
|
23
|
+
export interface RelationshipMemoryUpdate {
|
|
24
|
+
relationshipId: string;
|
|
25
|
+
revision: number;
|
|
26
|
+
tonePreference: "casual" | "direct" | "quiet" | "unknown";
|
|
27
|
+
averageReplyDelayMinutes?: number;
|
|
28
|
+
noReplyCount: number;
|
|
29
|
+
topicAffinities: TopicAffinity[];
|
|
30
|
+
lastInteractionAt?: string;
|
|
31
|
+
sourceRefs: SourceRef[];
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface RelationshipMemoryWriteAck {
|
|
35
|
+
relationshipId: string;
|
|
36
|
+
status: "acknowledged" | "degraded";
|
|
37
|
+
}
|
|
38
|
+
export interface RelationshipMemoryStore {
|
|
39
|
+
upsertRelationshipMemory(input: RelationshipMemoryUpdate): Promise<RelationshipMemoryWriteAck>;
|
|
40
|
+
loadRelationshipMemory(relationshipId?: string): Promise<RelationshipMemory | null>;
|
|
41
|
+
}
|
|
42
|
+
export declare function createRelationshipMemoryStore(database: StateDatabase): RelationshipMemoryStore;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { relationshipMemory } from "../db/schema/relationship-memory.js";
|
|
3
|
+
function safeParseJson(json, fallback) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(json);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return fallback;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function rowToMemory(row) {
|
|
12
|
+
return {
|
|
13
|
+
relationshipId: row.relationshipId,
|
|
14
|
+
revision: row.revision,
|
|
15
|
+
tonePreference: row.tonePreference,
|
|
16
|
+
averageReplyDelayMinutes: row.averageReplyDelayMinutes ?? undefined,
|
|
17
|
+
noReplyCount: row.noReplyCount,
|
|
18
|
+
topicAffinities: safeParseJson(row.topicAffinitiesJson, []),
|
|
19
|
+
lastInteractionAt: row.lastInteractionAt ?? undefined,
|
|
20
|
+
sourceRefs: safeParseJson(row.sourceRefsJson, []),
|
|
21
|
+
updatedAt: row.updatedAt,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const DEFAULT_RELATIONSHIP_ID = "default";
|
|
25
|
+
export function createRelationshipMemoryStore(database) {
|
|
26
|
+
const db = database.db;
|
|
27
|
+
return {
|
|
28
|
+
async upsertRelationshipMemory(input) {
|
|
29
|
+
const existing = await db
|
|
30
|
+
.select()
|
|
31
|
+
.from(relationshipMemory)
|
|
32
|
+
.where(eq(relationshipMemory.relationshipId, input.relationshipId))
|
|
33
|
+
.limit(1);
|
|
34
|
+
if (existing.length > 0) {
|
|
35
|
+
await db
|
|
36
|
+
.update(relationshipMemory)
|
|
37
|
+
.set({
|
|
38
|
+
revision: input.revision,
|
|
39
|
+
tonePreference: input.tonePreference,
|
|
40
|
+
averageReplyDelayMinutes: input.averageReplyDelayMinutes ?? null,
|
|
41
|
+
noReplyCount: input.noReplyCount,
|
|
42
|
+
topicAffinitiesJson: JSON.stringify(input.topicAffinities),
|
|
43
|
+
lastInteractionAt: input.lastInteractionAt ?? null,
|
|
44
|
+
sourceRefsJson: JSON.stringify(input.sourceRefs),
|
|
45
|
+
updatedAt: input.updatedAt,
|
|
46
|
+
})
|
|
47
|
+
.where(eq(relationshipMemory.relationshipId, input.relationshipId));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
await db.insert(relationshipMemory).values({
|
|
51
|
+
relationshipId: input.relationshipId,
|
|
52
|
+
revision: input.revision,
|
|
53
|
+
tonePreference: input.tonePreference,
|
|
54
|
+
averageReplyDelayMinutes: input.averageReplyDelayMinutes ?? null,
|
|
55
|
+
noReplyCount: input.noReplyCount,
|
|
56
|
+
topicAffinitiesJson: JSON.stringify(input.topicAffinities),
|
|
57
|
+
lastInteractionAt: input.lastInteractionAt ?? null,
|
|
58
|
+
sourceRefsJson: JSON.stringify(input.sourceRefs),
|
|
59
|
+
updatedAt: input.updatedAt,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return { relationshipId: input.relationshipId, status: "acknowledged" };
|
|
63
|
+
},
|
|
64
|
+
async loadRelationshipMemory(relationshipId) {
|
|
65
|
+
const id = relationshipId ?? DEFAULT_RELATIONSHIP_ID;
|
|
66
|
+
const rows = await db
|
|
67
|
+
.select()
|
|
68
|
+
.from(relationshipMemory)
|
|
69
|
+
.where(eq(relationshipMemory.relationshipId, id))
|
|
70
|
+
.limit(1);
|
|
71
|
+
if (rows.length === 0)
|
|
72
|
+
return null;
|
|
73
|
+
return rowToMemory(rows[0]);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
package/workspace-ops-bridge.js
CHANGED
|
@@ -47,6 +47,7 @@ export async function openWorkspaceOpsBridge(workspaceRoot) {
|
|
|
47
47
|
state: stateDb,
|
|
48
48
|
workspaceRoot: resolvedRoot,
|
|
49
49
|
connectorExecutor: deps.connectorExecutor,
|
|
50
|
+
registry: deps.registry,
|
|
50
51
|
});
|
|
51
52
|
const commands = commandsMod.createCliCommands({
|
|
52
53
|
readModels: deps.readModels,
|