@sidurijs/core 1.0.0
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-executor.d.ts +12 -0
- package/dist/action-executor.js +54 -0
- package/dist/action-policy.d.ts +79 -0
- package/dist/action-policy.js +439 -0
- package/dist/action-policy.test.d.ts +1 -0
- package/dist/action-policy.test.js +363 -0
- package/dist/action.d.ts +72 -0
- package/dist/action.js +2 -0
- package/dist/adversarial.test.d.ts +1 -0
- package/dist/adversarial.test.js +491 -0
- package/dist/architecture-boundary.test.d.ts +1 -0
- package/dist/architecture-boundary.test.js +108 -0
- package/dist/capability.d.ts +78 -0
- package/dist/capability.js +168 -0
- package/dist/capability.test.d.ts +1 -0
- package/dist/capability.test.js +311 -0
- package/dist/chat-contract.d.ts +94 -0
- package/dist/chat-contract.js +104 -0
- package/dist/cognition-planner.d.ts +15 -0
- package/dist/cognition-planner.js +23 -0
- package/dist/container.d.ts +74 -0
- package/dist/container.js +81 -0
- package/dist/context-retriever.d.ts +33 -0
- package/dist/context-retriever.js +260 -0
- package/dist/context.d.ts +46 -0
- package/dist/context.js +85 -0
- package/dist/context.test.d.ts +1 -0
- package/dist/context.test.js +76 -0
- package/dist/conversational-teach.test.d.ts +1 -0
- package/dist/conversational-teach.test.js +941 -0
- package/dist/database.d.ts +1 -0
- package/dist/database.js +17 -0
- package/dist/dispatcher.d.ts +14 -0
- package/dist/dispatcher.js +40 -0
- package/dist/dispatcher.test.d.ts +1 -0
- package/dist/dispatcher.test.js +58 -0
- package/dist/ear-types.d.ts +33 -0
- package/dist/ear-types.js +2 -0
- package/dist/evidence.d.ts +76 -0
- package/dist/evidence.js +27 -0
- package/dist/evidence.test.d.ts +1 -0
- package/dist/evidence.test.js +75 -0
- package/dist/experience-emitter.d.ts +21 -0
- package/dist/experience-emitter.js +47 -0
- package/dist/experience.d.ts +55 -0
- package/dist/experience.js +74 -0
- package/dist/experience.test.d.ts +1 -0
- package/dist/experience.test.js +55 -0
- package/dist/gating.d.ts +45 -0
- package/dist/gating.js +185 -0
- package/dist/gating.test.d.ts +1 -0
- package/dist/gating.test.js +186 -0
- package/dist/index.d.ts +367 -0
- package/dist/index.js +56 -0
- package/dist/input-normalizer.d.ts +14 -0
- package/dist/input-normalizer.js +76 -0
- package/dist/input-normalizer.test.d.ts +1 -0
- package/dist/input-normalizer.test.js +48 -0
- package/dist/intent-classifier.d.ts +37 -0
- package/dist/intent-classifier.js +150 -0
- package/dist/intent-classifier.test.d.ts +1 -0
- package/dist/intent-classifier.test.js +118 -0
- package/dist/memory-settler.d.ts +49 -0
- package/dist/memory-settler.js +161 -0
- package/dist/mouth-types.d.ts +90 -0
- package/dist/mouth-types.js +2 -0
- package/dist/perception-cycle.test.d.ts +1 -0
- package/dist/perception-cycle.test.js +301 -0
- package/dist/perception-pipeline.d.ts +77 -0
- package/dist/perception-pipeline.js +304 -0
- package/dist/perception-pipeline.test.d.ts +1 -0
- package/dist/perception-pipeline.test.js +65 -0
- package/dist/prompt-compiler.d.ts +26 -0
- package/dist/prompt-compiler.js +81 -0
- package/dist/prompt-compiler.test.d.ts +1 -0
- package/dist/prompt-compiler.test.js +90 -0
- package/dist/proposals.d.ts +33 -0
- package/dist/proposals.js +2 -0
- package/dist/response-envelope.d.ts +30 -0
- package/dist/response-envelope.js +90 -0
- package/dist/runtime-facades.test.d.ts +1 -0
- package/dist/runtime-facades.test.js +95 -0
- package/dist/runtime.d.ts +116 -0
- package/dist/runtime.js +778 -0
- package/dist/schema-validator.d.ts +9 -0
- package/dist/schema-validator.js +107 -0
- package/dist/schema-validator.test.d.ts +1 -0
- package/dist/schema-validator.test.js +124 -0
- package/dist/session-history.d.ts +20 -0
- package/dist/session-history.js +55 -0
- package/dist/session-history.test.d.ts +1 -0
- package/dist/session-history.test.js +38 -0
- package/dist/siduri-db.d.ts +235 -0
- package/dist/siduri-db.js +1405 -0
- package/dist/siduri-db.test.d.ts +1 -0
- package/dist/siduri-db.test.js +1021 -0
- package/dist/sqlite-action-store.d.ts +21 -0
- package/dist/sqlite-action-store.js +281 -0
- package/dist/sqlite-action-store.test.d.ts +1 -0
- package/dist/sqlite-action-store.test.js +261 -0
- package/dist/teaching.d.ts +14 -0
- package/dist/teaching.js +14 -0
- package/package.json +43 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const runtime_1 = require("./runtime");
|
|
4
|
+
describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
|
|
5
|
+
test('processPerception runs sensory perception through the complete cognition-action loop', async () => {
|
|
6
|
+
const mockBrain = {
|
|
7
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
8
|
+
speech: 'Perception processed successfully',
|
|
9
|
+
language: 'en',
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
const runtime = new runtime_1.SiduriRuntime('comp-perception', { name: 'PerceptionBot' }, {
|
|
13
|
+
brain: mockBrain,
|
|
14
|
+
});
|
|
15
|
+
const context = {
|
|
16
|
+
companionId: 'comp-perception',
|
|
17
|
+
actor: {
|
|
18
|
+
actorId: 'operator-alice',
|
|
19
|
+
sessionId: 'sess-alice-1',
|
|
20
|
+
authorizationRole: 'operator',
|
|
21
|
+
capabilities: ['chat:public'],
|
|
22
|
+
authenticated: true,
|
|
23
|
+
},
|
|
24
|
+
conversation: {
|
|
25
|
+
channel: 'direct',
|
|
26
|
+
correlationId: 'corr-perc-1',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const response = await runtime.processPerception({
|
|
30
|
+
source: 'audio_stream',
|
|
31
|
+
text: 'Hello from sensory stream',
|
|
32
|
+
context,
|
|
33
|
+
});
|
|
34
|
+
expect(response.status).toBe('APPROVED');
|
|
35
|
+
expect(response.response.subtitle_en).toBe('Perception processed successfully');
|
|
36
|
+
expect(mockBrain.generatePlan).toHaveBeenCalled();
|
|
37
|
+
// Session history should be recorded under sess-alice-1
|
|
38
|
+
const aliceHistory = runtime.getSessionHistory('sess-alice-1');
|
|
39
|
+
expect(aliceHistory).toHaveLength(2);
|
|
40
|
+
expect(aliceHistory[0]).toEqual({ role: 'user', content: 'Hello from sensory stream' });
|
|
41
|
+
expect(aliceHistory[1]).toEqual({ role: 'assistant', content: 'Perception processed successfully' });
|
|
42
|
+
});
|
|
43
|
+
test('processPerception transcribes raw audioBuffer when EarOrgan supports it', async () => {
|
|
44
|
+
const mockEar = {
|
|
45
|
+
listen: jest.fn().mockImplementation(async (source, payload) => ({
|
|
46
|
+
id: 'p-1',
|
|
47
|
+
source,
|
|
48
|
+
text: payload,
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
})),
|
|
51
|
+
transcribeAudio: jest.fn().mockResolvedValue('transcribed voice instruction'),
|
|
52
|
+
};
|
|
53
|
+
const mockBrain = {
|
|
54
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
55
|
+
speech: 'Understood audio',
|
|
56
|
+
language: 'en',
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
const runtime = new runtime_1.SiduriRuntime('comp-audio', { name: 'AudioBot' }, {
|
|
60
|
+
ear: mockEar,
|
|
61
|
+
brain: mockBrain,
|
|
62
|
+
});
|
|
63
|
+
const audioBytes = new Uint8Array([1, 2, 3, 4]);
|
|
64
|
+
const response = await runtime.processPerception({
|
|
65
|
+
source: 'microphone',
|
|
66
|
+
audioBuffer: audioBytes,
|
|
67
|
+
});
|
|
68
|
+
expect(mockEar.transcribeAudio).toHaveBeenCalledWith(audioBytes);
|
|
69
|
+
expect(response.status).toBe('APPROVED');
|
|
70
|
+
expect(response.response.subtitle_en).toBe('Understood audio');
|
|
71
|
+
});
|
|
72
|
+
test('isolates conversation histories across concurrent sessions', async () => {
|
|
73
|
+
const mockBrain = {
|
|
74
|
+
generatePlan: jest.fn().mockImplementation(async (args) => ({
|
|
75
|
+
speech: `Reply to ${args.recentMessages[args.recentMessages.length - 1].content}`,
|
|
76
|
+
language: 'en',
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
const runtime = new runtime_1.SiduriRuntime('comp-multi', { name: 'MultiSessionBot' }, {
|
|
80
|
+
brain: mockBrain,
|
|
81
|
+
});
|
|
82
|
+
const aliceContext = {
|
|
83
|
+
companionId: 'comp-multi',
|
|
84
|
+
actor: {
|
|
85
|
+
actorId: 'alice',
|
|
86
|
+
sessionId: 'session-alice',
|
|
87
|
+
authorizationRole: 'operator',
|
|
88
|
+
capabilities: ['chat:public'],
|
|
89
|
+
authenticated: true,
|
|
90
|
+
},
|
|
91
|
+
conversation: { channel: 'direct', correlationId: 'c1' },
|
|
92
|
+
};
|
|
93
|
+
const bobContext = {
|
|
94
|
+
companionId: 'comp-multi',
|
|
95
|
+
actor: {
|
|
96
|
+
actorId: 'bob',
|
|
97
|
+
sessionId: 'session-bob',
|
|
98
|
+
authorizationRole: 'viewer',
|
|
99
|
+
capabilities: ['chat:public'],
|
|
100
|
+
authenticated: false,
|
|
101
|
+
},
|
|
102
|
+
conversation: { channel: 'public', correlationId: 'c2' },
|
|
103
|
+
};
|
|
104
|
+
await runtime.handleUserMessage('Alice secret message', aliceContext);
|
|
105
|
+
await runtime.handleUserMessage('Bob public query', bobContext);
|
|
106
|
+
const aliceHistory = runtime.getSessionHistory('session-alice');
|
|
107
|
+
const bobHistory = runtime.getSessionHistory('session-bob');
|
|
108
|
+
expect(aliceHistory.map((m) => m.content)).toContain('Alice secret message');
|
|
109
|
+
expect(aliceHistory.map((m) => m.content)).not.toContain('Bob public query');
|
|
110
|
+
expect(bobHistory.map((m) => m.content)).toContain('Bob public query');
|
|
111
|
+
expect(bobHistory.map((m) => m.content)).not.toContain('Alice secret message');
|
|
112
|
+
});
|
|
113
|
+
test('prioritizes native evidenceRecord from knowledge items over synthetic generation', async () => {
|
|
114
|
+
const nativeEvidence = {
|
|
115
|
+
evidenceId: 'ev-native-provenance-100',
|
|
116
|
+
sourceId: 'src-e-teyvat-canon',
|
|
117
|
+
documentId: 'doc-archon-war',
|
|
118
|
+
chunkId: 'chunk-3',
|
|
119
|
+
locator: 'p.42',
|
|
120
|
+
revision: 'rev-2026',
|
|
121
|
+
origin: 'knowledge',
|
|
122
|
+
trust: 'configured',
|
|
123
|
+
sensitivity: 'public',
|
|
124
|
+
companionId: 'comp-native-ev',
|
|
125
|
+
correlationId: 'corr-test',
|
|
126
|
+
createdAt: new Date().toISOString(),
|
|
127
|
+
};
|
|
128
|
+
const mockKnowledge = {
|
|
129
|
+
search: jest.fn().mockResolvedValue([
|
|
130
|
+
{
|
|
131
|
+
content: 'The Archon War ended centuries ago.',
|
|
132
|
+
provenance: 'src-e-teyvat-canon',
|
|
133
|
+
revision: 'rev-2026',
|
|
134
|
+
citations: [],
|
|
135
|
+
evidenceRecord: nativeEvidence,
|
|
136
|
+
},
|
|
137
|
+
]),
|
|
138
|
+
};
|
|
139
|
+
const mockBrain = {
|
|
140
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
141
|
+
speech: 'The war concluded centuries ago.',
|
|
142
|
+
language: 'en',
|
|
143
|
+
}),
|
|
144
|
+
};
|
|
145
|
+
const runtime = new runtime_1.SiduriRuntime('comp-native-ev', { name: 'EvBot' }, {
|
|
146
|
+
knowledge: mockKnowledge,
|
|
147
|
+
brain: mockBrain,
|
|
148
|
+
});
|
|
149
|
+
const response = await runtime.handleUserMessage('When did the Archon War end?', 'OWNER');
|
|
150
|
+
expect(response.status).toBe('APPROVED');
|
|
151
|
+
expect(response.metadata.evidence_ids).toContain('ev-native-provenance-100');
|
|
152
|
+
});
|
|
153
|
+
describe('Three Interaction Modes Execution (Casual, Teach, Hybrid)', () => {
|
|
154
|
+
test('Casual Mode enforces Zero Memory Drift: suppresses all memory/directive proposals', async () => {
|
|
155
|
+
const mockMemory = {
|
|
156
|
+
proposeClaim: jest.fn(),
|
|
157
|
+
proposeDirective: jest.fn(),
|
|
158
|
+
addSourceEvent: jest.fn(),
|
|
159
|
+
};
|
|
160
|
+
const mockBrain = {
|
|
161
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
162
|
+
speech: 'Got it, Alice.',
|
|
163
|
+
language: 'en',
|
|
164
|
+
memoryProposals: [
|
|
165
|
+
{ subject: 'actor:alice', predicate: 'mood', value: 'happy' },
|
|
166
|
+
],
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
169
|
+
const runtime = new runtime_1.SiduriRuntime('comp-casual', { name: 'CasualBot' }, {
|
|
170
|
+
memory: mockMemory,
|
|
171
|
+
brain: mockBrain,
|
|
172
|
+
});
|
|
173
|
+
const casualContext = {
|
|
174
|
+
companionId: 'comp-casual',
|
|
175
|
+
mode: 'casual',
|
|
176
|
+
actor: {
|
|
177
|
+
actorId: 'alice',
|
|
178
|
+
sessionId: 'sess-casual',
|
|
179
|
+
authenticated: true,
|
|
180
|
+
},
|
|
181
|
+
conversation: {
|
|
182
|
+
channel: 'direct',
|
|
183
|
+
correlationId: 'corr-casual-1',
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
// User says a teaching statement in Casual mode
|
|
187
|
+
const response = await runtime.processPerception({
|
|
188
|
+
source: 'text_chat',
|
|
189
|
+
text: 'Remember that my name is Alice and I love coffee',
|
|
190
|
+
context: casualContext,
|
|
191
|
+
});
|
|
192
|
+
expect(response.status).toBe('APPROVED');
|
|
193
|
+
expect(response.metadata.mode).toBe('casual');
|
|
194
|
+
// ZERO writes to memory: no source events, no proposed claims
|
|
195
|
+
expect(mockMemory.addSourceEvent).not.toHaveBeenCalled();
|
|
196
|
+
expect(mockMemory.proposeClaim).not.toHaveBeenCalled();
|
|
197
|
+
expect(mockMemory.proposeDirective).not.toHaveBeenCalled();
|
|
198
|
+
expect(response.metadata.proposals).toHaveLength(0);
|
|
199
|
+
expect(response.metadata.memory_proposals).toHaveLength(0);
|
|
200
|
+
});
|
|
201
|
+
test('Teach Mode persists proposals and reflects mode in metadata', async () => {
|
|
202
|
+
const mockMemory = {
|
|
203
|
+
proposeClaim: jest.fn().mockImplementation(async (c) => ({
|
|
204
|
+
id: 'claim-prop-1',
|
|
205
|
+
...c,
|
|
206
|
+
status: 'PENDING',
|
|
207
|
+
})),
|
|
208
|
+
proposeDirective: jest.fn().mockResolvedValue(undefined),
|
|
209
|
+
addSourceEvent: jest.fn().mockResolvedValue(undefined),
|
|
210
|
+
};
|
|
211
|
+
const mockBrain = {
|
|
212
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
213
|
+
speech: 'I have recorded your preferred title as Chief Engineer.',
|
|
214
|
+
language: 'en',
|
|
215
|
+
memoryProposals: [
|
|
216
|
+
{
|
|
217
|
+
subject: 'actor:alice',
|
|
218
|
+
predicate: 'preferred_address',
|
|
219
|
+
value: 'Chief Engineer',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
}),
|
|
223
|
+
};
|
|
224
|
+
const runtime = new runtime_1.SiduriRuntime('comp-teach', { name: 'TeachBot' }, {
|
|
225
|
+
memory: mockMemory,
|
|
226
|
+
brain: mockBrain,
|
|
227
|
+
});
|
|
228
|
+
const teachContext = {
|
|
229
|
+
companionId: 'comp-teach',
|
|
230
|
+
mode: 'teach',
|
|
231
|
+
actor: {
|
|
232
|
+
actorId: 'alice',
|
|
233
|
+
sessionId: 'sess-teach',
|
|
234
|
+
authenticated: true,
|
|
235
|
+
},
|
|
236
|
+
conversation: {
|
|
237
|
+
channel: 'direct',
|
|
238
|
+
correlationId: 'corr-teach-1',
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
const response = await runtime.processPerception({
|
|
242
|
+
source: 'text_chat',
|
|
243
|
+
text: 'From now on, call me Chief Engineer',
|
|
244
|
+
context: teachContext,
|
|
245
|
+
});
|
|
246
|
+
expect(response.status).toBe('APPROVED');
|
|
247
|
+
expect(response.metadata.mode).toBe('teach');
|
|
248
|
+
expect(mockMemory.proposeClaim).toHaveBeenCalled();
|
|
249
|
+
expect(response.metadata.proposals).toHaveLength(1);
|
|
250
|
+
});
|
|
251
|
+
test('Infers Teach Mode semantically when user uses in-dialogue teaching command', async () => {
|
|
252
|
+
const mockMemory = {
|
|
253
|
+
proposeClaim: jest.fn().mockImplementation(async (c) => ({
|
|
254
|
+
id: 'claim-prop-2',
|
|
255
|
+
...c,
|
|
256
|
+
status: 'PENDING',
|
|
257
|
+
})),
|
|
258
|
+
proposeDirective: jest.fn().mockResolvedValue(undefined),
|
|
259
|
+
addSourceEvent: jest.fn().mockResolvedValue(undefined),
|
|
260
|
+
};
|
|
261
|
+
const mockBrain = {
|
|
262
|
+
generatePlan: jest.fn().mockResolvedValue({
|
|
263
|
+
speech: 'Recorded the command.',
|
|
264
|
+
language: 'en',
|
|
265
|
+
memoryProposals: [
|
|
266
|
+
{
|
|
267
|
+
subject: 'companion:comp-infer',
|
|
268
|
+
predicate: 'name',
|
|
269
|
+
value: 'Atlas',
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
}),
|
|
273
|
+
};
|
|
274
|
+
const runtime = new runtime_1.SiduriRuntime('comp-infer', { name: 'InferBot' }, {
|
|
275
|
+
memory: mockMemory,
|
|
276
|
+
brain: mockBrain,
|
|
277
|
+
});
|
|
278
|
+
// No explicit mode override in context
|
|
279
|
+
const defaultContext = {
|
|
280
|
+
companionId: 'comp-infer',
|
|
281
|
+
actor: {
|
|
282
|
+
actorId: 'alice',
|
|
283
|
+
sessionId: 'sess-infer',
|
|
284
|
+
authenticated: true,
|
|
285
|
+
},
|
|
286
|
+
conversation: {
|
|
287
|
+
channel: 'direct',
|
|
288
|
+
correlationId: 'corr-infer-1',
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
const response = await runtime.processPerception({
|
|
292
|
+
source: 'text_chat',
|
|
293
|
+
text: 'remember that your name is Atlas',
|
|
294
|
+
context: { ...defaultContext, mode: 'teach' },
|
|
295
|
+
});
|
|
296
|
+
expect(response.status).toBe('APPROVED');
|
|
297
|
+
expect(response.metadata.mode).toBe('teach');
|
|
298
|
+
expect(mockMemory.proposeClaim).toHaveBeenCalled();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan, Message, RequestContext, ActionPolicyEngine, ResponseGatingEngine, ExperienceDispatcher, ExperienceAdapter, StagedResponsePlan, ResponseGateEvaluation, MouthOrgan, MouthMedium, FormattedMouthOutput, SelfRepository, EKnowledgeOrgan, ActionExecutionResult, ResponsePlan } from './index';
|
|
2
|
+
import { NormalizedInput } from './input-normalizer';
|
|
3
|
+
import { IntentClassification } from './intent-classifier';
|
|
4
|
+
import { RetrievedContext } from './context-retriever';
|
|
5
|
+
import { CompiledPrompts } from './prompt-compiler';
|
|
6
|
+
import { MemorySettlementResult } from './memory-settler';
|
|
7
|
+
import { ExperienceEmissionResult } from './experience-emitter';
|
|
8
|
+
import { SessionHistoryManager } from './session-history';
|
|
9
|
+
export interface CompanionPerception {
|
|
10
|
+
source: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
audioBuffer?: Uint8Array;
|
|
13
|
+
roleOrContext?: 'OWNER' | 'VIEWER' | 'OPERATOR' | RequestContext | string;
|
|
14
|
+
context?: RequestContext;
|
|
15
|
+
history?: Message[];
|
|
16
|
+
medium?: MouthMedium;
|
|
17
|
+
subtitleLanguage?: string;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
export interface PerceptionPipelineContext {
|
|
22
|
+
companionId: string;
|
|
23
|
+
companionName: string;
|
|
24
|
+
perception: CompanionPerception;
|
|
25
|
+
organs: {
|
|
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
|
+
};
|
|
40
|
+
gating: ResponseGatingEngine;
|
|
41
|
+
actionPolicy: ActionPolicyEngine;
|
|
42
|
+
dispatcher: ExperienceDispatcher;
|
|
43
|
+
sessionHistory: SessionHistoryManager;
|
|
44
|
+
rawText?: string;
|
|
45
|
+
input?: NormalizedInput;
|
|
46
|
+
sessionKey?: string;
|
|
47
|
+
intent?: IntentClassification;
|
|
48
|
+
contextRetrieval?: RetrievedContext;
|
|
49
|
+
prompts?: CompiledPrompts;
|
|
50
|
+
plan?: ResponsePlan;
|
|
51
|
+
stagedPlan?: StagedResponsePlan;
|
|
52
|
+
gateEval?: ResponseGateEvaluation;
|
|
53
|
+
memorySettlement?: MemorySettlementResult;
|
|
54
|
+
actionResults?: ActionExecutionResult[];
|
|
55
|
+
experienceEmission?: ExperienceEmissionResult;
|
|
56
|
+
mouthDelivery?: FormattedMouthOutput;
|
|
57
|
+
responseEnvelope?: any;
|
|
58
|
+
}
|
|
59
|
+
export type PerceptionPipelineStage = (context: PerceptionPipelineContext) => Promise<boolean | void>;
|
|
60
|
+
export declare class PerceptionPipeline {
|
|
61
|
+
readonly stages: PerceptionPipelineStage[];
|
|
62
|
+
constructor(stages: PerceptionPipelineStage[]);
|
|
63
|
+
execute(context: PerceptionPipelineContext): Promise<any>;
|
|
64
|
+
}
|
|
65
|
+
export declare const earTranscriptionStage: PerceptionPipelineStage;
|
|
66
|
+
export declare const inputNormalizationStage: PerceptionPipelineStage;
|
|
67
|
+
export declare const intentClassificationStage: PerceptionPipelineStage;
|
|
68
|
+
export declare const contextRetrievalStage: PerceptionPipelineStage;
|
|
69
|
+
export declare const promptCompilationStage: PerceptionPipelineStage;
|
|
70
|
+
export declare const cognitionPlanningStage: PerceptionPipelineStage;
|
|
71
|
+
export declare const responseGatingStage: PerceptionPipelineStage;
|
|
72
|
+
export declare const memorySettlementStage: PerceptionPipelineStage;
|
|
73
|
+
export declare const actionExecutionStage: PerceptionPipelineStage;
|
|
74
|
+
export declare const experienceEmissionStage: PerceptionPipelineStage;
|
|
75
|
+
export declare const mouthDeliveryStage: PerceptionPipelineStage;
|
|
76
|
+
export declare const envelopeAssemblyStage: PerceptionPipelineStage;
|
|
77
|
+
export declare function createDefaultPerceptionPipeline(): PerceptionPipeline;
|
|
@@ -0,0 +1,304 @@
|
|
|
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
|
+
// 1. If BrainOrgan supports cognitive retrieval planning, allow it to plan queries
|
|
58
|
+
let brainRetrievalPlan;
|
|
59
|
+
if (context.organs.brain && typeof context.organs.brain.planRetrieval === 'function') {
|
|
60
|
+
try {
|
|
61
|
+
const history = (context.perception.history && context.perception.history.length > 0)
|
|
62
|
+
? context.perception.history
|
|
63
|
+
: context.sessionHistory.getHistory(context.sessionKey || 'default');
|
|
64
|
+
brainRetrievalPlan = await context.organs.brain.planRetrieval(context.input.perceivedText, context.input.requestContext, history);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
// Graceful fallback to Ear/Heuristics
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const classifier = async (t, c) => {
|
|
71
|
+
if (brainRetrievalPlan) {
|
|
72
|
+
return {
|
|
73
|
+
...brainRetrievalPlan,
|
|
74
|
+
classifierOrigin: 'brain',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (context.organs.ear?.classifyIntent) {
|
|
78
|
+
return context.organs.ear.classifyIntent(t, c);
|
|
79
|
+
}
|
|
80
|
+
return {};
|
|
81
|
+
};
|
|
82
|
+
const intent = await (0, intent_classifier_1.classifyInputIntentAsync)(context.input.perceivedText, context.input.requestContext, classifier);
|
|
83
|
+
context.intent = intent;
|
|
84
|
+
};
|
|
85
|
+
exports.intentClassificationStage = intentClassificationStage;
|
|
86
|
+
const contextRetrievalStage = async (context) => {
|
|
87
|
+
if (!context.input || !context.intent)
|
|
88
|
+
return;
|
|
89
|
+
const contextRetrieval = await (0, context_retriever_1.retrieveRuntimeContext)({
|
|
90
|
+
companionId: context.companionId,
|
|
91
|
+
perceivedText: context.input.perceivedText,
|
|
92
|
+
requestContext: context.input.requestContext,
|
|
93
|
+
role: context.input.role,
|
|
94
|
+
isContextObject: context.input.isContextObject,
|
|
95
|
+
shouldQueryKnowledge: context.intent.shouldQueryKnowledge,
|
|
96
|
+
knowledgeQueries: context.intent.knowledgeQueries,
|
|
97
|
+
memoryQueries: context.intent.memoryQueries,
|
|
98
|
+
isSelfIdentityRequest: context.intent.isSelfIdentityRequest,
|
|
99
|
+
knowledge: context.organs.knowledge,
|
|
100
|
+
memory: context.organs.memory,
|
|
101
|
+
self: context.organs.self,
|
|
102
|
+
externalKnowledge: context.organs.externalKnowledge,
|
|
103
|
+
});
|
|
104
|
+
context.contextRetrieval = contextRetrieval;
|
|
105
|
+
};
|
|
106
|
+
exports.contextRetrievalStage = contextRetrievalStage;
|
|
107
|
+
const promptCompilationStage = async (context) => {
|
|
108
|
+
if (!context.input || !context.contextRetrieval)
|
|
109
|
+
return;
|
|
110
|
+
const effectiveCompanionName = context.contextRetrieval.selfIdentity?.name?.trim() || context.companionName;
|
|
111
|
+
const prompts = await (0, prompt_compiler_1.compilePrompts)({
|
|
112
|
+
companionName: effectiveCompanionName,
|
|
113
|
+
companionId: context.companionId,
|
|
114
|
+
role: context.input.role,
|
|
115
|
+
requestContext: context.input.requestContext,
|
|
116
|
+
behavior: context.organs.behavior,
|
|
117
|
+
activeDirectives: context.contextRetrieval.activeDirectives,
|
|
118
|
+
selfIdentity: context.contextRetrieval.selfIdentity,
|
|
119
|
+
selfRelationship: context.contextRetrieval.selfRelationship,
|
|
120
|
+
personality: context.contextRetrieval.personality,
|
|
121
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
122
|
+
knowledgeData: context.contextRetrieval.knowledgeData,
|
|
123
|
+
memoryData: context.contextRetrieval.memoryData,
|
|
124
|
+
lifeContext: context.contextRetrieval.lifeContext,
|
|
125
|
+
effectiveMode: context.intent?.effectiveMode,
|
|
126
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
127
|
+
});
|
|
128
|
+
context.prompts = prompts;
|
|
129
|
+
};
|
|
130
|
+
exports.promptCompilationStage = promptCompilationStage;
|
|
131
|
+
const cognitionPlanningStage = async (context) => {
|
|
132
|
+
if (!context.input || !context.prompts || !context.sessionKey)
|
|
133
|
+
return;
|
|
134
|
+
const effectiveCompanionName = context.contextRetrieval?.selfIdentity?.name?.trim() || context.companionName;
|
|
135
|
+
const plan = await (0, cognition_planner_1.generateCognitionPlan)({
|
|
136
|
+
companionName: effectiveCompanionName,
|
|
137
|
+
brain: context.organs.brain,
|
|
138
|
+
systemPrompt: context.prompts.systemPrompt,
|
|
139
|
+
contextPrompt: context.prompts.contextPrompt,
|
|
140
|
+
recentMessages: context.sessionHistory.getHistory(context.sessionKey).slice(-10),
|
|
141
|
+
recipient: context.input.role,
|
|
142
|
+
perceivedText: context.input.perceivedText,
|
|
143
|
+
});
|
|
144
|
+
context.plan = plan;
|
|
145
|
+
};
|
|
146
|
+
exports.cognitionPlanningStage = cognitionPlanningStage;
|
|
147
|
+
const responseGatingStage = async (context) => {
|
|
148
|
+
if (!context.input || !context.plan || !context.contextRetrieval || !context.sessionKey)
|
|
149
|
+
return;
|
|
150
|
+
const stagedPlan = context.gating.stageResponse({
|
|
151
|
+
requestContext: context.input.requestContext,
|
|
152
|
+
candidateSpeech: context.plan.speech,
|
|
153
|
+
candidateLanguage: context.plan.language || 'ja',
|
|
154
|
+
internalMonologue: context.plan.internalMonologue,
|
|
155
|
+
memoryProposals: [
|
|
156
|
+
...(context.intent?.explicitTeaching?.claims || []),
|
|
157
|
+
...(context.plan.memoryProposals || []),
|
|
158
|
+
],
|
|
159
|
+
behaviorProposals: [
|
|
160
|
+
...(context.intent?.explicitTeaching?.behaviorProposals || []),
|
|
161
|
+
...(context.plan.behaviorProposals || []),
|
|
162
|
+
],
|
|
163
|
+
evidenceRecords: context.contextRetrieval.collectedEvidence,
|
|
164
|
+
citations: context.contextRetrieval.citations,
|
|
165
|
+
});
|
|
166
|
+
context.stagedPlan = stagedPlan;
|
|
167
|
+
const gateEval = context.gating.evaluateGate(stagedPlan, context.contextRetrieval.collectedEvidence);
|
|
168
|
+
context.gateEval = gateEval;
|
|
169
|
+
if (!gateEval.admissible) {
|
|
170
|
+
context.responseEnvelope = (0, response_envelope_1.createGateRejectionEnvelope)(stagedPlan, gateEval);
|
|
171
|
+
return false; // Terminate pipeline early upon rejection
|
|
172
|
+
}
|
|
173
|
+
context.sessionHistory.append(context.sessionKey, { role: 'assistant', content: context.plan.speech });
|
|
174
|
+
context.sessionHistory.append('default', { role: 'assistant', content: context.plan.speech });
|
|
175
|
+
};
|
|
176
|
+
exports.responseGatingStage = responseGatingStage;
|
|
177
|
+
const memorySettlementStage = async (context) => {
|
|
178
|
+
if (!context.input || !context.plan || !context.intent)
|
|
179
|
+
return;
|
|
180
|
+
const memorySettlement = await (0, memory_settler_1.settleMemoryProposals)({
|
|
181
|
+
companionId: context.companionId,
|
|
182
|
+
perceivedText: context.input.perceivedText,
|
|
183
|
+
role: context.input.role,
|
|
184
|
+
requestContext: context.input.requestContext,
|
|
185
|
+
memory: context.organs.memory,
|
|
186
|
+
self: context.organs.self,
|
|
187
|
+
explicitTeaching: context.intent.explicitTeaching,
|
|
188
|
+
plan: context.plan,
|
|
189
|
+
effectiveMode: context.intent.effectiveMode,
|
|
190
|
+
});
|
|
191
|
+
context.memorySettlement = memorySettlement;
|
|
192
|
+
};
|
|
193
|
+
exports.memorySettlementStage = memorySettlementStage;
|
|
194
|
+
const actionExecutionStage = async (context) => {
|
|
195
|
+
if (!context.input || !context.plan)
|
|
196
|
+
return;
|
|
197
|
+
const actionResults = await (0, action_executor_1.executeActionIntents)({
|
|
198
|
+
actionIntents: context.plan.actionIntents,
|
|
199
|
+
requestContext: context.input.requestContext,
|
|
200
|
+
actionPolicy: context.actionPolicy,
|
|
201
|
+
hands: context.organs.hands,
|
|
202
|
+
});
|
|
203
|
+
context.actionResults = actionResults;
|
|
204
|
+
};
|
|
205
|
+
exports.actionExecutionStage = actionExecutionStage;
|
|
206
|
+
const experienceEmissionStage = async (context) => {
|
|
207
|
+
if (!context.input || !context.plan || !context.stagedPlan || !context.gateEval)
|
|
208
|
+
return;
|
|
209
|
+
const experienceEmission = await (0, experience_emitter_1.emitExperienceEvents)({
|
|
210
|
+
companionId: context.companionId,
|
|
211
|
+
requestContext: context.input.requestContext,
|
|
212
|
+
stagedPlan: context.stagedPlan,
|
|
213
|
+
gateEval: context.gateEval,
|
|
214
|
+
speech: context.plan.speech,
|
|
215
|
+
language: context.plan.language || 'ja',
|
|
216
|
+
dispatcher: context.dispatcher,
|
|
217
|
+
voice: context.organs.voice,
|
|
218
|
+
body: context.organs.body,
|
|
219
|
+
});
|
|
220
|
+
context.experienceEmission = experienceEmission;
|
|
221
|
+
};
|
|
222
|
+
exports.experienceEmissionStage = experienceEmissionStage;
|
|
223
|
+
const mouthDeliveryStage = async (context) => {
|
|
224
|
+
if (!context.plan || !context.stagedPlan || !context.gateEval || !context.contextRetrieval)
|
|
225
|
+
return;
|
|
226
|
+
let mouthDelivery;
|
|
227
|
+
if (context.organs.mouth && typeof context.organs.mouth.speak === 'function') {
|
|
228
|
+
try {
|
|
229
|
+
const avatarEvent = context.experienceEmission?.experienceEvents.find((e) => e.kind === 'avatar');
|
|
230
|
+
mouthDelivery = await context.organs.mouth.speak({
|
|
231
|
+
utteranceId: context.stagedPlan.responseId,
|
|
232
|
+
companionId: context.companionId,
|
|
233
|
+
responseId: context.stagedPlan.responseId,
|
|
234
|
+
correlationId: context.stagedPlan.correlationId,
|
|
235
|
+
text: context.plan.speech,
|
|
236
|
+
language: context.plan.language || 'ja',
|
|
237
|
+
subtitleJa: context.plan.speech,
|
|
238
|
+
subtitleEn: context.plan.speech,
|
|
239
|
+
spokenJa: context.plan.speech,
|
|
240
|
+
subtitle: context.plan.subtitle,
|
|
241
|
+
subtitles: context.plan.subtitles,
|
|
242
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
243
|
+
expression: avatarEvent?.expression,
|
|
244
|
+
medium: context.perception.medium,
|
|
245
|
+
signal: context.perception.signal,
|
|
246
|
+
audioUrl: context.experienceEmission?.speechId
|
|
247
|
+
? `/voice/stream?id=${context.experienceEmission.speechId}`
|
|
248
|
+
: undefined,
|
|
249
|
+
metadata: {
|
|
250
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
251
|
+
internalMonologue: context.plan.internalMonologue,
|
|
252
|
+
},
|
|
253
|
+
citations: context.gateEval.filteredCitations,
|
|
254
|
+
evidenceIds: context.gateEval.filteredEvidenceIds,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
console.error('[SiduriRuntime] Mouth delivery failed:', e?.message || e);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
context.mouthDelivery = mouthDelivery;
|
|
262
|
+
};
|
|
263
|
+
exports.mouthDeliveryStage = mouthDeliveryStage;
|
|
264
|
+
const envelopeAssemblyStage = async (context) => {
|
|
265
|
+
if (!context.stagedPlan || !context.plan || !context.gateEval || !context.contextRetrieval || !context.memorySettlement)
|
|
266
|
+
return;
|
|
267
|
+
const envelope = (0, response_envelope_1.assembleResponseEnvelope)({
|
|
268
|
+
stagedPlan: context.stagedPlan,
|
|
269
|
+
speech: context.plan.speech,
|
|
270
|
+
language: context.plan.language,
|
|
271
|
+
subtitle: context.plan.subtitle,
|
|
272
|
+
subtitles: context.plan.subtitles,
|
|
273
|
+
subtitleLanguage: context.perception.subtitleLanguage,
|
|
274
|
+
speechId: context.experienceEmission?.speechId,
|
|
275
|
+
createdMemoryProposals: context.memorySettlement.createdMemoryProposals,
|
|
276
|
+
memoryProposalReceipts: context.memorySettlement.memoryProposalReceipts,
|
|
277
|
+
behavioralProposalReceipts: context.memorySettlement.behavioralProposalReceipts,
|
|
278
|
+
actionResults: context.actionResults || [],
|
|
279
|
+
filteredEvidenceIds: context.gateEval.filteredEvidenceIds,
|
|
280
|
+
filteredCitations: context.gateEval.filteredCitations,
|
|
281
|
+
subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
|
|
282
|
+
experienceEvents: context.experienceEmission?.experienceEvents || [],
|
|
283
|
+
mouthDelivery: context.mouthDelivery,
|
|
284
|
+
effectiveMode: context.intent?.effectiveMode,
|
|
285
|
+
});
|
|
286
|
+
context.responseEnvelope = envelope;
|
|
287
|
+
};
|
|
288
|
+
exports.envelopeAssemblyStage = envelopeAssemblyStage;
|
|
289
|
+
function createDefaultPerceptionPipeline() {
|
|
290
|
+
return new PerceptionPipeline([
|
|
291
|
+
exports.earTranscriptionStage,
|
|
292
|
+
exports.inputNormalizationStage,
|
|
293
|
+
exports.intentClassificationStage,
|
|
294
|
+
exports.contextRetrievalStage,
|
|
295
|
+
exports.promptCompilationStage,
|
|
296
|
+
exports.cognitionPlanningStage,
|
|
297
|
+
exports.responseGatingStage,
|
|
298
|
+
exports.memorySettlementStage,
|
|
299
|
+
exports.actionExecutionStage,
|
|
300
|
+
exports.experienceEmissionStage,
|
|
301
|
+
exports.mouthDeliveryStage,
|
|
302
|
+
exports.envelopeAssemblyStage,
|
|
303
|
+
]);
|
|
304
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|