@siduri-x/core 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/action-policy.d.ts +8 -1
  2. package/dist/action-policy.js +84 -24
  3. package/dist/action-policy.test.js +67 -1
  4. package/dist/action.d.ts +1 -1
  5. package/dist/capability.d.ts +6 -2
  6. package/dist/capability.js +5 -1
  7. package/dist/capability.test.js +1 -0
  8. package/dist/chat-contract.d.ts +3 -1
  9. package/dist/chat-contract.js +5 -2
  10. package/dist/container.d.ts +74 -0
  11. package/dist/container.js +81 -0
  12. package/dist/context.d.ts +3 -1
  13. package/dist/context.js +13 -0
  14. package/dist/index.d.ts +11 -3
  15. package/dist/index.js +2 -0
  16. package/dist/input-normalizer.js +3 -1
  17. package/dist/intent-classifier.d.ts +4 -2
  18. package/dist/intent-classifier.js +32 -1
  19. package/dist/intent-classifier.test.js +52 -0
  20. package/dist/memory-settler.d.ts +2 -1
  21. package/dist/memory-settler.js +9 -1
  22. package/dist/perception-cycle.test.js +134 -0
  23. package/dist/perception-pipeline.d.ts +76 -0
  24. package/dist/perception-pipeline.js +258 -0
  25. package/dist/perception-pipeline.test.d.ts +1 -0
  26. package/dist/perception-pipeline.test.js +65 -0
  27. package/dist/prompt-compiler.d.ts +2 -1
  28. package/dist/prompt-compiler.js +7 -1
  29. package/dist/proposals.d.ts +4 -1
  30. package/dist/response-envelope.d.ts +2 -1
  31. package/dist/response-envelope.js +2 -1
  32. package/dist/runtime-facades.test.js +27 -27
  33. package/dist/runtime.d.ts +36 -113
  34. package/dist/runtime.js +58 -403
  35. package/dist/siduri-db.d.ts +25 -9
  36. package/dist/siduri-db.js +114 -15
  37. package/dist/siduri-db.test.js +4 -3
  38. package/dist/sqlite-action-store.d.ts +1 -1
  39. package/dist/sqlite-action-store.js +37 -6
  40. package/dist/sqlite-action-store.test.js +9 -0
  41. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { RequestContext } from './index';
1
+ import { RequestContext, InteractionMode } from './index';
2
2
  import { extractDeterministicTeaching } from './teaching';
