@siduri-x/core 2.0.0 → 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.
@@ -165,6 +165,7 @@ describe('AuthorizationCapability Cryptographic & Tamper Review', () => {
165
165
  decisionCode: event1.decision.decisionCode,
166
166
  } : null,
167
167
  parametersHash: event1.parametersHash || null,
168
+ resultHash: null,
168
169
  error: event1.error || null,
169
170
  timestamp: event1.timestamp,
170
171
  });
@@ -190,6 +191,7 @@ describe('AuthorizationCapability Cryptographic & Tamper Review', () => {
190
191
  decisionCode: event2.decision.decisionCode,
191
192
  } : null,
192
193
  parametersHash: event2.parametersHash || null,
194
+ resultHash: null,
193
195
  error: event2.error || null,
194
196
  timestamp: event2.timestamp,
195
197
  });
@@ -203,7 +205,47 @@ describe('AuthorizationCapability Cryptographic & Tamper Review', () => {
203
205
  });
204
206
  const tamperedHash1 = crypto.createHash('sha256').update(`${initialPrevHash}:${tamperedCanonical1}`, 'utf8').digest('hex');
205
207
  const brokenHash2 = crypto.createHash('sha256').update(`${tamperedHash1}:${canonical2}`, 'utf8').digest('hex');
206
- expect(brokenHash2).not.toBe(event2.resultHash);
208
+ expect(brokenHash2).not.toBe(event2.eventHash);
209
+ });
210
+ it('detects tampering with resultHash on completed action events', async () => {
211
+ const store = new capability_1.InMemoryActionStore();
212
+ const initialPrevHash = '0000000000000000000000000000000000000000000000000000000000000000';
213
+ const event = {
214
+ executionId: 'exec-1',
215
+ actionId: 'act-1',
216
+ toolName: 'comm/send_email',
217
+ companionId: 'comp-1',
218
+ riskLevel: 'LOW',
219
+ lifecycle: 'COMPLETED',
220
+ parametersHash: 'param-hash-1',
221
+ resultHash: 'result-hash-original',
222
+ timestamp: '2026-09-12T10:00:00.000Z',
223
+ };
224
+ await store.appendAudit(event);
225
+ const log = await store.getAuditLog();
226
+ const recorded = log[0];
227
+ // Tampering with resultHash changes canonical payload and recalculates a mismatched hash
228
+ const tamperedPayload = {
229
+ executionId: recorded.executionId,
230
+ actionId: recorded.actionId,
231
+ toolName: recorded.toolName,
232
+ providerId: recorded.providerId || null,
233
+ companionId: recorded.companionId,
234
+ actorId: recorded.actorId || null,
235
+ sessionId: recorded.sessionId || null,
236
+ channel: recorded.channel || null,
237
+ correlationId: recorded.correlationId || null,
238
+ riskLevel: recorded.riskLevel,
239
+ lifecycle: recorded.lifecycle,
240
+ decision: null,
241
+ parametersHash: recorded.parametersHash || null,
242
+ resultHash: 'result-hash-TAMPERED',
243
+ error: recorded.error || null,
244
+ timestamp: recorded.timestamp,
245
+ };
246
+ const tamperedCanonical = (0, capability_1.canonicalizeJson)(tamperedPayload);
247
+ const recomputedHash = crypto.createHash('sha256').update(`${initialPrevHash}:${tamperedCanonical}`, 'utf8').digest('hex');
248
+ expect(recomputedHash).not.toBe(recorded.eventHash);
207
249
  });
208
250
  });
