@siduri-x/core 2.0.3 → 2.0.4
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/dist/chat-contract.d.ts +4 -0
- package/dist/chat-contract.js +17 -2
- package/dist/index.d.ts +4 -2
- package/dist/memory-settler.js +1 -1
- package/dist/mouth-types.d.ts +7 -2
- package/dist/perception-pipeline.d.ts +1 -0
- package/dist/perception-pipeline.js +7 -0
- package/dist/prompt-compiler.d.ts +1 -0
- package/dist/prompt-compiler.js +5 -1
- package/dist/proposals.d.ts +2 -1
- package/dist/response-envelope.d.ts +3 -0
- package/dist/response-envelope.js +13 -3
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +2 -1
- package/dist/siduri-db.d.ts +9 -2
- package/dist/siduri-db.js +96 -121
- package/dist/siduri-db.test.js +18 -18
- package/package.json +1 -1
package/dist/chat-contract.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface ChatRequest {
|
|
|
13
13
|
history?: Message[];
|
|
14
14
|
medium?: MouthMedium;
|
|
15
15
|
signal?: AbortSignal;
|
|
16
|
+
subtitleLanguage?: string;
|
|
16
17
|
[key: string]: any;
|
|
17
18
|
}
|
|
18
19
|
export interface ChatResponseMetadataEvent {
|
|
@@ -30,6 +31,9 @@ export interface ChatResponsePlan {
|
|
|
30
31
|
subtitle_ja: string;
|
|
31
32
|
subtitle_en: string;
|
|
32
33
|
spoken_ja?: string;
|
|
34
|
+
subtitle?: string;
|
|
35
|
+
subtitle_language?: string;
|
|
36
|
+
subtitles?: Record<string, string>;
|
|
33
37
|
evidence_ids?: string[];
|
|
34
38
|
}
|
|
35
39
|
export interface ChatResponseMetadata {
|
package/dist/chat-contract.js
CHANGED
|
@@ -21,8 +21,9 @@ async function dispatchCompanionChat(runtime, payload) {
|
|
|
21
21
|
else {
|
|
22
22
|
roleOrContext = 'OWNER';
|
|
23
23
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const requestedSubtitleLang = payload.subtitleLanguage || payload.subtitle_language;
|
|
25
|
+
const runtimeResult = (payload.medium || payload.signal || requestedSubtitleLang)
|
|
26
|
+
? await runner.handleUserMessage(userMessage, roleOrContext, history, payload.medium, payload.signal, requestedSubtitleLang)
|
|
26
27
|
: await runner.handleUserMessage(userMessage, roleOrContext, history);
|
|
27
28
|
const delivery = runtimeResult?.delivery;
|
|
28
29
|
// Normalize response plan
|
|
@@ -41,6 +42,17 @@ async function dispatchCompanionChat(runtime, payload) {
|
|
|
41
42
|
expression = avatarEvent.expression;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
const resolvedSubtitles = {
|
|
46
|
+
...(runtimeResult?.response?.subtitles || {}),
|
|
47
|
+
...(delivery?.subtitles || {}),
|
|
48
|
+
};
|
|
49
|
+
const subtitle = (requestedSubtitleLang && resolvedSubtitles[requestedSubtitleLang]) ||
|
|
50
|
+
runtimeResult?.response?.subtitle ||
|
|
51
|
+
(requestedSubtitleLang === 'ja' ? (delivery?.subtitles?.ja ?? runtimeResult?.response?.subtitle_ja) : undefined) ||
|
|
52
|
+
(requestedSubtitleLang === 'en' ? (delivery?.subtitles?.en ?? runtimeResult?.response?.subtitle_en) : undefined);
|
|
53
|
+
if (subtitle && requestedSubtitleLang) {
|
|
54
|
+
resolvedSubtitles[requestedSubtitleLang] = subtitle;
|
|
55
|
+
}
|
|
44
56
|
// Ensure both spoken_ja and subtitle_en are accessible alongside speech_id and evidence_ids
|
|
45
57
|
const responsePlan = {
|
|
46
58
|
speech_id: runtimeResult?.response?.speech_id,
|
|
@@ -48,6 +60,9 @@ async function dispatchCompanionChat(runtime, payload) {
|
|
|
48
60
|
subtitle_ja: delivery?.subtitles?.ja ?? runtimeResult?.response?.subtitle_ja ?? speech,
|
|
49
61
|
subtitle_en: delivery?.subtitles?.en ?? runtimeResult?.response?.subtitle_en ?? speech,
|
|
50
62
|
spoken_ja: delivery?.subtitles?.spoken ?? runtimeResult?.response?.spoken_ja ?? runtimeResult?.response?.subtitle_ja ?? speech,
|
|
63
|
+
subtitle,
|
|
64
|
+
subtitle_language: requestedSubtitleLang,
|
|
65
|
+
subtitles: resolvedSubtitles,
|
|
51
66
|
evidence_ids: runtimeResult?.metadata?.evidence_ids ?? runtimeResult?.response?.evidence_ids ?? [],
|
|
52
67
|
};
|
|
53
68
|
const metadata = {
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ import { EvidenceRecord } from './evidence';
|
|
|
31
31
|
import { ActionIntent } from './action';
|
|
32
32
|
import { RequestContext } from './context';
|
|
33
33
|
import { EarIngestOptions } from './ear-types';
|
|
34
|
-
import { ClaimType, ClaimAuthority, ClaimStatus, SourceEvent, MemoryProposal, BehaviorProposal } from './proposals';
|
|
34
|
+
import { ClaimType, ClaimAuthority, ClaimStatus, DirectiveStatus, SourceEvent, MemoryProposal, BehaviorProposal } from './proposals';
|
|
35
35
|
export interface OrganConfig {
|
|
36
36
|
provider: string;
|
|
37
37
|
[key: string]: unknown;
|
|
@@ -61,6 +61,8 @@ export interface BrainContext {
|
|
|
61
61
|
export interface ResponsePlan {
|
|
62
62
|
speech: string;
|
|
63
63
|
language: string;
|
|
64
|
+
subtitle?: string;
|
|
65
|
+
subtitles?: Record<string, string>;
|
|
64
66
|
memoryProposals?: MemoryProposal[];
|
|
65
67
|
behaviorProposals?: BehaviorProposal[];
|
|
66
68
|
actionIntents?: ActionIntent[];
|
|
@@ -98,7 +100,7 @@ export interface BehaviorDirective {
|
|
|
98
100
|
companionId: string;
|
|
99
101
|
directive: string;
|
|
100
102
|
priority: number;
|
|
101
|
-
status:
|
|
103
|
+
status: DirectiveStatus;
|
|
102
104
|
supersedesId?: string;
|
|
103
105
|
memoryClass?: 'identity' | 'relationship' | 'behavioral';
|
|
104
106
|
subject?: string;
|
package/dist/memory-settler.js
CHANGED
package/dist/mouth-types.d.ts
CHANGED
|
@@ -17,6 +17,9 @@ export interface MouthUtterance {
|
|
|
17
17
|
subtitleJa?: string;
|
|
18
18
|
subtitleEn?: string;
|
|
19
19
|
spokenJa?: string;
|
|
20
|
+
subtitle?: string;
|
|
21
|
+
subtitleLanguage?: string;
|
|
22
|
+
subtitles?: Record<string, string>;
|
|
20
23
|
expression?: string;
|
|
21
24
|
action?: string;
|
|
22
25
|
medium?: MouthMedium;
|
|
@@ -35,10 +38,12 @@ export interface FormattedMouthOutput {
|
|
|
35
38
|
ssml?: string;
|
|
36
39
|
visemes?: MouthVisemeCue[];
|
|
37
40
|
subtitles?: {
|
|
38
|
-
ja
|
|
39
|
-
en
|
|
41
|
+
ja?: string;
|
|
42
|
+
en?: string;
|
|
40
43
|
spoken?: string;
|
|
44
|
+
[lang: string]: string | undefined;
|
|
41
45
|
};
|
|
46
|
+
subtitle?: string;
|
|
42
47
|
audioUrl?: string;
|
|
43
48
|
audioBuffer?: Uint8Array;
|
|
44
49
|
expression?: string;
|
|
@@ -93,6 +93,7 @@ const promptCompilationStage = async (context) => {
|
|
|
93
93
|
memoryData: context.contextRetrieval.memoryData,
|
|
94
94
|
lifeContext: context.contextRetrieval.lifeContext,
|
|
95
95
|
effectiveMode: context.intent?.effectiveMode,
|
|
96
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
96
97
|
});
|
|
97
98
|
context.prompts = prompts;
|
|
98
99
|
};
|
|
@@ -198,6 +199,9 @@ const mouthDeliveryStage = async (context) => {
|
|
|
198
199
|
subtitleJa: context.plan.speech,
|
|
199
200
|
subtitleEn: context.plan.speech,
|
|
200
201
|
spokenJa: context.plan.speech,
|
|
202
|
+
subtitle: context.plan.subtitle,
|
|
203
|
+
subtitles: context.plan.subtitles,
|
|
204
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
201
205
|
expression: avatarEvent?.expression,
|
|
202
206
|
medium: context.perception.medium,
|
|
203
207
|
signal: context.perception.signal,
|
|
@@ -226,6 +230,9 @@ const envelopeAssemblyStage = async (context) => {
|
|
|
226
230
|
stagedPlan: context.stagedPlan,
|
|
227
231
|
speech: context.plan.speech,
|
|
228
232
|
language: context.plan.language,
|
|
233
|
+
subtitle: context.plan.subtitle,
|
|
234
|
+
subtitles: context.plan.subtitles,
|
|
235
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
229
236
|
speechId: context.experienceEmission?.speechId,
|
|
230
237
|
createdMemoryProposals: context.memorySettlement.createdMemoryProposals,
|
|
231
238
|
memoryProposalReceipts: context.memorySettlement.memoryProposalReceipts,
|
package/dist/prompt-compiler.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.compilePrompts = compilePrompts;
|
|
|
5
5
|
* Compiles neutral system prompt and formatted context prompt from structured data.
|
|
6
6
|
*/
|
|
7
7
|
async function compilePrompts(params) {
|
|
8
|
-
const { companionName, companionId, role, requestContext, behavior, activeDirectives, subsystemDiagnostics, knowledgeData, memoryData, lifeContext, effectiveMode, } = params;
|
|
8
|
+
const { companionName, companionId, role, requestContext, behavior, activeDirectives, subsystemDiagnostics, knowledgeData, memoryData, lifeContext, effectiveMode, subtitleLanguage, } = params;
|
|
9
9
|
let contextPrompt = '';
|
|
10
10
|
if (Object.keys(subsystemDiagnostics).length > 0) {
|
|
11
11
|
contextPrompt +=
|
|
@@ -48,9 +48,13 @@ async function compilePrompts(params) {
|
|
|
48
48
|
: effectiveMode === 'teach'
|
|
49
49
|
? 'Operating Mode: Teach Mode (Active learning session - accurately capture user preferences and proposed boundaries for operator review).'
|
|
50
50
|
: undefined;
|
|
51
|
+
const subtitleInstruction = subtitleLanguage && subtitleLanguage !== 'off'
|
|
52
|
+
? `Requested Subtitle Language: "${subtitleLanguage}". Along with your primary speech, provide a natural subtitle translation in "${subtitleLanguage}" in the subtitle field.`
|
|
53
|
+
: undefined;
|
|
51
54
|
const systemPrompt = [
|
|
52
55
|
`You are ${companionName}.`,
|
|
53
56
|
modeInstruction,
|
|
57
|
+
subtitleInstruction,
|
|
54
58
|
'This is a neutral conversation context.',
|
|
55
59
|
'Use only approved, permitted memory as factual personal context.',
|
|
56
60
|
'Do not claim prior personal knowledge when no approved memory supports it.',
|
package/dist/proposals.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type ClaimType = 'semantic' | 'preference' | 'episodic' | 'relationship';
|
|
2
2
|
export type ClaimAuthority = 'user_explicit' | 'user_correction' | 'import' | 'repeated_dialogue' | 'inference' | 'observation';
|
|
3
|
-
export type ClaimStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'SESSION_ONLY' | 'EXPIRED' | 'SUPERSEDED' | 'REVOKED';
|
|
3
|
+
export type ClaimStatus = 'pending' | 'approved' | 'rejected' | 'session-only' | 'expired' | 'superseded' | 'revoked' | 'PENDING' | 'APPROVED' | 'REJECTED' | 'SESSION_ONLY' | 'EXPIRED' | 'SUPERSEDED' | 'REVOKED';
|
|
4
|
+
export type DirectiveStatus = 'pending' | 'active' | 'disabled' | 'superseded' | 'rejected' | 'revoked' | 'expired' | 'confirmed' | 'PENDING' | 'ACTIVE' | 'DISABLED' | 'SUPERSEDED' | 'REJECTED' | 'REVOKED' | 'EXPIRED';
|
|
4
5
|
export interface SourceEvent {
|
|
5
6
|
id: string;
|
|
6
7
|
sourceType: string;
|
|
@@ -5,6 +5,9 @@ export interface AssembleResponseEnvelopeParams {
|
|
|
5
5
|
stagedPlan: StagedResponsePlan;
|
|
6
6
|
speech: string;
|
|
7
7
|
language?: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
subtitles?: Record<string, string>;
|
|
10
|
+
subtitleLanguage?: string;
|
|
8
11
|
speechId?: string;
|
|
9
12
|
createdMemoryProposals: Claim[];
|
|
10
13
|
memoryProposalReceipts: MemoryProposalReceipt[];
|
|
@@ -29,7 +29,14 @@ function createGateRejectionEnvelope(stagedPlan, gateEval) {
|
|
|
29
29
|
* Assembles the standardized response structure for approved companion responses.
|
|
30
30
|
*/
|
|
31
31
|
function assembleResponseEnvelope(params) {
|
|
32
|
-
const { stagedPlan, speech, language, speechId, createdMemoryProposals, memoryProposalReceipts, actionResults, filteredEvidenceIds, filteredCitations, subsystemDiagnostics, experienceEvents, mouthDelivery, effectiveMode, } = params;
|
|
32
|
+
const { stagedPlan, speech, language, subtitle, subtitles, subtitleLanguage, speechId, createdMemoryProposals, memoryProposalReceipts, actionResults, filteredEvidenceIds, filteredCitations, subsystemDiagnostics, experienceEvents, mouthDelivery, effectiveMode, } = params;
|
|
33
|
+
const resolvedSubtitles = {
|
|
34
|
+
...(mouthDelivery?.subtitles || {}),
|
|
35
|
+
...(subtitles || {}),
|
|
36
|
+
};
|
|
37
|
+
if (subtitle && subtitleLanguage) {
|
|
38
|
+
resolvedSubtitles[subtitleLanguage] = subtitle;
|
|
39
|
+
}
|
|
33
40
|
return {
|
|
34
41
|
status: 'APPROVED',
|
|
35
42
|
response_id: stagedPlan.responseId,
|
|
@@ -37,8 +44,11 @@ function assembleResponseEnvelope(params) {
|
|
|
37
44
|
response: {
|
|
38
45
|
speech_id: speechId,
|
|
39
46
|
audio_url: mouthDelivery?.audioUrl ?? (speechId ? `/voice/stream?id=${speechId}` : undefined),
|
|
40
|
-
subtitle_ja: mouthDelivery?.subtitles?.ja ?? speech,
|
|
41
|
-
subtitle_en: mouthDelivery?.subtitles?.en ?? speech,
|
|
47
|
+
subtitle_ja: mouthDelivery?.subtitles?.ja ?? resolvedSubtitles['ja'] ?? speech,
|
|
48
|
+
subtitle_en: mouthDelivery?.subtitles?.en ?? resolvedSubtitles['en'] ?? speech,
|
|
49
|
+
subtitle: subtitle ?? (subtitleLanguage ? resolvedSubtitles[subtitleLanguage] : undefined),
|
|
50
|
+
subtitle_language: subtitleLanguage,
|
|
51
|
+
subtitles: resolvedSubtitles,
|
|
42
52
|
},
|
|
43
53
|
delivery: mouthDelivery,
|
|
44
54
|
metadata: {
|
package/dist/runtime.d.ts
CHANGED
|
@@ -46,5 +46,5 @@ export declare class SiduriRuntime {
|
|
|
46
46
|
/**
|
|
47
47
|
* Primary entrypoint for text chat messages.
|
|
48
48
|
*/
|
|
49
|
-
handleUserMessage(message: string, roleOrContext?: 'OWNER' | 'VIEWER' | 'OPERATOR' | RequestContext | string, history?: Message[], medium?: MouthMedium, signal?: AbortSignal): Promise<any>;
|
|
49
|
+
handleUserMessage(message: string, roleOrContext?: 'OWNER' | 'VIEWER' | 'OPERATOR' | RequestContext | string, history?: Message[], medium?: MouthMedium, signal?: AbortSignal, subtitleLanguage?: string): Promise<any>;
|
|
50
50
|
}
|
package/dist/runtime.js
CHANGED
|
@@ -81,7 +81,7 @@ class SiduriRuntime {
|
|
|
81
81
|
/**
|
|
82
82
|
* Primary entrypoint for text chat messages.
|
|
83
83
|
*/
|
|
84
|
-
async handleUserMessage(message, roleOrContext = 'OWNER', history = [], medium, signal) {
|
|
84
|
+
async handleUserMessage(message, roleOrContext = 'OWNER', history = [], medium, signal, subtitleLanguage) {
|
|
85
85
|
return this.processPerception({
|
|
86
86
|
source: 'text_chat',
|
|
87
87
|
text: message,
|
|
@@ -89,6 +89,7 @@ class SiduriRuntime {
|
|
|
89
89
|
history,
|
|
90
90
|
medium,
|
|
91
91
|
signal,
|
|
92
|
+
subtitleLanguage,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
}
|
package/dist/siduri-db.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ClaimStatus, DirectiveStatus } from './proposals';
|
|
1
2
|
export interface SelfIdentity {
|
|
2
3
|
companionId: string;
|
|
3
4
|
name: string;
|
|
@@ -19,7 +20,7 @@ export interface SelfDirective {
|
|
|
19
20
|
companionId: string;
|
|
20
21
|
priority?: number;
|
|
21
22
|
directive: string;
|
|
22
|
-
status:
|
|
23
|
+
status: DirectiveStatus;
|
|
23
24
|
category: 'behavioral' | 'guardrail' | 'relational' | string;
|
|
24
25
|
scopeActor?: string;
|
|
25
26
|
supersedesId?: string;
|
|
@@ -90,7 +91,7 @@ export interface MemoryClaim {
|
|
|
90
91
|
subject: string;
|
|
91
92
|
predicate: string;
|
|
92
93
|
value: string;
|
|
93
|
-
status:
|
|
94
|
+
status: ClaimStatus;
|
|
94
95
|
confidence: number;
|
|
95
96
|
validFrom?: string;
|
|
96
97
|
validUntil?: string;
|
|
@@ -99,6 +100,7 @@ export interface MemoryClaim {
|
|
|
99
100
|
supersedes?: string;
|
|
100
101
|
sourceEventId?: string;
|
|
101
102
|
}
|
|
103
|
+
export declare function normalizeStatus(status?: string, defaultStatus?: string): string;
|
|
102
104
|
export interface SiduriDatabaseOptions {
|
|
103
105
|
dbPath?: string;
|
|
104
106
|
}
|
|
@@ -111,7 +113,9 @@ export declare class SiduriDatabase {
|
|
|
111
113
|
setIdentity(identity: SelfIdentity): void;
|
|
112
114
|
getPersonality(companionId: string): PersonalityTraits | undefined;
|
|
113
115
|
setPersonality(companionId: string, traits: PersonalityTraits): void;
|
|
116
|
+
private rowToSelfDirective;
|
|
114
117
|
getActiveDirectives(companionId: string): SelfDirective[];
|
|
118
|
+
getAllDirectives(companionId: string): SelfDirective[];
|
|
115
119
|
commitDirective(directive: SelfDirective): void;
|
|
116
120
|
getDirective(id: string, companionId?: string): SelfDirective | undefined;
|
|
117
121
|
approveDirective(id: string, companionId?: string): void;
|
|
@@ -135,11 +139,13 @@ export declare class SiduriDatabase {
|
|
|
135
139
|
recordEvent(event: EpisodicEvent): void;
|
|
136
140
|
getRecentEvents(companionId: string, limit?: number): EpisodicEvent[];
|
|
137
141
|
getEvent(id: string): EpisodicEvent | undefined;
|
|
142
|
+
private rowToMemoryClaim;
|
|
138
143
|
proposeClaim(claim: Omit<MemoryClaim, 'status' | 'confidence' | 'assertedAt'> & {
|
|
139
144
|
confidence?: number;
|
|
140
145
|
assertedAt?: string;
|
|
141
146
|
supersedes?: string;
|
|
142
147
|
sourceEventId?: string;
|
|
148
|
+
status?: string;
|
|
143
149
|
}): MemoryClaim;
|
|
144
150
|
approveClaim(id: string, companionId?: string): void;
|
|
145
151
|
rejectClaim(id: string, companionId?: string): void;
|
|
@@ -149,6 +155,7 @@ export declare class SiduriDatabase {
|
|
|
149
155
|
searchClaims(companionId: string, query: string, limit?: number): MemoryClaim[];
|
|
150
156
|
getPendingClaims(companionId: string, limit?: number): MemoryClaim[];
|
|
151
157
|
getApprovedClaims(companionId: string, limit?: number): MemoryClaim[];
|
|
158
|
+
getAllClaims(companionId?: string, limit?: number): MemoryClaim[];
|
|
152
159
|
getClaim(id: string): MemoryClaim | undefined;
|
|
153
160
|
resetMemory(companionId: string): void;
|
|
154
161
|
}
|
package/dist/siduri-db.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SiduriDatabase = void 0;
|
|
4
|
+
exports.normalizeStatus = normalizeStatus;
|
|
4
5
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5
6
|
const crypto = require('crypto');
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
7
8
|
const { DatabaseSync } = require('node:sqlite');
|
|
9
|
+
function normalizeStatus(status, defaultStatus = 'pending') {
|
|
10
|
+
if (!status)
|
|
11
|
+
return defaultStatus;
|
|
12
|
+
return status.toLowerCase().replace(/_/g, '-');
|
|
13
|
+
}
|
|
8
14
|
class SiduriDatabase {
|
|
9
15
|
db;
|
|
10
16
|
constructor(options = {}) {
|
|
@@ -41,7 +47,7 @@ class SiduriDatabase {
|
|
|
41
47
|
companion_id TEXT NOT NULL,
|
|
42
48
|
priority INTEGER DEFAULT 50,
|
|
43
49
|
directive TEXT NOT NULL,
|
|
44
|
-
status TEXT DEFAULT '
|
|
50
|
+
status TEXT DEFAULT 'active',
|
|
45
51
|
category TEXT DEFAULT 'behavioral',
|
|
46
52
|
scope_actor TEXT,
|
|
47
53
|
supersedes_id TEXT,
|
|
@@ -123,7 +129,7 @@ class SiduriDatabase {
|
|
|
123
129
|
subject TEXT NOT NULL,
|
|
124
130
|
predicate TEXT NOT NULL,
|
|
125
131
|
value TEXT NOT NULL,
|
|
126
|
-
status TEXT DEFAULT '
|
|
132
|
+
status TEXT DEFAULT 'pending',
|
|
127
133
|
confidence REAL DEFAULT 1.0,
|
|
128
134
|
valid_from TEXT,
|
|
129
135
|
valid_until TEXT,
|
|
@@ -272,30 +278,41 @@ class SiduriDatabase {
|
|
|
272
278
|
`);
|
|
273
279
|
stmt.run(companionId, traits.warmth, traits.formality, traits.sarcasm, traits.verbosity, traits.curiosity);
|
|
274
280
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
SELECT * FROM self_directives
|
|
278
|
-
WHERE companion_id = ? AND status = 'ACTIVE'
|
|
279
|
-
ORDER BY priority DESC, created_at ASC
|
|
280
|
-
`);
|
|
281
|
-
return stmt.all(companionId).map((row) => ({
|
|
281
|
+
rowToSelfDirective(row) {
|
|
282
|
+
return {
|
|
282
283
|
id: row.id,
|
|
283
284
|
companionId: row.companion_id,
|
|
284
285
|
priority: row.priority,
|
|
285
286
|
directive: row.directive,
|
|
286
|
-
status: row.status,
|
|
287
|
+
status: normalizeStatus(row.status, 'active'),
|
|
287
288
|
category: row.category,
|
|
288
289
|
scopeActor: row.scope_actor || undefined,
|
|
289
290
|
supersedesId: row.supersedes_id || undefined,
|
|
290
|
-
createdAt: row.created_at
|
|
291
|
-
}
|
|
291
|
+
createdAt: row.created_at,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
getActiveDirectives(companionId) {
|
|
295
|
+
const stmt = this.db.prepare(`
|
|
296
|
+
SELECT * FROM self_directives
|
|
297
|
+
WHERE companion_id = ? AND LOWER(status) = 'active'
|
|
298
|
+
ORDER BY priority DESC, created_at ASC
|
|
299
|
+
`);
|
|
300
|
+
return stmt.all(companionId).map((row) => this.rowToSelfDirective(row));
|
|
301
|
+
}
|
|
302
|
+
getAllDirectives(companionId) {
|
|
303
|
+
const stmt = this.db.prepare(`
|
|
304
|
+
SELECT * FROM self_directives
|
|
305
|
+
WHERE companion_id = ?
|
|
306
|
+
ORDER BY priority DESC, created_at ASC
|
|
307
|
+
`);
|
|
308
|
+
return stmt.all(companionId).map((row) => this.rowToSelfDirective(row));
|
|
292
309
|
}
|
|
293
310
|
commitDirective(directive) {
|
|
294
311
|
const stmt = this.db.prepare(`
|
|
295
312
|
INSERT INTO self_directives (id, companion_id, priority, directive, status, category, scope_actor, supersedes_id, created_at)
|
|
296
313
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
297
314
|
`);
|
|
298
|
-
stmt.run(directive.id, directive.companionId, directive.priority !== undefined ? directive.priority : 50, directive.directive, directive.status, directive.category || 'behavioral', directive.scopeActor || null, directive.supersedesId || null, directive.createdAt || new Date().toISOString());
|
|
315
|
+
stmt.run(directive.id, directive.companionId, directive.priority !== undefined ? directive.priority : 50, directive.directive, normalizeStatus(directive.status, 'active'), directive.category || 'behavioral', directive.scopeActor || null, directive.supersedesId || null, directive.createdAt || new Date().toISOString());
|
|
299
316
|
}
|
|
300
317
|
getDirective(id, companionId) {
|
|
301
318
|
const stmt = companionId
|
|
@@ -304,17 +321,7 @@ class SiduriDatabase {
|
|
|
304
321
|
const row = (companionId ? stmt.get(id, companionId) : stmt.get(id));
|
|
305
322
|
if (!row)
|
|
306
323
|
return undefined;
|
|
307
|
-
return
|
|
308
|
-
id: row.id,
|
|
309
|
-
companionId: row.companion_id,
|
|
310
|
-
priority: row.priority,
|
|
311
|
-
directive: row.directive,
|
|
312
|
-
status: row.status,
|
|
313
|
-
category: row.category,
|
|
314
|
-
scopeActor: row.scope_actor || undefined,
|
|
315
|
-
supersedesId: row.supersedes_id || undefined,
|
|
316
|
-
createdAt: row.created_at,
|
|
317
|
-
};
|
|
324
|
+
return this.rowToSelfDirective(row);
|
|
318
325
|
}
|
|
319
326
|
approveDirective(id, companionId) {
|
|
320
327
|
const findStmt = companionId
|
|
@@ -324,28 +331,28 @@ class SiduriDatabase {
|
|
|
324
331
|
if (!row) {
|
|
325
332
|
return;
|
|
326
333
|
}
|
|
327
|
-
if (row.status !== '
|
|
328
|
-
throw new Error(`Cannot approve directive '${id}': invalid transition from status '${row.status}' to '
|
|
334
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
335
|
+
throw new Error(`Cannot approve directive '${id}': invalid transition from status '${row.status}' to 'active' (only pending directives can be approved)`);
|
|
329
336
|
}
|
|
330
|
-
// If this directive supersedes an earlier directive, transition that prior directive to
|
|
337
|
+
// If this directive supersedes an earlier directive, transition that prior directive to superseded
|
|
331
338
|
if (row.supersedes_id) {
|
|
332
339
|
const supersededId = row.supersedes_id;
|
|
333
340
|
const effectiveCompanionId = companionId || row.companion_id;
|
|
334
341
|
if (effectiveCompanionId) {
|
|
335
|
-
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
342
|
+
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = 'superseded' WHERE id = ? AND companion_id = ?");
|
|
336
343
|
supersedeStmt.run(supersededId, effectiveCompanionId);
|
|
337
344
|
}
|
|
338
345
|
else {
|
|
339
|
-
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
346
|
+
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = 'superseded' WHERE id = ?");
|
|
340
347
|
supersedeStmt.run(supersededId);
|
|
341
348
|
}
|
|
342
349
|
}
|
|
343
350
|
if (companionId) {
|
|
344
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
351
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'active' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
345
352
|
stmt.run(id, companionId);
|
|
346
353
|
}
|
|
347
354
|
else {
|
|
348
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
355
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'active' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
349
356
|
stmt.run(id);
|
|
350
357
|
}
|
|
351
358
|
}
|
|
@@ -357,45 +364,45 @@ class SiduriDatabase {
|
|
|
357
364
|
if (!row) {
|
|
358
365
|
return;
|
|
359
366
|
}
|
|
360
|
-
if (row.status !== '
|
|
361
|
-
throw new Error(`Cannot reject directive '${id}': invalid transition from status '${row.status}' to '
|
|
367
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
368
|
+
throw new Error(`Cannot reject directive '${id}': invalid transition from status '${row.status}' to 'rejected' (only pending directives can be rejected)`);
|
|
362
369
|
}
|
|
363
370
|
if (companionId) {
|
|
364
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
371
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'rejected' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
365
372
|
stmt.run(id, companionId);
|
|
366
373
|
}
|
|
367
374
|
else {
|
|
368
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
375
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'rejected' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
369
376
|
stmt.run(id);
|
|
370
377
|
}
|
|
371
378
|
}
|
|
372
379
|
revokeDirective(id, companionId) {
|
|
373
380
|
if (companionId) {
|
|
374
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
381
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'revoked' WHERE id = ? AND companion_id = ?");
|
|
375
382
|
stmt.run(id, companionId);
|
|
376
383
|
}
|
|
377
384
|
else {
|
|
378
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
385
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'revoked' WHERE id = ?");
|
|
379
386
|
stmt.run(id);
|
|
380
387
|
}
|
|
381
388
|
}
|
|
382
389
|
expireDirective(id, companionId) {
|
|
383
390
|
if (companionId) {
|
|
384
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
391
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'expired' WHERE id = ? AND companion_id = ?");
|
|
385
392
|
stmt.run(id, companionId);
|
|
386
393
|
}
|
|
387
394
|
else {
|
|
388
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
395
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'expired' WHERE id = ?");
|
|
389
396
|
stmt.run(id);
|
|
390
397
|
}
|
|
391
398
|
}
|
|
392
399
|
disableDirective(id, companionId) {
|
|
393
400
|
if (companionId) {
|
|
394
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
401
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'disabled' WHERE id = ? AND companion_id = ?");
|
|
395
402
|
stmt.run(id, companionId);
|
|
396
403
|
}
|
|
397
404
|
else {
|
|
398
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
405
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'disabled' WHERE id = ?");
|
|
399
406
|
stmt.run(id);
|
|
400
407
|
}
|
|
401
408
|
}
|
|
@@ -603,9 +610,26 @@ class SiduriDatabase {
|
|
|
603
610
|
payload: JSON.parse(row.payload)
|
|
604
611
|
};
|
|
605
612
|
}
|
|
613
|
+
rowToMemoryClaim(row) {
|
|
614
|
+
return {
|
|
615
|
+
id: row.id,
|
|
616
|
+
companionId: row.companion_id,
|
|
617
|
+
subject: row.subject,
|
|
618
|
+
predicate: row.predicate,
|
|
619
|
+
value: row.value,
|
|
620
|
+
status: normalizeStatus(row.status, 'pending'),
|
|
621
|
+
confidence: row.confidence,
|
|
622
|
+
validFrom: row.valid_from || undefined,
|
|
623
|
+
validUntil: row.valid_until || undefined,
|
|
624
|
+
evidence: row.evidence ? (typeof row.evidence === 'string' ? JSON.parse(row.evidence) : row.evidence) : undefined,
|
|
625
|
+
assertedAt: row.asserted_at,
|
|
626
|
+
supersedes: row.supersedes || undefined,
|
|
627
|
+
sourceEventId: row.source_event_id || undefined,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
606
630
|
proposeClaim(claim) {
|
|
607
631
|
const id = claim.id || crypto.randomUUID();
|
|
608
|
-
const status = '
|
|
632
|
+
const status = normalizeStatus(claim.status, 'pending');
|
|
609
633
|
const confidence = claim.confidence ?? 1.0;
|
|
610
634
|
const assertedAt = claim.assertedAt || new Date().toISOString();
|
|
611
635
|
const stmt = this.db.prepare(`
|
|
@@ -616,7 +640,7 @@ class SiduriDatabase {
|
|
|
616
640
|
return {
|
|
617
641
|
...claim,
|
|
618
642
|
id,
|
|
619
|
-
status,
|
|
643
|
+
status: status,
|
|
620
644
|
confidence,
|
|
621
645
|
assertedAt,
|
|
622
646
|
supersedes: claim.supersedes,
|
|
@@ -631,67 +655,67 @@ class SiduriDatabase {
|
|
|
631
655
|
if (!row) {
|
|
632
656
|
return;
|
|
633
657
|
}
|
|
634
|
-
if (row.status !== '
|
|
635
|
-
throw new Error(`Cannot approve claim '${id}': invalid transition from status '${row.status}' to '
|
|
658
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
659
|
+
throw new Error(`Cannot approve claim '${id}': invalid transition from status '${row.status}' to 'approved' (only pending claims can be approved)`);
|
|
636
660
|
}
|
|
637
|
-
// If this claim supersedes an earlier claim, transition that prior claim to
|
|
661
|
+
// If this claim supersedes an earlier claim, transition that prior claim to superseded
|
|
638
662
|
if (row.supersedes) {
|
|
639
663
|
const supersededId = row.supersedes;
|
|
640
664
|
if (companionId) {
|
|
641
|
-
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
665
|
+
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = 'superseded' WHERE id = ? AND companion_id = ?");
|
|
642
666
|
supersedeStmt.run(supersededId, companionId);
|
|
643
667
|
}
|
|
644
668
|
else {
|
|
645
|
-
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
669
|
+
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = 'superseded' WHERE id = ?");
|
|
646
670
|
supersedeStmt.run(supersededId);
|
|
647
671
|
}
|
|
648
672
|
}
|
|
649
673
|
if (companionId) {
|
|
650
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
674
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'approved' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
651
675
|
stmt.run(id, companionId);
|
|
652
676
|
}
|
|
653
677
|
else {
|
|
654
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
678
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'approved' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
655
679
|
stmt.run(id);
|
|
656
680
|
}
|
|
657
681
|
}
|
|
658
682
|
rejectClaim(id, companionId) {
|
|
659
683
|
if (companionId) {
|
|
660
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
684
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'rejected' WHERE id = ? AND companion_id = ?");
|
|
661
685
|
stmt.run(id, companionId);
|
|
662
686
|
}
|
|
663
687
|
else {
|
|
664
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
688
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'rejected' WHERE id = ?");
|
|
665
689
|
stmt.run(id);
|
|
666
690
|
}
|
|
667
691
|
}
|
|
668
692
|
revokeClaim(id, companionId) {
|
|
669
693
|
if (companionId) {
|
|
670
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
694
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'revoked' WHERE id = ? AND companion_id = ?");
|
|
671
695
|
stmt.run(id, companionId);
|
|
672
696
|
}
|
|
673
697
|
else {
|
|
674
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
698
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'revoked' WHERE id = ?");
|
|
675
699
|
stmt.run(id);
|
|
676
700
|
}
|
|
677
701
|
}
|
|
678
702
|
expireClaim(id, companionId) {
|
|
679
703
|
if (companionId) {
|
|
680
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
704
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'expired' WHERE id = ? AND companion_id = ?");
|
|
681
705
|
stmt.run(id, companionId);
|
|
682
706
|
}
|
|
683
707
|
else {
|
|
684
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
708
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'expired' WHERE id = ?");
|
|
685
709
|
stmt.run(id);
|
|
686
710
|
}
|
|
687
711
|
}
|
|
688
712
|
markClaimSessionOnly(id, companionId) {
|
|
689
713
|
if (companionId) {
|
|
690
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
714
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'session-only' WHERE id = ? AND companion_id = ?");
|
|
691
715
|
stmt.run(id, companionId);
|
|
692
716
|
}
|
|
693
717
|
else {
|
|
694
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
718
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'session-only' WHERE id = ?");
|
|
695
719
|
stmt.run(id);
|
|
696
720
|
}
|
|
697
721
|
}
|
|
@@ -699,82 +723,33 @@ class SiduriDatabase {
|
|
|
699
723
|
const stmt = this.db.prepare(`
|
|
700
724
|
SELECT c.* FROM memory_claims c
|
|
701
725
|
JOIN memory_search s ON c.rowid = s.rowid
|
|
702
|
-
WHERE c.companion_id = ? AND c.status = '
|
|
726
|
+
WHERE c.companion_id = ? AND LOWER(c.status) = 'approved' AND memory_search MATCH ?
|
|
703
727
|
ORDER BY rank
|
|
704
728
|
LIMIT ?
|
|
705
729
|
`);
|
|
706
|
-
return stmt.all(companionId, query, limit).map((row) => (
|
|
707
|
-
id: row.id,
|
|
708
|
-
companionId: row.companion_id,
|
|
709
|
-
subject: row.subject,
|
|
710
|
-
predicate: row.predicate,
|
|
711
|
-
value: row.value,
|
|
712
|
-
status: row.status,
|
|
713
|
-
confidence: row.confidence,
|
|
714
|
-
validFrom: row.valid_from || undefined,
|
|
715
|
-
validUntil: row.valid_until || undefined,
|
|
716
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
717
|
-
assertedAt: row.asserted_at,
|
|
718
|
-
supersedes: row.supersedes || undefined,
|
|
719
|
-
sourceEventId: row.source_event_id || undefined,
|
|
720
|
-
}));
|
|
730
|
+
return stmt.all(companionId, query, limit).map((row) => this.rowToMemoryClaim(row));
|
|
721
731
|
}
|
|
722
732
|
getPendingClaims(companionId, limit = 50) {
|
|
723
|
-
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND status = '
|
|
724
|
-
return stmt.all(companionId, limit).map((row) => (
|
|
725
|
-
id: row.id,
|
|
726
|
-
companionId: row.companion_id,
|
|
727
|
-
subject: row.subject,
|
|
728
|
-
predicate: row.predicate,
|
|
729
|
-
value: row.value,
|
|
730
|
-
status: row.status,
|
|
731
|
-
confidence: row.confidence,
|
|
732
|
-
validFrom: row.valid_from || undefined,
|
|
733
|
-
validUntil: row.valid_until || undefined,
|
|
734
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
735
|
-
assertedAt: row.asserted_at,
|
|
736
|
-
supersedes: row.supersedes || undefined,
|
|
737
|
-
sourceEventId: row.source_event_id || undefined,
|
|
738
|
-
}));
|
|
733
|
+
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND LOWER(status) = 'pending' ORDER BY asserted_at DESC LIMIT ?");
|
|
734
|
+
return stmt.all(companionId, limit).map((row) => this.rowToMemoryClaim(row));
|
|
739
735
|
}
|
|
740
736
|
getApprovedClaims(companionId, limit = 50) {
|
|
741
|
-
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND status = '
|
|
742
|
-
return stmt.all(companionId, limit).map((row) => (
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
validFrom: row.valid_from || undefined,
|
|
751
|
-
validUntil: row.valid_until || undefined,
|
|
752
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
753
|
-
assertedAt: row.asserted_at,
|
|
754
|
-
supersedes: row.supersedes || undefined,
|
|
755
|
-
sourceEventId: row.source_event_id || undefined,
|
|
756
|
-
}));
|
|
737
|
+
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND LOWER(status) = 'approved' ORDER BY asserted_at DESC LIMIT ?");
|
|
738
|
+
return stmt.all(companionId, limit).map((row) => this.rowToMemoryClaim(row));
|
|
739
|
+
}
|
|
740
|
+
getAllClaims(companionId, limit = 100) {
|
|
741
|
+
const stmt = companionId
|
|
742
|
+
? this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? ORDER BY asserted_at DESC LIMIT ?")
|
|
743
|
+
: this.db.prepare("SELECT * FROM memory_claims ORDER BY asserted_at DESC LIMIT ?");
|
|
744
|
+
const rows = companionId ? stmt.all(companionId, limit) : stmt.all(limit);
|
|
745
|
+
return rows.map((row) => this.rowToMemoryClaim(row));
|
|
757
746
|
}
|
|
758
747
|
getClaim(id) {
|
|
759
748
|
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE id = ?");
|
|
760
749
|
const row = stmt.get(id);
|
|
761
750
|
if (!row)
|
|
762
751
|
return undefined;
|
|
763
|
-
return
|
|
764
|
-
id: row.id,
|
|
765
|
-
companionId: row.companion_id,
|
|
766
|
-
subject: row.subject,
|
|
767
|
-
predicate: row.predicate,
|
|
768
|
-
value: row.value,
|
|
769
|
-
status: row.status,
|
|
770
|
-
confidence: row.confidence,
|
|
771
|
-
validFrom: row.valid_from || undefined,
|
|
772
|
-
validUntil: row.valid_until || undefined,
|
|
773
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
774
|
-
assertedAt: row.asserted_at,
|
|
775
|
-
supersedes: row.supersedes || undefined,
|
|
776
|
-
sourceEventId: row.source_event_id || undefined,
|
|
777
|
-
};
|
|
752
|
+
return this.rowToMemoryClaim(row);
|
|
778
753
|
}
|
|
779
754
|
resetMemory(companionId) {
|
|
780
755
|
const deleteClaims = this.db.prepare("DELETE FROM memory_claims WHERE companion_id = ?");
|
package/dist/siduri-db.test.js
CHANGED
|
@@ -370,7 +370,7 @@ describe('SiduriDatabase', () => {
|
|
|
370
370
|
evidence: ['lore book chapter 3'],
|
|
371
371
|
assertedAt: new Date().toISOString(),
|
|
372
372
|
});
|
|
373
|
-
expect(claim.status).toBe('
|
|
373
|
+
expect(claim.status).toBe('pending');
|
|
374
374
|
expect(claim.subject).toBe('Kur');
|
|
375
375
|
expect(claim.predicate).toBe('is');
|
|
376
376
|
expect(claim.value).toBe('a dark entity from the underworld');
|
|
@@ -401,7 +401,7 @@ describe('SiduriDatabase', () => {
|
|
|
401
401
|
const approved = db.getApprovedClaims('siduri-test');
|
|
402
402
|
expect(approved).toHaveLength(1);
|
|
403
403
|
expect(approved[0].id).toBe(claim1.id);
|
|
404
|
-
expect(approved[0].status).toBe('
|
|
404
|
+
expect(approved[0].status).toBe('approved');
|
|
405
405
|
});
|
|
406
406
|
it('searches claims using FTS5 full-text search', () => {
|
|
407
407
|
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
@@ -617,7 +617,7 @@ describe('SiduriDatabase', () => {
|
|
|
617
617
|
expect(db2.getInventory(cId)).toHaveLength(1);
|
|
618
618
|
expect(db2.getInventory(cId)[0].entityName).toBe('Aged Wine');
|
|
619
619
|
const claims = db2.searchClaims(cId, 'wine');
|
|
620
|
-
expect(claims.some((c) => c.id === claim.id && c.status === '
|
|
620
|
+
expect(claims.some((c) => c.id === claim.id && c.status === 'approved')).toBe(true);
|
|
621
621
|
db2.close();
|
|
622
622
|
// Prevent afterEach from double-closing
|
|
623
623
|
db = null;
|
|
@@ -691,7 +691,7 @@ describe('SiduriDatabase', () => {
|
|
|
691
691
|
const active = db.getActiveDirectives(cId);
|
|
692
692
|
expect(active).toHaveLength(1);
|
|
693
693
|
expect(active[0].id).toBe(dId);
|
|
694
|
-
expect(active[0].status).toBe('
|
|
694
|
+
expect(active[0].status).toBe('active');
|
|
695
695
|
// 3. Revoke directive
|
|
696
696
|
db.revokeDirective(dId);
|
|
697
697
|
expect(db.getActiveDirectives(cId)).toHaveLength(0);
|
|
@@ -702,7 +702,7 @@ describe('SiduriDatabase', () => {
|
|
|
702
702
|
companionId: cId,
|
|
703
703
|
priority: 50,
|
|
704
704
|
directive: 'Unsafe rule',
|
|
705
|
-
status: '
|
|
705
|
+
status: 'pending',
|
|
706
706
|
category: 'behavioral',
|
|
707
707
|
});
|
|
708
708
|
db.rejectDirective(d2Id);
|
|
@@ -717,22 +717,22 @@ describe('SiduriDatabase', () => {
|
|
|
717
717
|
companionId: cId,
|
|
718
718
|
priority: 50,
|
|
719
719
|
directive: 'Rejected directive',
|
|
720
|
-
status: '
|
|
720
|
+
status: 'rejected',
|
|
721
721
|
category: 'behavioral',
|
|
722
722
|
});
|
|
723
|
-
expect(() => db.approveDirective('dir-rejected-1')).toThrow(/invalid transition from status '
|
|
723
|
+
expect(() => db.approveDirective('dir-rejected-1')).toThrow(/invalid transition from status 'rejected' to 'active'/i);
|
|
724
724
|
// 2. Commit directive in ACTIVE state
|
|
725
725
|
db.commitDirective({
|
|
726
726
|
id: 'dir-active-1',
|
|
727
727
|
companionId: cId,
|
|
728
728
|
priority: 50,
|
|
729
729
|
directive: 'Already active directive',
|
|
730
|
-
status: '
|
|
730
|
+
status: 'active',
|
|
731
731
|
category: 'behavioral',
|
|
732
732
|
});
|
|
733
|
-
expect(() => db.approveDirective('dir-active-1')).toThrow(/invalid transition from status '
|
|
733
|
+
expect(() => db.approveDirective('dir-active-1')).toThrow(/invalid transition from status 'active' to 'active'/i);
|
|
734
734
|
// 3. Rejecting an already ACTIVE directive throws
|
|
735
|
-
expect(() => db.rejectDirective('dir-active-1')).toThrow(/invalid transition from status '
|
|
735
|
+
expect(() => db.rejectDirective('dir-active-1')).toThrow(/invalid transition from status 'active' to 'rejected'/i);
|
|
736
736
|
});
|
|
737
737
|
it('automatically marks prior directive as SUPERSEDED when approving superseding directive', () => {
|
|
738
738
|
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
@@ -766,7 +766,7 @@ describe('SiduriDatabase', () => {
|
|
|
766
766
|
expect(active).toHaveLength(1);
|
|
767
767
|
expect(active[0].id).toBe('dir-replacement-1');
|
|
768
768
|
const original = db.getDirective('dir-original-1', cId);
|
|
769
|
-
expect(original?.status).toBe('
|
|
769
|
+
expect(original?.status).toBe('superseded');
|
|
770
770
|
});
|
|
771
771
|
it('enforces companion isolation on directive approval', () => {
|
|
772
772
|
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
@@ -777,14 +777,14 @@ describe('SiduriDatabase', () => {
|
|
|
777
777
|
companionId: cIdB,
|
|
778
778
|
priority: 50,
|
|
779
779
|
directive: 'Beta private rule',
|
|
780
|
-
status: '
|
|
780
|
+
status: 'pending',
|
|
781
781
|
category: 'behavioral',
|
|
782
782
|
});
|
|
783
783
|
// Alpha attempts to approve Beta's directive scoped to Alpha
|
|
784
784
|
db.approveDirective('dir-beta-1', cIdA);
|
|
785
|
-
// Beta's directive must remain
|
|
785
|
+
// Beta's directive must remain pending and unapproved
|
|
786
786
|
const betaDirective = db.getDirective('dir-beta-1', cIdB);
|
|
787
|
-
expect(betaDirective?.status).toBe('
|
|
787
|
+
expect(betaDirective?.status).toBe('pending');
|
|
788
788
|
expect(db.getActiveDirectives(cIdB)).toHaveLength(0);
|
|
789
789
|
// Beta approves its own directive successfully
|
|
790
790
|
db.approveDirective('dir-beta-1', cIdB);
|
|
@@ -800,7 +800,7 @@ describe('SiduriDatabase', () => {
|
|
|
800
800
|
predicate: 'likes',
|
|
801
801
|
value: 'matcha',
|
|
802
802
|
});
|
|
803
|
-
expect(claim.status).toBe('
|
|
803
|
+
expect(claim.status).toBe('pending');
|
|
804
804
|
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
805
805
|
// Approve
|
|
806
806
|
db.approveClaim('claim-1');
|
|
@@ -835,7 +835,7 @@ describe('SiduriDatabase', () => {
|
|
|
835
835
|
});
|
|
836
836
|
db.rejectClaim(rejectedClaim.id);
|
|
837
837
|
// Attempting to approve a REJECTED claim must throw
|
|
838
|
-
expect(() => db.approveClaim(rejectedClaim.id)).toThrow(/invalid transition from status '
|
|
838
|
+
expect(() => db.approveClaim(rejectedClaim.id)).toThrow(/invalid transition from status 'rejected' to 'approved'/i);
|
|
839
839
|
// 2. Propose and approve claim, then revoke
|
|
840
840
|
const revokedClaim = db.proposeClaim({
|
|
841
841
|
id: 'claim-revoked',
|
|
@@ -847,7 +847,7 @@ describe('SiduriDatabase', () => {
|
|
|
847
847
|
db.approveClaim(revokedClaim.id);
|
|
848
848
|
db.revokeClaim(revokedClaim.id);
|
|
849
849
|
// Attempting to approve a REVOKED claim must throw
|
|
850
|
-
expect(() => db.approveClaim(revokedClaim.id)).toThrow(/invalid transition from status '
|
|
850
|
+
expect(() => db.approveClaim(revokedClaim.id)).toThrow(/invalid transition from status 'revoked' to 'approved'/i);
|
|
851
851
|
// 3. Propose and expire claim
|
|
852
852
|
const expiredClaim = db.proposeClaim({
|
|
853
853
|
id: 'claim-expired',
|
|
@@ -858,7 +858,7 @@ describe('SiduriDatabase', () => {
|
|
|
858
858
|
});
|
|
859
859
|
db.expireClaim(expiredClaim.id);
|
|
860
860
|
// Attempting to approve an EXPIRED claim must throw
|
|
861
|
-
expect(() => db.approveClaim(expiredClaim.id)).toThrow(/invalid transition from status '
|
|
861
|
+
expect(() => db.approveClaim(expiredClaim.id)).toThrow(/invalid transition from status 'expired' to 'approved'/i);
|
|
862
862
|
});
|
|
863
863
|
});
|
|
864
864
|
});
|
package/package.json
CHANGED