3
3
  export interface IntentClassification {
4
4
  normalizedMessage: string;
@@ -7,13 +7,15 @@ export interface IntentClassification {
7
7
  isSelfIdentityRequest: boolean;
8
8
  isGreeting: boolean;
9
9
  shouldQueryKnowledge: boolean;
10
+ effectiveMode: InteractionMode;
10
11
  confidence?: number;
11
12
  classifierOrigin?: 'heuristic' | 'cognitive' | 'ear';
12
13
  }
13
14
  export type CognitiveIntentClassifier = (text: string, context: RequestContext) => Promise<Partial<IntentClassification>> | Partial<IntentClassification>;
14
15
  /**
15
16
  * Evaluates domain heuristics and intent classification for user messages.
16
- * Determines if deterministic teaching is present and whether external knowledge
17
+ * Determines if deterministic teaching is present, resolves the effective
18
+ * interaction mode (casual, teach, hybrid), and determines if external knowledge
17
19
  * retrieval is appropriate.
18
20
  */
19
21
  export declare function classifyInputIntent(text: string, context: RequestContext, overrides?: Partial<IntentClassification>): IntentClassification;
@@ -5,7 +5,8 @@ exports.classifyInputIntentAsync = classifyInputIntentAsync;
5
5
  const teaching_1 = require("./teaching");
6
6
  /**
7
7
  * Evaluates domain heuristics and intent classification for user messages.
8
- * Determines if deterministic teaching is present and whether external knowledge
8
+ * Determines if deterministic teaching is present, resolves the effective
9
+ * interaction mode (casual, teach, hybrid), and determines if external knowledge
9
10
  * retrieval is appropriate.
10
11
  */
11
12
  function classifyInputIntent(text, context, overrides) {
@@ -21,6 +22,35 @@ function classifyInputIntent(text, context, overrides) {
21
22
  /^(?:hello|hi|hey|greetings|good morning|good afternoon|good evening|howdy|yo)[.!]?$/.test(normalizedMessage);
22
23
  const shouldQueryKnowledge = overrides?.shouldQueryKnowledge ??
23
24
  (!isTeachingLike && !isSelfIdentityRequest && !isGreeting);
25
+ // Multi-tier Interaction Mode Resolution:
26
+ // 1. Overrides / Cognitive Classifier
27
+ // 2. Explicit Request Override (context.mode)
28
+ // 3. Security Boundary: public channel or external source forces 'casual' (Zero Memory Drift)
29
+ // 4. In-dialogue semantic cues (!casual, !teach, "remember that...", etc.)
30
+ // 5. Default companion baseline: 'hybrid' (salience filtering)
31
+ let effectiveMode;
32
+ if (overrides?.effectiveMode) {
33
+ effectiveMode = overrides.effectiveMode;
34
+ }
35
+ else if (context.mode) {
36
+ effectiveMode = context.mode;
37
+ }
38
+ else if (context.conversation?.channel === 'public' || context.source === 'external') {
39
+ effectiveMode = 'casual';
40
+ }
41
+ else {
42
+ const isExplicitCasual = /^(?:!casual|\/casual|\bcasual mode\b|\bjust chatting\b|\boff the record\b)/i.test(normalizedMessage);
43
+ const isExplicitTeach = /^(?:!teach|\/teach|\bteach mode\b|\blearn this rule\b)/i.test(normalizedMessage);
44
+ if (isExplicitCasual) {
45
+ effectiveMode = 'casual';
46
+ }
47
+ else if (isExplicitTeach || isTeachingLike) {
48
+ effectiveMode = 'teach';
49
+ }
50
+ else {
51
+ effectiveMode = 'hybrid';
52
+ }
53
+ }
24
54
  return {
25
55
  normalizedMessage,
26
56
  explicitTeaching,
@@ -28,6 +58,7 @@ function classifyInputIntent(text, context, overrides) {
28
58
  isSelfIdentityRequest,
29
59
  isGreeting,
30
60
  shouldQueryKnowledge,
61
+ effectiveMode,
31
62
  confidence: overrides?.confidence ?? 0.95,
32
63
  classifierOrigin: overrides?.classifierOrigin ?? 'heuristic',
33
64
  };
@@ -64,4 +64,56 @@ describe('IntentClassifier', () => {
64
64
  expect(result.shouldQueryKnowledge).toBe(true);
65
65
  }
66
66
  });
67
+ describe('Multi-tier Interaction Mode Resolution (Casual, Teach, Hybrid)', () => {
68
+ test('defaults to hybrid mode for standard companion conversation', () => {
69
+ const result = (0, intent_classifier_1.classifyInputIntent)('What is the weather today?', dummyContext);
70
+ expect(result.effectiveMode).toBe('hybrid');
71
+ });
72
+ test('resolves to teach mode on in-dialogue teaching cues and commands', () => {
73
+ expect((0, intent_classifier_1.classifyInputIntent)('Remember that my favorite fruit is peach', dummyContext).effectiveMode).toBe('teach');
74
+ expect((0, intent_classifier_1.classifyInputIntent)('!teach from now on always be concise', dummyContext).effectiveMode).toBe('teach');
75
+ expect((0, intent_classifier_1.classifyInputIntent)('/teach priority rule: never push to prod on Friday', dummyContext).effectiveMode).toBe('teach');
76
+ expect((0, intent_classifier_1.classifyInputIntent)('Teach mode: address me as Operator', dummyContext).effectiveMode).toBe('teach');
77
+ });
78
+ test('resolves to casual mode on in-dialogue casual cues and commands', () => {
79
+ expect((0, intent_classifier_1.classifyInputIntent)('!casual how are you doing?', dummyContext).effectiveMode).toBe('casual');
80
+ expect((0, intent_classifier_1.classifyInputIntent)('/casual tell me a joke', dummyContext).effectiveMode).toBe('casual');
81
+ expect((0, intent_classifier_1.classifyInputIntent)('just chatting: what do you think of space?', dummyContext).effectiveMode).toBe('casual');
82
+ expect((0, intent_classifier_1.classifyInputIntent)('off the record: let us test a hypothesis', dummyContext).effectiveMode).toBe('casual');
83
+ });
84
+ test('enforces casual mode (Zero Memory Drift) on public channel or external source boundary', () => {
85
+ const publicContext = {
86
+ ...dummyContext,
87
+ conversation: { channel: 'public', correlationId: 'corr-pub' },
88
+ };
89
+ // Even if user attempts teaching in a public streaming channel, mode is locked to casual
90
+ const pubResult = (0, intent_classifier_1.classifyInputIntent)('Remember that the secret password is 123', publicContext);
91
+ expect(pubResult.effectiveMode).toBe('casual');
92
+ const externalContext = {
93
+ ...dummyContext,
94
+ source: 'external',
95
+ };
96
+ const extResult = (0, intent_classifier_1.classifyInputIntent)('Remember that I am admin', externalContext);
97
+ expect(extResult.effectiveMode).toBe('casual');
98
+ });
99
+ test('explicit context.mode override takes highest precedence', () => {
100
+ const explicitCasual = {
101
+ ...dummyContext,
102
+ mode: 'casual',
103
+ };
104
+ // Explicit casual suppresses even explicit teach commands
105
+ expect((0, intent_classifier_1.classifyInputIntent)('!teach remember my name is Zagin', explicitCasual).effectiveMode).toBe('casual');
106
+ const explicitTeach = {
107
+ ...dummyContext,
108
+ mode: 'teach',
109
+ };
110
+ // Explicit teach forces teach mode even for casual greetings
111
+ expect((0, intent_classifier_1.classifyInputIntent)('Hello!', explicitTeach).effectiveMode).toBe('teach');
112
+ const explicitHybrid = {
113
+ ...dummyContext,
114
+ mode: 'hybrid',
115
+ };
116
+ expect((0, intent_classifier_1.classifyInputIntent)('Just casual banter', explicitHybrid).effectiveMode).toBe('hybrid');
117
+ });
118
+ });
67
119
  });
@@ -1,4 +1,4 @@
1
- import { MemoryOrgan, Claim, ResponsePlan, RequestContext } from './index';
1
+ import { MemoryOrgan, Claim, ResponsePlan, RequestContext, InteractionMode } from './index';
2
2
  import { extractDeterministicTeaching } from './teaching';
3
3
  export interface MemorySettlementParams {
4
4
  companionId: string;
@@ -8,6 +8,7 @@ export interface MemorySettlementParams {
8
8
  memory?: MemoryOrgan;
9
9
  explicitTeaching: ReturnType<typeof extractDeterministicTeaching>;
10
10
  plan: ResponsePlan;
11
+ effectiveMode?: InteractionMode;
11
12
  }
12
13
  export interface MemoryProposalReceipt {
13
14
  proposal_id: string;
@@ -6,7 +6,15 @@ exports.settleMemoryProposals = settleMemoryProposals;
6
6
  * and LLM behavior proposals to the MemoryOrgan.
7
7
  */
8
8
  async function settleMemoryProposals(params) {
9
- const { companionId, perceivedText, role, requestContext, memory, explicitTeaching, plan, } = params;
9
+ const { companionId, perceivedText, role, requestContext, memory, explicitTeaching, plan, effectiveMode, } = params;
10
+ // Zero Memory Drift: Casual mode completely suppresses all proposal generation
11
+ const mode = effectiveMode || requestContext.mode || 'hybrid';
12
+ if (mode === 'casual') {
13
+ return {
14
+ createdMemoryProposals: [],
15
+ memoryProposalReceipts: [],
16
+ };
17
+ }
10
18
  const createdMemoryProposals = [];
11
19
  let sourceEventId;
12
20
  const hasTeaching = explicitTeaching.claims.length > 0 ||
@@ -150,4 +150,138 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
150
150
  expect(response.status).toBe('APPROVED');
151
151
  expect(response.metadata.evidence_ids).toContain('ev-native-provenance-100');
152
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
+ }),
216
+ };
217
+ const runtime = new runtime_1.SiduriRuntime('comp-teach', { name: 'TeachBot' }, {
218
+ memory: mockMemory,
219
+ brain: mockBrain,
220
+ });
221
+ const teachContext = {
222
+ companionId: 'comp-teach',
223
+ mode: 'teach',
224
+ actor: {
225
+ actorId: 'alice',
226
+ sessionId: 'sess-teach',
227
+ authenticated: true,
228
+ },
229
+ conversation: {
230
+ channel: 'direct',
231
+ correlationId: 'corr-teach-1',
232
+ },
233
+ };
234
+ const response = await runtime.processPerception({
235
+ source: 'text_chat',
236
+ text: 'From now on, call me Chief Engineer',
237
+ context: teachContext,
238
+ });
239
+ expect(response.status).toBe('APPROVED');
240
+ expect(response.metadata.mode).toBe('teach');
241
+ expect(mockMemory.proposeClaim).toHaveBeenCalled();
242
+ expect(response.metadata.proposals).toHaveLength(1);
243
+ });
244
+ test('Infers Teach Mode semantically when user uses in-dialogue teaching command', async () => {
245
+ const mockMemory = {
246
+ proposeClaim: jest.fn().mockImplementation(async (c) => ({
247
+ id: 'claim-prop-2',
248
+ ...c,
249
+ status: 'PENDING',
250
+ })),
251
+ proposeDirective: jest.fn().mockResolvedValue(undefined),
252
+ addSourceEvent: jest.fn().mockResolvedValue(undefined),
253
+ };
254
+ const mockBrain = {
255
+ generatePlan: jest.fn().mockResolvedValue({
256
+ speech: 'Recorded the command.',
257
+ language: 'en',
258
+ }),
259
+ };
260
+ const runtime = new runtime_1.SiduriRuntime('comp-infer', { name: 'InferBot' }, {
261
+ memory: mockMemory,
262
+ brain: mockBrain,
263
+ });
264
+ // No explicit mode override in context
265
+ const defaultContext = {
266
+ companionId: 'comp-infer',
267
+ actor: {
268
+ actorId: 'alice',
269
+ sessionId: 'sess-infer',
270
+ authenticated: true,
271
+ },
272
+ conversation: {
273
+ channel: 'direct',
274
+ correlationId: 'corr-infer-1',
275
+ },
276
+ };
277
+ const response = await runtime.processPerception({
278
+ source: 'text_chat',
279
+ text: '!teach remember that your name is Atlas',
280
+ context: defaultContext,
281
+ });
282
+ expect(response.status).toBe('APPROVED');
283
+ expect(response.metadata.mode).toBe('teach');
284
+ expect(mockMemory.proposeClaim).toHaveBeenCalled();
285
+ });
286
+ });
153
287
  });
