@siduri-x/core 2.0.1 → 2.0.2
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/action-policy.d.ts +8 -1
- package/dist/action-policy.js +84 -24
- package/dist/action-policy.test.js +67 -1
- package/dist/action.d.ts +1 -1
- package/dist/capability.d.ts +6 -2
- package/dist/capability.js +5 -1
- package/dist/capability.test.js +1 -0
- package/dist/chat-contract.d.ts +3 -1
- package/dist/chat-contract.js +5 -2
- package/dist/container.d.ts +74 -0
- package/dist/container.js +81 -0
- package/dist/context.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/input-normalizer.js +3 -1
- package/dist/perception-pipeline.d.ts +76 -0
- package/dist/perception-pipeline.js +255 -0
- package/dist/perception-pipeline.test.d.ts +1 -0
- package/dist/perception-pipeline.test.js +65 -0
- package/dist/runtime-facades.test.js +27 -27
- package/dist/runtime.d.ts +36 -113
- package/dist/runtime.js +58 -403
- package/dist/siduri-db.test.js +4 -3
- package/dist/sqlite-action-store.d.ts +1 -1
- package/dist/sqlite-action-store.js +37 -6
- package/dist/sqlite-action-store.test.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.envelopeAssemblyStage = exports.mouthDeliveryStage = exports.experienceEmissionStage = exports.actionExecutionStage = exports.memorySettlementStage = exports.responseGatingStage = exports.cognitionPlanningStage = exports.promptCompilationStage = exports.contextRetrievalStage = exports.intentClassificationStage = exports.inputNormalizationStage = exports.earTranscriptionStage = exports.PerceptionPipeline = void 0;
|
|
4
|
+
exports.createDefaultPerceptionPipeline = createDefaultPerceptionPipeline;
|
|
5
|
+
const input_normalizer_1 = require("./input-normalizer");
|
|
6
|
+
const intent_classifier_1 = require("./intent-classifier");
|
|
7
|
+
const context_retriever_1 = require("./context-retriever");
|
|
8
|
+
const prompt_compiler_1 = require("./prompt-compiler");
|
|
9
|
+
const cognition_planner_1 = require("./cognition-planner");
|
|
10
|
+
const memory_settler_1 = require("./memory-settler");
|
|
11
|
+
const action_executor_1 = require("./action-executor");
|
|
12
|
+
const experience_emitter_1 = require("./experience-emitter");
|
|
13
|
+
const response_envelope_1 = require("./response-envelope");
|
|
14
|
+
class PerceptionPipeline {
|
|
15
|
+
stages;
|
|
16
|
+
constructor(stages) {
|
|
17
|
+
this.stages = stages;
|
|
18
|
+
}
|
|
19
|
+
async execute(context) {
|
|
20
|
+
for (const stage of this.stages) {
|
|
21
|
+
const continueNext = await stage(context);
|
|
22
|
+
if (continueNext === false) {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return context.responseEnvelope;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.PerceptionPipeline = PerceptionPipeline;
|
|
30
|
+
// --- Individual Pipeline Stages ---
|
|
31
|
+
const earTranscriptionStage = async (context) => {
|
|
32
|
+
let rawText = context.perception.text || '';
|
|
33
|
+
if (!rawText && context.perception.audioBuffer && context.organs.ear && typeof context.organs.ear.transcribeAudio === 'function') {
|
|
34
|
+
rawText = await context.organs.ear.transcribeAudio(context.perception.audioBuffer);
|
|
35
|
+
}
|
|
36
|
+
context.rawText = rawText;
|
|
37
|
+
};
|
|
38
|
+
exports.earTranscriptionStage = earTranscriptionStage;
|
|
39
|
+
const inputNormalizationStage = async (context) => {
|
|
40
|
+
const roleOrContext = context.perception.context || context.perception.roleOrContext || 'OWNER';
|
|
41
|
+
const history = context.perception.history || [];
|
|
42
|
+
const input = await (0, input_normalizer_1.normalizeUserInput)(context.rawText || '', roleOrContext, history, context.companionId, context.organs.ear);
|
|
43
|
+
context.input = input;
|
|
44
|
+
const sessionKey = input.requestContext.actor.sessionId ||
|
|
45
|
+
input.requestContext.conversation.correlationId ||
|
|
46
|
+
'default';
|
|
47
|
+
context.sessionKey = sessionKey;
|
|
48
|
+
const currentMessage = { role: 'user', content: input.perceivedText };
|
|
49
|
+
const boundedSessionHistory = [...input.boundedHistory, currentMessage].slice(-20);
|
|
50
|
+
context.sessionHistory.setHistory(sessionKey, boundedSessionHistory);
|
|
51
|
+
context.sessionHistory.setHistory('default', boundedSessionHistory);
|
|
52
|
+
};
|
|
53
|
+
exports.inputNormalizationStage = inputNormalizationStage;
|
|
54
|
+
const intentClassificationStage = async (context) => {
|
|
55
|
+
if (!context.input)
|
|
56
|
+
return;
|
|
57
|
+
const intent = await (0, intent_classifier_1.classifyInputIntentAsync)(context.input.perceivedText, context.input.requestContext, context.organs.ear?.classifyIntent
|
|
58
|
+
? (t, c) => context.organs.ear.classifyIntent(t, c)
|
|
59
|
+
: undefined);
|
|
60
|
+
context.intent = intent;
|
|
61
|
+
};
|
|
62
|
+
exports.intentClassificationStage = intentClassificationStage;
|
|
63
|
+
const contextRetrievalStage = async (context) => {
|
|
64
|
+
if (!context.input || !context.intent)
|
|
65
|
+
return;
|
|
66
|
+
const contextRetrieval = await (0, context_retriever_1.retrieveRuntimeContext)({
|
|
67
|
+
companionId: context.companionId,
|
|
68
|
+
perceivedText: context.input.perceivedText,
|
|
69
|
+
requestContext: context.input.requestContext,
|
|
70
|
+
role: context.input.role,
|
|
71
|
+
isContextObject: context.input.isContextObject,
|
|
72
|
+
shouldQueryKnowledge: context.intent.shouldQueryKnowledge,
|
|
73
|
+
knowledge: context.organs.knowledge,
|
|
74
|
+
memory: context.organs.memory,
|
|
75
|
+
self: context.organs.self,
|
|
76
|
+
externalKnowledge: context.organs.externalKnowledge,
|
|
77
|
+
});
|
|
78
|
+
context.contextRetrieval = contextRetrieval;
|
|
79
|
+
};
|
|
80
|
+
exports.contextRetrievalStage = contextRetrievalStage;
|
|
81
|
+
const promptCompilationStage = async (context) => {
|
|
82
|
+
if (!context.input || !context.contextRetrieval)
|
|
83
|
+
return;
|
|
84
|
+
const prompts = await (0, prompt_compiler_1.compilePrompts)({
|
|
85
|
+
companionName: context.companionName,
|
|
86
|
+
companionId: context.companionId,
|
|
87
|
+
role: context.input.role,
|
|
88
|
+
requestContext: context.input.requestContext,
|
|
89
|
+
behavior: context.organs.behavior,
|
|
90
|
+
activeDirectives: context.contextRetrieval.activeDirectives,
|
|
91
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
92
|
+
knowledgeData: context.contextRetrieval.knowledgeData,
|
|
93
|
+
memoryData: context.contextRetrieval.memoryData,
|
|
94
|
+
lifeContext: context.contextRetrieval.lifeContext,
|
|
95
|
+
});
|
|
96
|
+
context.prompts = prompts;
|
|
97
|
+
};
|
|
98
|
+
exports.promptCompilationStage = promptCompilationStage;
|
|
99
|
+
const cognitionPlanningStage = async (context) => {
|
|
100
|
+
if (!context.input || !context.prompts || !context.sessionKey)
|
|
101
|
+
return;
|
|
102
|
+
const plan = await (0, cognition_planner_1.generateCognitionPlan)({
|
|
103
|
+
companionName: context.companionName,
|
|
104
|
+
brain: context.organs.brain,
|
|
105
|
+
systemPrompt: context.prompts.systemPrompt,
|
|
106
|
+
contextPrompt: context.prompts.contextPrompt,
|
|
107
|
+
recentMessages: context.sessionHistory.getHistory(context.sessionKey).slice(-10),
|
|
108
|
+
recipient: context.input.role,
|
|
109
|
+
perceivedText: context.input.perceivedText,
|
|
110
|
+
});
|
|
111
|
+
context.plan = plan;
|
|
112
|
+
};
|
|
113
|
+
exports.cognitionPlanningStage = cognitionPlanningStage;
|
|
114
|
+
const responseGatingStage = async (context) => {
|
|
115
|
+
if (!context.input || !context.plan || !context.contextRetrieval || !context.sessionKey)
|
|
116
|
+
return;
|
|
117
|
+
const stagedPlan = context.gating.stageResponse({
|
|
118
|
+
requestContext: context.input.requestContext,
|
|
119
|
+
candidateSpeech: context.plan.speech,
|
|
120
|
+
candidateLanguage: context.plan.language || 'ja',
|
|
121
|
+
internalMonologue: context.plan.internalMonologue,
|
|
122
|
+
memoryProposals: context.plan.memoryProposals,
|
|
123
|
+
behaviorProposals: context.plan.behaviorProposals,
|
|
124
|
+
evidenceRecords: context.contextRetrieval.collectedEvidence,
|
|
125
|
+
citations: context.contextRetrieval.citations,
|
|
126
|
+
});
|
|
127
|
+
context.stagedPlan = stagedPlan;
|
|
128
|
+
const gateEval = context.gating.evaluateGate(stagedPlan, context.contextRetrieval.collectedEvidence);
|
|
129
|
+
context.gateEval = gateEval;
|
|
130
|
+
if (!gateEval.admissible) {
|
|
131
|
+
context.responseEnvelope = (0, response_envelope_1.createGateRejectionEnvelope)(stagedPlan, gateEval);
|
|
132
|
+
return false; // Terminate pipeline early upon rejection
|
|
133
|
+
}
|
|
134
|
+
context.sessionHistory.append(context.sessionKey, { role: 'assistant', content: context.plan.speech });
|
|
135
|
+
context.sessionHistory.append('default', { role: 'assistant', content: context.plan.speech });
|
|
136
|
+
};
|
|
137
|
+
exports.responseGatingStage = responseGatingStage;
|
|
138
|
+
const memorySettlementStage = async (context) => {
|
|
139
|
+
if (!context.input || !context.plan || !context.intent)
|
|
140
|
+
return;
|
|
141
|
+
const memorySettlement = await (0, memory_settler_1.settleMemoryProposals)({
|
|
142
|
+
companionId: context.companionId,
|
|
143
|
+
perceivedText: context.input.perceivedText,
|
|
144
|
+
role: context.input.role,
|
|
145
|
+
requestContext: context.input.requestContext,
|
|
146
|
+
memory: context.organs.memory,
|
|
147
|
+
explicitTeaching: context.intent.explicitTeaching,
|
|
148
|
+
plan: context.plan,
|
|
149
|
+
});
|
|
150
|
+
context.memorySettlement = memorySettlement;
|
|
151
|
+
};
|
|
152
|
+
exports.memorySettlementStage = memorySettlementStage;
|
|
153
|
+
const actionExecutionStage = async (context) => {
|
|
154
|
+
if (!context.input || !context.plan)
|
|
155
|
+
return;
|
|
156
|
+
const actionResults = await (0, action_executor_1.executeActionIntents)({
|
|
157
|
+
actionIntents: context.plan.actionIntents,
|
|
158
|
+
requestContext: context.input.requestContext,
|
|
159
|
+
actionPolicy: context.actionPolicy,
|
|
160
|
+
hands: context.organs.hands,
|
|
161
|
+
});
|
|
162
|
+
context.actionResults = actionResults;
|
|
163
|
+
};
|
|
164
|
+
exports.actionExecutionStage = actionExecutionStage;
|
|
165
|
+
const experienceEmissionStage = async (context) => {
|
|
166
|
+
if (!context.input || !context.plan || !context.stagedPlan || !context.gateEval)
|
|
167
|
+
return;
|
|
168
|
+
const experienceEmission = await (0, experience_emitter_1.emitExperienceEvents)({
|
|
169
|
+
companionId: context.companionId,
|
|
170
|
+
requestContext: context.input.requestContext,
|
|
171
|
+
stagedPlan: context.stagedPlan,
|
|
172
|
+
gateEval: context.gateEval,
|
|
173
|
+
speech: context.plan.speech,
|
|
174
|
+
language: context.plan.language || 'ja',
|
|
175
|
+
dispatcher: context.dispatcher,
|
|
176
|
+
voice: context.organs.voice,
|
|
177
|
+
body: context.organs.body,
|
|
178
|
+
});
|
|
179
|
+
context.experienceEmission = experienceEmission;
|
|
180
|
+
};
|
|
181
|
+
exports.experienceEmissionStage = experienceEmissionStage;
|
|
182
|
+
const mouthDeliveryStage = async (context) => {
|
|
183
|
+
if (!context.plan || !context.stagedPlan || !context.gateEval || !context.contextRetrieval)
|
|
184
|
+
return;
|
|
185
|
+
let mouthDelivery;
|
|
186
|
+
if (context.organs.mouth && typeof context.organs.mouth.speak === 'function') {
|
|
187
|
+
try {
|
|
188
|
+
const avatarEvent = context.experienceEmission?.experienceEvents.find((e) => e.kind === 'avatar');
|
|
189
|
+
mouthDelivery = await context.organs.mouth.speak({
|
|
190
|
+
utteranceId: context.stagedPlan.responseId,
|
|
191
|
+
companionId: context.companionId,
|
|
192
|
+
responseId: context.stagedPlan.responseId,
|
|
193
|
+
correlationId: context.stagedPlan.correlationId,
|
|
194
|
+
text: context.plan.speech,
|
|
195
|
+
language: context.plan.language || 'ja',
|
|
196
|
+
subtitleJa: context.plan.speech,
|
|
197
|
+
subtitleEn: context.plan.speech,
|
|
198
|
+
spokenJa: context.plan.speech,
|
|
199
|
+
expression: avatarEvent?.expression,
|
|
200
|
+
medium: context.perception.medium,
|
|
201
|
+
signal: context.perception.signal,
|
|
202
|
+
audioUrl: context.experienceEmission?.speechId
|
|
203
|
+
? `/voice/stream?id=${context.experienceEmission.speechId}`
|
|
204
|
+
: undefined,
|
|
205
|
+
metadata: {
|
|
206
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
207
|
+
internalMonologue: context.plan.internalMonologue,
|
|
208
|
+
},
|
|
209
|
+
citations: context.gateEval.filteredCitations,
|
|
210
|
+
evidenceIds: context.gateEval.filteredEvidenceIds,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.error('[SiduriRuntime] Mouth delivery failed:', e?.message || e);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
context.mouthDelivery = mouthDelivery;
|
|
218
|
+
};
|
|
219
|
+
exports.mouthDeliveryStage = mouthDeliveryStage;
|
|
220
|
+
const envelopeAssemblyStage = async (context) => {
|
|
221
|
+
if (!context.stagedPlan || !context.plan || !context.gateEval || !context.contextRetrieval || !context.memorySettlement)
|
|
222
|
+
return;
|
|
223
|
+
const envelope = (0, response_envelope_1.assembleResponseEnvelope)({
|
|
224
|
+
stagedPlan: context.stagedPlan,
|
|
225
|
+
speech: context.plan.speech,
|
|
226
|
+
language: context.plan.language,
|
|
227
|
+
speechId: context.experienceEmission?.speechId,
|
|
228
|
+
createdMemoryProposals: context.memorySettlement.createdMemoryProposals,
|
|
229
|
+
memoryProposalReceipts: context.memorySettlement.memoryProposalReceipts,
|
|
230
|
+
actionResults: context.actionResults || [],
|
|
231
|
+
filteredEvidenceIds: context.gateEval.filteredEvidenceIds,
|
|
232
|
+
filteredCitations: context.gateEval.filteredCitations,
|
|
233
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
234
|
+
experienceEvents: context.experienceEmission?.experienceEvents || [],
|
|
235
|
+
mouthDelivery: context.mouthDelivery,
|
|
236
|
+
});
|
|
237
|
+
context.responseEnvelope = envelope;
|
|
238
|
+
};
|
|
239
|
+
exports.envelopeAssemblyStage = envelopeAssemblyStage;
|
|
240
|
+
function createDefaultPerceptionPipeline() {
|
|
241
|
+
return new PerceptionPipeline([
|
|
242
|
+
exports.earTranscriptionStage,
|
|
243
|
+
exports.inputNormalizationStage,
|
|
244
|
+
exports.intentClassificationStage,
|
|
245
|
+
exports.contextRetrievalStage,
|
|
246
|
+
exports.promptCompilationStage,
|
|
247
|
+
exports.cognitionPlanningStage,
|
|
248
|
+
exports.responseGatingStage,
|
|
249
|
+
exports.memorySettlementStage,
|
|
250
|
+
exports.actionExecutionStage,
|
|
251
|
+
exports.experienceEmissionStage,
|
|
252
|
+
exports.mouthDeliveryStage,
|
|
253
|
+
exports.envelopeAssemblyStage,
|
|
254
|
+
]);
|
|
255
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const perception_pipeline_1 = require("./perception-pipeline");
|
|
4
|
+
const gating_1 = require("./gating");
|
|
5
|
+
const action_policy_1 = require("./action-policy");
|
|
6
|
+
const dispatcher_1 = require("./dispatcher");
|
|
7
|
+
const session_history_1 = require("./session-history");
|
|
8
|
+
describe('PerceptionPipeline (Pipes & Filters Execution)', () => {
|
|
9
|
+
function createMockContext(overrides = {}) {
|
|
10
|
+
return {
|
|
11
|
+
companionId: 'test-companion',
|
|
12
|
+
companionName: 'Test Companion',
|
|
13
|
+
perception: {
|
|
14
|
+
source: 'text_chat',
|
|
15
|
+
text: 'Hello world',
|
|
16
|
+
roleOrContext: 'OWNER',
|
|
17
|
+
},
|
|
18
|
+
organs: {},
|
|
19
|
+
gating: new gating_1.ResponseGatingEngine(),
|
|
20
|
+
actionPolicy: new action_policy_1.ActionPolicyEngine(),
|
|
21
|
+
dispatcher: new dispatcher_1.ExperienceDispatcher(),
|
|
22
|
+
sessionHistory: new session_history_1.SessionHistoryManager(),
|
|
23
|
+
...overrides,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
test('executes stages in sequence and returns response envelope', async () => {
|
|
27
|
+
const executedStages = [];
|
|
28
|
+
const stageA = async (ctx) => {
|
|
29
|
+
executedStages.push('stageA');
|
|
30
|
+
ctx.rawText = (ctx.perception.text || '').toUpperCase();
|
|
31
|
+
};
|
|
32
|
+
const stageB = async (ctx) => {
|
|
33
|
+
executedStages.push('stageB');
|
|
34
|
+
ctx.responseEnvelope = { result: ctx.rawText };
|
|
35
|
+
};
|
|
36
|
+
const pipeline = new perception_pipeline_1.PerceptionPipeline([stageA, stageB]);
|
|
37
|
+
const ctx = createMockContext();
|
|
38
|
+
const result = await pipeline.execute(ctx);
|
|
39
|
+
expect(executedStages).toEqual(['stageA', 'stageB']);
|
|
40
|
+
expect(result).toEqual({ result: 'HELLO WORLD' });
|
|
41
|
+
});
|
|
42
|
+
test('halts pipeline execution early when a stage returns false', async () => {
|
|
43
|
+
const executedStages = [];
|
|
44
|
+
const stageA = async () => {
|
|
45
|
+
executedStages.push('stageA');
|
|
46
|
+
};
|
|
47
|
+
const stageReject = async (ctx) => {
|
|
48
|
+
executedStages.push('stageReject');
|
|
49
|
+
ctx.responseEnvelope = { rejected: true, reason: 'halt_early' };
|
|
50
|
+
return false; // halt
|
|
51
|
+
};
|
|
52
|
+
const stageB = async () => {
|
|
53
|
+
executedStages.push('stageB');
|
|
54
|
+
};
|
|
55
|
+
const pipeline = new perception_pipeline_1.PerceptionPipeline([stageA, stageReject, stageB]);
|
|
56
|
+
const ctx = createMockContext();
|
|
57
|
+
const result = await pipeline.execute(ctx);
|
|
58
|
+
expect(executedStages).toEqual(['stageA', 'stageReject']);
|
|
59
|
+
expect(result).toEqual({ rejected: true, reason: 'halt_early' });
|
|
60
|
+
});
|
|
61
|
+
test('createDefaultPerceptionPipeline constructs a 12-stage pipeline', () => {
|
|
62
|
+
const defaultPipeline = (0, perception_pipeline_1.createDefaultPerceptionPipeline)();
|
|
63
|
+
expect(defaultPipeline.stages.length).toBe(12);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
describe('
|
|
5
|
-
test('delegates vision and observation methods to configured organs', async () => {
|
|
3
|
+
const container_1 = require("./container");
|
|
4
|
+
describe('CompanionContainer & Direct Domain Access', () => {
|
|
5
|
+
test('delegates vision and observation methods to configured organs via container', async () => {
|
|
6
6
|
const mockVision = {
|
|
7
7
|
analyze: jest.fn().mockResolvedValue('an ancient artifact'),
|
|
8
8
|
};
|
|
@@ -11,23 +11,23 @@ describe('SiduriRuntime Facade Methods & Delegation', () => {
|
|
|
11
11
|
current: jest.fn().mockReturnValue([{ observationId: 'obs-1' }]),
|
|
12
12
|
clearExpired: jest.fn().mockReturnValue(1),
|
|
13
13
|
};
|
|
14
|
-
const
|
|
14
|
+
const container = new container_1.CompanionContainer('test-comp', { name: 'Test' }, {
|
|
15
15
|
vision: mockVision,
|
|
16
16
|
observation: mockObservation,
|
|
17
17
|
});
|
|
18
|
-
const visionResult = await
|
|
18
|
+
const visionResult = await container.vision.analyze('http://example.com/img.png', 'describe');
|
|
19
19
|
expect(visionResult).toBe('an ancient artifact');
|
|
20
20
|
expect(mockVision.analyze).toHaveBeenCalledWith('http://example.com/img.png', 'describe');
|
|
21
21
|
const frame = new Uint8Array([1, 2, 3]);
|
|
22
|
-
const obsResult = await
|
|
22
|
+
const obsResult = await container.observation.ingest(frame, 'camera-1', 'provider-x');
|
|
23
23
|
expect(obsResult.duplicate).toBe(false);
|
|
24
24
|
expect(mockObservation.ingest).toHaveBeenCalledWith(frame, 'camera-1', 'provider-x');
|
|
25
|
-
const cur =
|
|
25
|
+
const cur = container.observation.current();
|
|
26
26
|
expect(cur).toEqual([{ observationId: 'obs-1' }]);
|
|
27
|
-
const cleared =
|
|
27
|
+
const cleared = container.observation.clearExpired();
|
|
28
28
|
expect(cleared).toBe(1);
|
|
29
29
|
});
|
|
30
|
-
test('delegates memory operations
|
|
30
|
+
test('delegates memory operations directly on the memory organ', async () => {
|
|
31
31
|
const mockMemory = {
|
|
32
32
|
initialize: jest.fn().mockResolvedValue(undefined),
|
|
33
33
|
getClaims: jest.fn().mockResolvedValue([{ id: 'claim-1' }]),
|
|
@@ -42,39 +42,39 @@ describe('SiduriRuntime Facade Methods & Delegation', () => {
|
|
|
42
42
|
disableDirective: jest.fn().mockResolvedValue(undefined),
|
|
43
43
|
resetMemory: jest.fn().mockResolvedValue(undefined),
|
|
44
44
|
};
|
|
45
|
-
const
|
|
45
|
+
const container = new container_1.CompanionContainer('test-comp', { name: 'Test' }, {
|
|
46
46
|
memory: mockMemory,
|
|
47
47
|
});
|
|
48
|
-
expect(await
|
|
48
|
+
expect(await container.memory.getClaims(10)).toEqual([{ id: 'claim-1' }]);
|
|
49
49
|
expect(mockMemory.getClaims).toHaveBeenCalledWith(10);
|
|
50
|
-
expect(await
|
|
51
|
-
expect(await
|
|
52
|
-
await
|
|
50
|
+
expect(await container.memory.getPendingClaims()).toEqual([{ id: 'claim-pending-1' }]);
|
|
51
|
+
expect(await container.memory.getDirectives()).toEqual([{ id: 'dir-1' }]);
|
|
52
|
+
await container.memory.approveClaim('c-1');
|
|
53
53
|
expect(mockMemory.approveClaim).toHaveBeenCalledWith('c-1');
|
|
54
|
-
await
|
|
54
|
+
await container.memory.rejectClaim('c-2');
|
|
55
55
|
expect(mockMemory.rejectClaim).toHaveBeenCalledWith('c-2');
|
|
56
|
-
await
|
|
57
|
-
expect(mockMemory.updateClaim).toHaveBeenCalledWith('c-1', { value: '
|
|
58
|
-
await
|
|
56
|
+
await container.memory.updateClaim('c-1', { value: 'updated' });
|
|
57
|
+
expect(mockMemory.updateClaim).toHaveBeenCalledWith('c-1', { value: 'updated' });
|
|
58
|
+
await container.memory.approveDirective('d-1');
|
|
59
59
|
expect(mockMemory.approveDirective).toHaveBeenCalledWith('d-1');
|
|
60
|
-
await
|
|
60
|
+
await container.memory.rejectDirective('d-2');
|
|
61
61
|
expect(mockMemory.rejectDirective).toHaveBeenCalledWith('d-2');
|
|
62
|
-
await
|
|
62
|
+
await container.memory.revokeDirective('d-3');
|
|
63
63
|
expect(mockMemory.revokeDirective).toHaveBeenCalledWith('d-3');
|
|
64
|
-
await
|
|
64
|
+
await container.memory.disableDirective('d-4');
|
|
65
65
|
expect(mockMemory.disableDirective).toHaveBeenCalledWith('d-4');
|
|
66
|
-
await
|
|
66
|
+
await container.memory.resetMemory();
|
|
67
67
|
expect(mockMemory.resetMemory).toHaveBeenCalled();
|
|
68
68
|
});
|
|
69
69
|
test('configures SqliteActionStore when actionStore is sqlite', () => {
|
|
70
|
-
const
|
|
70
|
+
const container = new container_1.CompanionContainer('comp-sqlite', {
|
|
71
71
|
id: 'comp-sqlite',
|
|
72
72
|
name: 'Sqlite Test',
|
|
73
73
|
actionStore: 'sqlite',
|
|
74
74
|
});
|
|
75
|
-
expect(
|
|
75
|
+
expect(container.actionPolicy.getStore()).toBeDefined();
|
|
76
76
|
// Verify it is an instance of SqliteActionStore
|
|
77
|
-
expect(
|
|
77
|
+
expect(container.actionPolicy.getStore().constructor.name).toBe('SqliteActionStore');
|
|
78
78
|
});
|
|
79
79
|
test('accepts custom actionStore via RuntimeOrgans', () => {
|
|
80
80
|
const customStore = {
|
|
@@ -87,9 +87,9 @@ describe('SiduriRuntime Facade Methods & Delegation', () => {
|
|
|
87
87
|
getAuditLog: jest.fn(),
|
|
88
88
|
verifyAuditChain: jest.fn(),
|
|
89
89
|
};
|
|
90
|
-
const
|
|
90
|
+
const container = new container_1.CompanionContainer('comp-custom', { id: 'comp-custom', name: 'Custom' }, {
|
|
91
91
|
actionStore: customStore,
|
|
92
92
|
});
|
|
93
|
-
expect(
|
|
93
|
+
expect(container.actionPolicy.getStore()).toBe(customStore);
|
|
94
94
|
});
|
|
95
95
|
});
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,127 +1,50 @@
|
|
|
1
|
-
import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
memory?: OrganConfig | Record<string, unknown>;
|
|
7
|
-
knowledge?: OrganConfig | Record<string, unknown>;
|
|
8
|
-
behavior?: OrganConfig | Record<string, unknown>;
|
|
9
|
-
body?: OrganConfig | Record<string, unknown>;
|
|
10
|
-
vision?: OrganConfig | Record<string, unknown>;
|
|
11
|
-
hands?: OrganConfig | Record<string, unknown>;
|
|
12
|
-
ear?: OrganConfig | Record<string, unknown>;
|
|
13
|
-
observation?: OrganConfig | Record<string, unknown>;
|
|
14
|
-
mouth?: OrganConfig | Record<string, unknown>;
|
|
15
|
-
self?: OrganConfig | Record<string, unknown>;
|
|
16
|
-
externalKnowledge?: OrganConfig | Record<string, unknown>;
|
|
17
|
-
actionPolicy?: Record<string, unknown>;
|
|
18
|
-
actionStore?: 'in-memory' | 'sqlite' | {
|
|
19
|
-
type: 'sqlite' | 'in-memory';
|
|
20
|
-
dbPath?: string;
|
|
21
|
-
};
|
|
22
|
-
actionStorePath?: string;
|
|
23
|
-
[key: string]: unknown;
|
|
24
|
-
}
|
|
25
|
-
export interface RuntimeOrgans {
|
|
26
|
-
brain?: BrainOrgan;
|
|
27
|
-
memory?: MemoryOrgan;
|
|
28
|
-
voice?: VoiceOrgan | ExperienceAdapter;
|
|
29
|
-
knowledge?: KnowledgeOrgan;
|
|
30
|
-
vision?: VisionOrgan;
|
|
31
|
-
behavior?: BehaviorOrgan;
|
|
32
|
-
body?: BodyOrgan | ExperienceAdapter;
|
|
33
|
-
hands?: HandsOrgan;
|
|
34
|
-
ear?: EarOrgan;
|
|
35
|
-
observation?: ObservationOrgan;
|
|
36
|
-
mouth?: MouthOrgan;
|
|
37
|
-
self?: SelfRepository;
|
|
38
|
-
externalKnowledge?: EKnowledgeOrgan;
|
|
39
|
-
actionStore?: ActionStore;
|
|
40
|
-
actionPolicy?: ActionPolicyEngine;
|
|
41
|
-
}
|
|
42
|
-
export interface CompanionPerception {
|
|
43
|
-
source: string;
|
|
44
|
-
text?: string;
|
|
45
|
-
audioBuffer?: Uint8Array;
|
|
46
|
-
roleOrContext?: 'OWNER' | 'VIEWER' | 'OPERATOR' | RequestContext | string;
|
|
47
|
-
context?: RequestContext;
|
|
48
|
-
history?: Message[];
|
|
49
|
-
medium?: MouthMedium;
|
|
50
|
-
metadata?: Record<string, unknown>;
|
|
51
|
-
signal?: AbortSignal;
|
|
52
|
-
}
|
|
1
|
+
import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan, MouthOrgan, SelfRepository, EKnowledgeOrgan, Message, RequestContext, MouthMedium, ResponseGatingEngine, ActionPolicyEngine, ExperienceDispatcher } from './index';
|
|
2
|
+
import { SessionHistoryManager } from './session-history';
|
|
3
|
+
import { CompanionPerception, PerceptionPipeline } from './perception-pipeline';
|
|
4
|
+
import { CompanionContainer, RuntimeOrgans, SiduriRuntimeConfig } from './container';
|
|
5
|
+
export { CompanionPerception, RuntimeOrgans, SiduriRuntimeConfig };
|
|
53
6
|
/**
|
|
54
|
-
* SiduriRuntime coordinates companion
|
|
55
|
-
*
|
|
56
|
-
*
|
|
7
|
+
* SiduriRuntime coordinates companion perception and cognition execution.
|
|
8
|
+
* Lifecycle management and organ storage are handled by CompanionContainer.
|
|
9
|
+
* The 12-stage perception cycle is executed via PerceptionPipeline.
|
|
57
10
|
*/
|
|
58
11
|
export declare class SiduriRuntime {
|
|
59
|
-
id: string;
|
|
60
|
-
config: SiduriRuntimeConfig;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly config: SiduriRuntimeConfig;
|
|
14
|
+
readonly container: CompanionContainer;
|
|
15
|
+
readonly pipeline: PerceptionPipeline;
|
|
16
|
+
constructor(id: string, config: SiduriRuntimeConfig, containerOrOrgans?: CompanionContainer | RuntimeOrgans, pipeline?: PerceptionPipeline);
|
|
17
|
+
get organs(): RuntimeOrgans;
|
|
18
|
+
get brain(): BrainOrgan | undefined;
|
|
19
|
+
get memory(): MemoryOrgan | undefined;
|
|
20
|
+
get voice(): VoiceOrgan | undefined;
|
|
21
|
+
get knowledge(): KnowledgeOrgan | undefined;
|
|
22
|
+
get vision(): VisionOrgan | undefined;
|
|
23
|
+
get behavior(): BehaviorOrgan | undefined;
|
|
24
|
+
get body(): BodyOrgan | undefined;
|
|
25
|
+
get hands(): HandsOrgan | undefined;
|
|
26
|
+
get ear(): EarOrgan | undefined;
|
|
27
|
+
get observation(): ObservationOrgan | undefined;
|
|
28
|
+
set observation(org: ObservationOrgan | undefined);
|
|
29
|
+
get mouth(): MouthOrgan | undefined;
|
|
30
|
+
get self(): SelfRepository | undefined;
|
|
31
|
+
get externalKnowledge(): EKnowledgeOrgan | undefined;
|
|
32
|
+
get gating(): ResponseGatingEngine;
|
|
33
|
+
get actionPolicy(): ActionPolicyEngine;
|
|
34
|
+
get dispatcher(): ExperienceDispatcher;
|
|
35
|
+
get sessionHistory(): SessionHistoryManager;
|
|
78
36
|
get conversationHistory(): Message[];
|
|
79
37
|
set conversationHistory(messages: Message[]);
|
|
80
|
-
constructor(id: string, config: SiduriRuntimeConfig, organs?: RuntimeOrgans);
|
|
81
38
|
initialize(): Promise<void>;
|
|
82
39
|
getSessionHistory(sessionKey: string): Message[];
|
|
83
40
|
clearHistory(sessionKey?: string): void;
|
|
84
|
-
analyzeVision(imageUrl: string, prompt: string): Promise<string>;
|
|
85
|
-
ingestObservation(frame: Uint8Array, sourceName: string, providerId?: string): Promise<ObservationResult>;
|
|
86
|
-
getCurrentObservations(now?: Date): Observation[];
|
|
87
|
-
clearExpiredObservations(now?: Date): number;
|
|
88
|
-
getClaims(limit?: number): Promise<Claim[]>;
|
|
89
|
-
getPendingClaims(limit?: number): Promise<Claim[]>;
|
|
90
|
-
getDirectives(): Promise<BehaviorDirective[]>;
|
|
91
|
-
approveClaim(id: string): Promise<void>;
|
|
92
|
-
rejectClaim(id: string): Promise<void>;
|
|
93
|
-
updateClaim(id: string, updates: Partial<Pick<Claim, 'subject' | 'predicate' | 'value' | 'scope' | 'sensitivity' | 'confidence' | 'validFrom' | 'validUntil'>>): Promise<Claim>;
|
|
94
|
-
approveDirective(id: string, companionId?: string): Promise<void>;
|
|
95
|
-
rejectDirective(id: string, companionId?: string): Promise<void>;
|
|
96
|
-
revokeDirective(id: string, companionId?: string): Promise<void>;
|
|
97
|
-
disableDirective(id: string, companionId?: string): Promise<void>;
|
|
98
|
-
resetMemory(): Promise<void>;
|
|
99
|
-
stageResponse(options: StageResponseOptions): StagedResponsePlan;
|
|
100
|
-
evaluateGate(plan: StagedResponsePlan, evidenceRecords?: EvidenceRecord[]): ResponseGateEvaluation;
|
|
101
|
-
approveResponse(options: ApproveResponseOptions): {
|
|
102
|
-
success: boolean;
|
|
103
|
-
reason?: string;
|
|
104
|
-
plan?: StagedResponsePlan;
|
|
105
|
-
};
|
|
106
|
-
rejectResponse(options: RejectResponseOptions): {
|
|
107
|
-
success: boolean;
|
|
108
|
-
reason?: string;
|
|
109
|
-
plan?: StagedResponsePlan;
|
|
110
|
-
};
|
|
111
|
-
approveAction(options: ApproveActionOptions): Promise<ActionApprovalResult>;
|
|
112
|
-
getStagedPlan(responseId: string): StagedResponsePlan | undefined;
|
|
113
|
-
findStagedPlanByCorrelation(companionId: string, correlationId: string): StagedResponsePlan | undefined;
|
|
114
41
|
/**
|
|
115
42
|
* Processes an incoming perception (sensory audio, text, platform event, or observation alert)
|
|
116
|
-
* through the
|
|
43
|
+
* through the decoupled PerceptionPipeline.
|
|
117
44
|
*/
|
|
118
45
|
processPerception(perception: CompanionPerception): Promise<any>;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
unregisterMouthChannel(channelId: string): void;
|
|
123
|
-
broadcastMouth(utterance: MouthUtterance): Promise<FormattedMouthOutput[]>;
|
|
124
|
-
interruptMouth(reason?: string): void;
|
|
125
|
-
streamMouth(utterance: MouthUtterance): AsyncIterable<MouthStreamChunk>;
|
|
46
|
+
/**
|
|
47
|
+
* Primary entrypoint for text chat messages.
|
|
48
|
+
*/
|
|
126
49
|
handleUserMessage(message: string, roleOrContext?: 'OWNER' | 'VIEWER' | 'OPERATOR' | RequestContext | string, history?: Message[], medium?: MouthMedium, signal?: AbortSignal): Promise<any>;
|
|
127
50
|
}
|