209
251
  describe('Durable Action Approval Restart Semantics', () => {
@@ -239,6 +281,7 @@ describe('AuthorizationCapability Cryptographic & Tamper Review', () => {
239
281
  await engine1.approveAction({
240
282
  executionId: 'exec-restart-1',
241
283
  approverActorId: 'operator-1',
284
+ approverRole: 'operator',
242
285
  reason: 'Scheduled maintenance',
243
286
  });
244
287
  // 3. Process restarts: new ActionPolicyEngine instance with empty in-memory set but shared durable store
@@ -78,4 +78,6 @@ export interface ChatResponse {
78
78
  * Canonical helper to dispatch a chat request to a SiduriRuntime instance.
79
79
  * Guarantees a 1:1 identical response structure for localweb (apps/api) and standalone CLI.
80
80
  */
81
- export declare function dispatchCompanionChat(runtime: SiduriRuntime, payload: ChatRequest): Promise<ChatResponse>;
81
+ export declare function dispatchCompanionChat(runtime: SiduriRuntime | {
82
+ runtime: SiduriRuntime;
83
+ }, payload: ChatRequest): Promise<ChatResponse>;
@@ -6,6 +6,9 @@ exports.dispatchCompanionChat = dispatchCompanionChat;
6
6
  * Guarantees a 1:1 identical response structure for localweb (apps/api) and standalone CLI.
7
7
  */
8
8
  async function dispatchCompanionChat(runtime, payload) {
9
+ const runner = 'runtime' in runtime && typeof runtime.handleUserMessage !== 'function'
10
+ ? runtime.runtime
11
+ : runtime;
9
12
  const userMessage = payload.message || payload.text || '';
10
13
  const history = Array.isArray(payload.history) ? payload.history : [];
11
14
  let roleOrContext;
@@ -19,8 +22,8 @@ async function dispatchCompanionChat(runtime, payload) {
19
22
  roleOrContext = 'OWNER';
20
23
  }
21
24
  const runtimeResult = (payload.medium || payload.signal)
22
- ? await runtime.handleUserMessage(userMessage, roleOrContext, history, payload.medium, payload.signal)
23
- : await runtime.handleUserMessage(userMessage, roleOrContext, history);
25
+ ? await runner.handleUserMessage(userMessage, roleOrContext, history, payload.medium, payload.signal)
26
+ : await runner.handleUserMessage(userMessage, roleOrContext, history);
24
27
  const delivery = runtimeResult?.delivery;
25
28
  // Normalize response plan
26
29
  const speech = delivery?.displayText ||
@@ -0,0 +1,74 @@
1
+ import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan, MouthOrgan, SelfRepository, EKnowledgeOrgan, OrganConfig, ActionStore, ActionPolicyEngine, ResponseGatingEngine, ExperienceDispatcher, ExperienceAdapter } from './index';
2
+ import { SessionHistoryManager } from './session-history';
3
+ import { SiduriRuntime } from './runtime';
4
+ export interface SiduriRuntimeConfig {
5
+ name: string;
6
+ brain?: OrganConfig | Record<string, unknown>;
7
+ voice?: OrganConfig | Record<string, unknown>;
8
+ memory?: OrganConfig | Record<string, unknown>;
9
+ knowledge?: OrganConfig | Record<string, unknown>;
10
+ behavior?: OrganConfig | Record<string, unknown>;
11
+ body?: OrganConfig | Record<string, unknown>;
12
+ vision?: OrganConfig | Record<string, unknown>;
13
+ hands?: OrganConfig | Record<string, unknown>;
14
+ ear?: OrganConfig | Record<string, unknown>;
15
+ observation?: OrganConfig | Record<string, unknown>;
16
+ mouth?: OrganConfig | Record<string, unknown>;
17
+ self?: OrganConfig | Record<string, unknown>;
18
+ externalKnowledge?: OrganConfig | Record<string, unknown>;
19
+ actionPolicy?: Record<string, unknown>;
20
+ actionStore?: 'in-memory' | 'sqlite' | {
21
+ type: 'sqlite' | 'in-memory';
22
+ dbPath?: string;
23
+ };
24
+ actionStorePath?: string;
25
+ [key: string]: unknown;
26
+ }
27
+ export interface RuntimeOrgans {
28
+ brain?: BrainOrgan;
29
+ memory?: MemoryOrgan;
30
+ voice?: VoiceOrgan | ExperienceAdapter;
31
+ knowledge?: KnowledgeOrgan;
32
+ vision?: VisionOrgan;
33
+ behavior?: BehaviorOrgan;
34
+ body?: BodyOrgan | ExperienceAdapter;
35
+ hands?: HandsOrgan;
36
+ ear?: EarOrgan;
37
+ observation?: ObservationOrgan;
38
+ mouth?: MouthOrgan;
39
+ self?: SelfRepository;
40
+ externalKnowledge?: EKnowledgeOrgan;
41
+ actionStore?: ActionStore;
42
+ actionPolicy?: ActionPolicyEngine;
43
+ }
44
+ /**
45
+ * CompanionContainer manages the lifecycle, discovery, wiring, and dependency injection
46
+ * of organs and infrastructure for a companion instance.
47
+ */
48
+ export declare class CompanionContainer {
49
+ readonly id: string;
50
+ readonly config: SiduriRuntimeConfig;
51
+ readonly organs: RuntimeOrgans;
52
+ readonly gating: ResponseGatingEngine;
53
+ readonly actionPolicy: ActionPolicyEngine;
54
+ readonly dispatcher: ExperienceDispatcher;
55
+ readonly sessionHistory: SessionHistoryManager;
56
+ private _runtime?;
57
+ constructor(id: string, config: SiduriRuntimeConfig, organs?: RuntimeOrgans);
58
+ get brain(): BrainOrgan | undefined;
59
+ get memory(): MemoryOrgan | undefined;
60
+ get voice(): ExperienceAdapter | VoiceOrgan | undefined;
61
+ get knowledge(): KnowledgeOrgan | undefined;
62
+ get vision(): VisionOrgan | undefined;
63
+ get behavior(): BehaviorOrgan | undefined;
64
+ get body(): ExperienceAdapter | BodyOrgan | undefined;
65
+ get hands(): HandsOrgan | undefined;
66
+ get ear(): EarOrgan | undefined;
67
+ get observation(): ObservationOrgan | undefined;
68
+ set observation(org: ObservationOrgan | undefined);
69
+ get mouth(): MouthOrgan | undefined;
70
+ get self(): SelfRepository | undefined;
71
+ get externalKnowledge(): EKnowledgeOrgan | undefined;
72
+ initialize(): Promise<void>;
73
+ get runtime(): SiduriRuntime;
74
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompanionContainer = void 0;
4
+ const index_1 = require("./index");
5
+ const session_history_1 = require("./session-history");
6
+ const runtime_1 = require("./runtime");
7
+ /**
8
+ * CompanionContainer manages the lifecycle, discovery, wiring, and dependency injection
9
+ * of organs and infrastructure for a companion instance.
10
+ */
11
+ class CompanionContainer {
12
+ id;
13
+ config;
14
+ organs;
15
+ gating;
16
+ actionPolicy;
17
+ dispatcher;
18
+ sessionHistory;
19
+ _runtime;
20
+ constructor(id, config, organs = {}) {
21
+ this.id = id;
22
+ this.config = config;
23
+ this.organs = organs;
24
+ this.gating = new index_1.ResponseGatingEngine();
25
+ let actionStore = organs.actionStore;
26
+ if (!actionStore) {
27
+ const storeOpt = config.actionStore;
28
+ const storePath = config.actionStorePath || (typeof storeOpt === 'object' ? storeOpt.dbPath : undefined);
29
+ if (storeOpt === 'sqlite' || (typeof storeOpt === 'object' && storeOpt.type === 'sqlite') || storePath) {
30
+ actionStore = new index_1.SqliteActionStore({ dbPath: storePath });
31
+ }
32
+ }
33
+ this.actionPolicy = organs.actionPolicy || new index_1.ActionPolicyEngine({
34
+ store: actionStore,
35
+ });
36
+ this.dispatcher = new index_1.ExperienceDispatcher();
37
+ if (this.organs.voice && typeof this.organs.voice.handleEvent === 'function') {
38
+ this.dispatcher.registerAdapter(this.organs.voice);
39
+ }
40
+ if (this.organs.body && typeof this.organs.body.handleEvent === 'function') {
41
+ this.dispatcher.registerAdapter(this.organs.body);
42
+ }
43
+ if (this.organs.mouth && typeof this.organs.mouth.handleEvent === 'function') {
44
+ this.dispatcher.registerAdapter(this.organs.mouth);
45
+ }
46
+ this.sessionHistory = new session_history_1.SessionHistoryManager();
47
+ }
48
+ // Direct organ accessors
49
+ get brain() { return this.organs.brain; }
50
+ get memory() { return this.organs.memory; }
51
+ get voice() { return this.organs.voice; }
52
+ get knowledge() { return this.organs.knowledge; }
53
+ get vision() { return this.organs.vision; }
54
+ get behavior() { return this.organs.behavior; }
55
+ get body() { return this.organs.body; }
56
+ get hands() { return this.organs.hands; }
57
+ get ear() { return this.organs.ear; }
58
+ get observation() { return this.organs.observation; }
59
+ set observation(org) { this.organs.observation = org; }
60
+ get mouth() { return this.organs.mouth; }
61
+ get self() { return this.organs.self; }
62
+ get externalKnowledge() { return this.organs.externalKnowledge; }
63
+ async initialize() {
64
+ if (this.organs.memory && typeof this.organs.memory.initialize === 'function') {
65
+ await this.organs.memory.initialize(this.id);
66
+ }
67
+ if (this.organs.hands && typeof this.organs.hands.listTools === 'function') {
68
+ const tools = await this.organs.hands.listTools();
69
+ for (const tool of tools) {
70
+ this.actionPolicy.registerToolDefinition(tool);
71
+ }
72
+ }
73
+ }
74
+ get runtime() {
75
+ if (!this._runtime) {
76
+ this._runtime = new runtime_1.SiduriRuntime(this.id, this.config, this);
77
+ }
78
+ return this._runtime;
79
+ }
80
+ }
81
+ exports.CompanionContainer = CompanionContainer;
package/dist/context.d.ts CHANGED
@@ -25,7 +25,7 @@ export interface RequestContext {
25
25
  subject?: SubjectRef;
26
26
  metadata?: Record<string, unknown>;
27
27
  }
28
- export type DiagnosticCode = 'legacy_role_removed' | 'anonymous_session_generated' | 'companion_default_mapped_for_bootstrap' | 'actor_scoped_subject_mapped';
28
+ export type DiagnosticCode = 'legacy_role_removed' | 'anonymous_session_generated' | 'companion_default_mapped_for_bootstrap' | 'actor_scoped_subject_mapped' | 'role_escalation_attempt_suppressed' | 'capability_escalation_attempt_suppressed';
29
29
  export type ContextErrorCode = 'MISSING_CONTEXT' | 'INVALID_CONTEXT' | 'FORBIDDEN_CONTEXT' | 'AMBIGUOUS_CONTEXT' | 'UNAUTHORIZED_CAPABILITY';
30
30
  export interface ContextError {
31
31
  code: ContextErrorCode;
package/dist/index.d.ts CHANGED
@@ -25,6 +25,8 @@ export * from './session-history';
25
25
  export * from './schema-validator';
26
26
  export * from './siduri-db';
27
27
  export * from './database';
28
+ export * from './container';
29
+ export * from './perception-pipeline';
28
30
  import { EvidenceRecord } from './evidence';
29
31
  import { ActionIntent } from './action';
30
32
  import { RequestContext } from './context';
@@ -124,13 +126,15 @@ export interface MemoryOrgan {
124
126
  markClaimSessionOnly?(id: string): Promise<void>;
125
127
  expireClaim?(id: string): Promise<void>;
126
128
  revokeClaim?(id: string, reason?: string): Promise<void>;
127
- getDirectives(): Promise<BehaviorDirective[]>;
128
- proposeDirective(directiveData: Omit<BehaviorDirective, 'id' | 'status' | 'companionId'>): Promise<BehaviorDirective>;
129
- approveDirective(id: string): Promise<void>;
130
- rejectDirective(id: string): Promise<void>;
131
- revokeDirective(id: string): Promise<void>;
132
- disableDirective(id: string): Promise<void>;
133
- expireDirective?(id: string): Promise<void>;
129
+ getDirectives(companionId?: string): Promise<BehaviorDirective[]>;
130
+ proposeDirective(directiveData: Omit<BehaviorDirective, 'id' | 'status' | 'companionId'> & {
131
+ companionId?: string;
132
+ }): Promise<BehaviorDirective>;
133
+ approveDirective(id: string, companionId?: string): Promise<void>;
134
+ rejectDirective(id: string, companionId?: string): Promise<void>;
135
+ revokeDirective(id: string, companionId?: string): Promise<void>;
136
+ disableDirective(id: string, companionId?: string): Promise<void>;
137
+ expireDirective?(id: string, companionId?: string): Promise<void>;
134
138
  supersedeClaim?(id: string, replacement: Omit<Claim, 'id' | 'status' | 'companionId'>): Promise<Claim>;
135
139
  updateClaim?(id: string, updates: Partial<Pick<Claim, 'subject' | 'predicate' | 'value' | 'scope' | 'sensitivity' | 'confidence' | 'validFrom' | 'validUntil'>>): Promise<Claim>;
136
140
  resetMemory?(): Promise<void>;
package/dist/index.js CHANGED
@@ -42,5 +42,7 @@ __exportStar(require("./session-history"), exports);
42
42
  __exportStar(require("./schema-validator"), exports);
43
43
  __exportStar(require("./siduri-db"), exports);
44
44
  __exportStar(require("./database"), exports);
45
+ __exportStar(require("./container"), exports);
46
+ __exportStar(require("./perception-pipeline"), exports);
45
47
  // Mouth (Communication & Output Delivery)
46
48
  __exportStar(require("./mouth-types"), exports);
@@ -16,7 +16,9 @@ async function normalizeUserInput(message, roleOrContext = 'OWNER', history = []
16
16
  }
17
17
  const isContextObject = typeof roleOrContext === 'object' && roleOrContext !== null;
18
18
  const role = isContextObject
19
- ? (roleOrContext.actor?.authorizationRole === 'viewer' ? 'VIEWER' : 'OWNER')
19
+ ? (roleOrContext.actor?.authorizationRole === 'viewer' || roleOrContext.actor?.authenticated === false
20
+ ? 'VIEWER'
21
+ : 'OWNER')
20
22
  : roleOrContext;
21
23
  const requestContext = isContextObject
22
24
  ? roleOrContext
@@ -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,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 {};