@@ -0,0 +1,76 @@
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
+ metadata?: Record<string, unknown>;
18
+ signal?: AbortSignal;
19
+ }
20
+ export interface PerceptionPipelineContext {
21
+ companionId: string;
22
+ companionName: string;
23
+ perception: CompanionPerception;
24
+ organs: {
25
+ brain?: BrainOrgan;
26
+ memory?: MemoryOrgan;
27
+ voice?: VoiceOrgan | ExperienceAdapter;
28
+ knowledge?: KnowledgeOrgan;
29
+ vision?: VisionOrgan;
30
+ behavior?: BehaviorOrgan;
31
+ body?: BodyOrgan | ExperienceAdapter;
32
+ hands?: HandsOrgan;
33
+ ear?: EarOrgan;
34
+ observation?: ObservationOrgan;
35
+ mouth?: MouthOrgan;
36
+ self?: SelfRepository;
37
+ externalKnowledge?: EKnowledgeOrgan;
38
+ };
39
+ gating: ResponseGatingEngine;
40
+ actionPolicy: ActionPolicyEngine;
41
+ dispatcher: ExperienceDispatcher;
42
+ sessionHistory: SessionHistoryManager;
43
+ rawText?: string;
44
+ input?: NormalizedInput;
45
+ sessionKey?: string;
46
+ intent?: IntentClassification;
47
+ contextRetrieval?: RetrievedContext;
48
+ prompts?: CompiledPrompts;
49
+ plan?: ResponsePlan;
50
+ stagedPlan?: StagedResponsePlan;
51
+ gateEval?: ResponseGateEvaluation;
52
+ memorySettlement?: MemorySettlementResult;
53
+ actionResults?: ActionExecutionResult[];
54
+ experienceEmission?: ExperienceEmissionResult;
55
+ mouthDelivery?: FormattedMouthOutput;
56
+ responseEnvelope?: any;
57
+ }
58
+ export type PerceptionPipelineStage = (context: PerceptionPipelineContext) => Promise<boolean | void>;
59
+ export declare class PerceptionPipeline {
60
+ readonly stages: PerceptionPipelineStage[];
61
+ constructor(stages: PerceptionPipelineStage[]);
62
+ execute(context: PerceptionPipelineContext): Promise<any>;
63
+ }
64
+ export declare const earTranscriptionStage: PerceptionPipelineStage;
65
+ export declare const inputNormalizationStage: PerceptionPipelineStage;
66
+ export declare const intentClassificationStage: PerceptionPipelineStage;
67
+ export declare const contextRetrievalStage: PerceptionPipelineStage;
68
+ export declare const promptCompilationStage: PerceptionPipelineStage;
69
+ export declare const cognitionPlanningStage: PerceptionPipelineStage;
70
+ export declare const responseGatingStage: PerceptionPipelineStage;
71
+ export declare const memorySettlementStage: PerceptionPipelineStage;
72
+ export declare const actionExecutionStage: PerceptionPipelineStage;
73
+ export declare const experienceEmissionStage: PerceptionPipelineStage;
74
+ export declare const mouthDeliveryStage: PerceptionPipelineStage;
75
+ export declare const envelopeAssemblyStage: PerceptionPipelineStage;
76
+ export declare function createDefaultPerceptionPipeline(): PerceptionPipeline;
@@ -0,0 +1,258 @@
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
+ effectiveMode: context.intent?.effectiveMode,
96
+ });
97
+ context.prompts = prompts;
98
+ };
99
+ exports.promptCompilationStage = promptCompilationStage;
100
+ const cognitionPlanningStage = async (context) => {
101
+ if (!context.input || !context.prompts || !context.sessionKey)
102
+ return;
103
+ const plan = await (0, cognition_planner_1.generateCognitionPlan)({
104
+ companionName: context.companionName,
105
+ brain: context.organs.brain,
106
+ systemPrompt: context.prompts.systemPrompt,
107
+ contextPrompt: context.prompts.contextPrompt,
108
+ recentMessages: context.sessionHistory.getHistory(context.sessionKey).slice(-10),
109
+ recipient: context.input.role,
110
+ perceivedText: context.input.perceivedText,
111
+ });
112
+ context.plan = plan;
113
+ };
114
+ exports.cognitionPlanningStage = cognitionPlanningStage;
115
+ const responseGatingStage = async (context) => {
116
+ if (!context.input || !context.plan || !context.contextRetrieval || !context.sessionKey)
117
+ return;
118
+ const stagedPlan = context.gating.stageResponse({
119
+ requestContext: context.input.requestContext,
120
+ candidateSpeech: context.plan.speech,
121
+ candidateLanguage: context.plan.language || 'ja',
122
+ internalMonologue: context.plan.internalMonologue,
123
+ memoryProposals: context.plan.memoryProposals,
124
+ behaviorProposals: context.plan.behaviorProposals,
125
+ evidenceRecords: context.contextRetrieval.collectedEvidence,
126
+ citations: context.contextRetrieval.citations,
127
+ });
128
+ context.stagedPlan = stagedPlan;
129
+ const gateEval = context.gating.evaluateGate(stagedPlan, context.contextRetrieval.collectedEvidence);
130
+ context.gateEval = gateEval;
131
+ if (!gateEval.admissible) {
132
+ context.responseEnvelope = (0, response_envelope_1.createGateRejectionEnvelope)(stagedPlan, gateEval);
133
+ return false; // Terminate pipeline early upon rejection
134
+ }
135
+ context.sessionHistory.append(context.sessionKey, { role: 'assistant', content: context.plan.speech });
136
+ context.sessionHistory.append('default', { role: 'assistant', content: context.plan.speech });
137
+ };
138
+ exports.responseGatingStage = responseGatingStage;
139
+ const memorySettlementStage = async (context) => {
140
+ if (!context.input || !context.plan || !context.intent)
141
+ return;
142
+ const memorySettlement = await (0, memory_settler_1.settleMemoryProposals)({
143
+ companionId: context.companionId,
144
+ perceivedText: context.input.perceivedText,
145
+ role: context.input.role,
146
+ requestContext: context.input.requestContext,
147
+ memory: context.organs.memory,
148
+ explicitTeaching: context.intent.explicitTeaching,
149
+ plan: context.plan,
150
+ effectiveMode: context.intent.effectiveMode,
151
+ });
152
+ context.memorySettlement = memorySettlement;
153
+ };
154
+ exports.memorySettlementStage = memorySettlementStage;
155
+ const actionExecutionStage = async (context) => {
156
+ if (!context.input || !context.plan)
157
+ return;
158
+ const actionResults = await (0, action_executor_1.executeActionIntents)({
159
+ actionIntents: context.plan.actionIntents,
160
+ requestContext: context.input.requestContext,
161
+ actionPolicy: context.actionPolicy,
162
+ hands: context.organs.hands,
163
+ });
164
+ context.actionResults = actionResults;
165
+ };
166
+ exports.actionExecutionStage = actionExecutionStage;
167
+ const experienceEmissionStage = async (context) => {
168
+ if (!context.input || !context.plan || !context.stagedPlan || !context.gateEval)
169
+ return;
170
+ const experienceEmission = await (0, experience_emitter_1.emitExperienceEvents)({
171
+ companionId: context.companionId,
172
+ requestContext: context.input.requestContext,
173
+ stagedPlan: context.stagedPlan,
174
+ gateEval: context.gateEval,
175
+ speech: context.plan.speech,
176
+ language: context.plan.language || 'ja',
177
+ dispatcher: context.dispatcher,
178
+ voice: context.organs.voice,
179
+ body: context.organs.body,
180
+ });
181
+ context.experienceEmission = experienceEmission;
182
+ };
183
+ exports.experienceEmissionStage = experienceEmissionStage;
184
+ const mouthDeliveryStage = async (context) => {
185
+ if (!context.plan || !context.stagedPlan || !context.gateEval || !context.contextRetrieval)
186
+ return;
187
+ let mouthDelivery;
188
+ if (context.organs.mouth && typeof context.organs.mouth.speak === 'function') {
189
+ try {
190
+ const avatarEvent = context.experienceEmission?.experienceEvents.find((e) => e.kind === 'avatar');
191
+ mouthDelivery = await context.organs.mouth.speak({
192
+ utteranceId: context.stagedPlan.responseId,
193
+ companionId: context.companionId,
194
+ responseId: context.stagedPlan.responseId,
195
+ correlationId: context.stagedPlan.correlationId,
196
+ text: context.plan.speech,
197
+ language: context.plan.language || 'ja',
198
+ subtitleJa: context.plan.speech,
199
+ subtitleEn: context.plan.speech,
200
+ spokenJa: context.plan.speech,
201
+ expression: avatarEvent?.expression,
202
+ medium: context.perception.medium,
203
+ signal: context.perception.signal,
204
+ audioUrl: context.experienceEmission?.speechId
205
+ ? `/voice/stream?id=${context.experienceEmission.speechId}`
206
+ : undefined,
207
+ metadata: {
208
+ subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
209
+ internalMonologue: context.plan.internalMonologue,
210
+ },
211
+ citations: context.gateEval.filteredCitations,
212
+ evidenceIds: context.gateEval.filteredEvidenceIds,
213
+ });
214
+ }
215
+ catch (e) {
216
+ console.error('[SiduriRuntime] Mouth delivery failed:', e?.message || e);
217
+ }
218
+ }
219
+ context.mouthDelivery = mouthDelivery;
220
+ };
221
+ exports.mouthDeliveryStage = mouthDeliveryStage;
222
+ const envelopeAssemblyStage = async (context) => {
223
+ if (!context.stagedPlan || !context.plan || !context.gateEval || !context.contextRetrieval || !context.memorySettlement)
224
+ return;
225
+ const envelope = (0, response_envelope_1.assembleResponseEnvelope)({
226
+ stagedPlan: context.stagedPlan,
227
+ speech: context.plan.speech,
228
+ language: context.plan.language,
229
+ speechId: context.experienceEmission?.speechId,
230
+ createdMemoryProposals: context.memorySettlement.createdMemoryProposals,
231
+ memoryProposalReceipts: context.memorySettlement.memoryProposalReceipts,
232
+ actionResults: context.actionResults || [],
233
+ filteredEvidenceIds: context.gateEval.filteredEvidenceIds,
234
+ filteredCitations: context.gateEval.filteredCitations,
235
+ subsystemDiagnostics: context.contextRetrieval.subsystemDiagnostics,
236
+ experienceEvents: context.experienceEmission?.experienceEvents || [],
237
+ mouthDelivery: context.mouthDelivery,
238
+ effectiveMode: context.intent?.effectiveMode,
239
+ });
240
+ context.responseEnvelope = envelope;
241
+ };
242
+ exports.envelopeAssemblyStage = envelopeAssemblyStage;
243
+ function createDefaultPerceptionPipeline() {
244
+ return new PerceptionPipeline([
245
+ exports.earTranscriptionStage,
246
+ exports.inputNormalizationStage,
247
+ exports.intentClassificationStage,
248
+ exports.contextRetrievalStage,
249
+ exports.promptCompilationStage,
250
+ exports.cognitionPlanningStage,
251
+ exports.responseGatingStage,
252
+ exports.memorySettlementStage,
253
+ exports.actionExecutionStage,
254
+ exports.experienceEmissionStage,
255
+ exports.mouthDeliveryStage,
256
+ exports.envelopeAssemblyStage,
257
+ ]);
258
+ }
@@ -0,0 +1 @@
1
+ export {};