@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.
- package/dist/action-policy.d.ts +35 -1
- package/dist/action-policy.js +228 -8
- package/dist/action-policy.test.js +171 -1
- package/dist/action.d.ts +1 -1
- package/dist/adversarial.test.js +4 -2
- package/dist/capability.d.ts +15 -2
- package/dist/capability.js +12 -1
- package/dist/capability.test.js +44 -1
- package/dist/chat-contract.d.ts +3 -1
- package/dist/chat-contract.js +5 -2
- package/dist/container.d.ts +74 -0
- package/dist/container.js +81 -0
- package/dist/context.d.ts +1 -1
- package/dist/index.d.ts +11 -7
- package/dist/index.js +2 -0
- package/dist/input-normalizer.js +3 -1
- package/dist/perception-pipeline.d.ts +76 -0
- package/dist/perception-pipeline.js +255 -0
- package/dist/perception-pipeline.test.d.ts +1 -0
- package/dist/perception-pipeline.test.js +65 -0
- package/dist/runtime-facades.test.js +27 -27
- package/dist/runtime.d.ts +36 -112
- package/dist/runtime.js +58 -392
- package/dist/schema-validator.test.js +2 -2
- package/dist/siduri-db.d.ts +27 -8
- package/dist/siduri-db.js +260 -17
- package/dist/siduri-db.test.js +284 -0
- package/dist/sqlite-action-store.d.ts +3 -2
- package/dist/sqlite-action-store.js +60 -6
- package/dist/sqlite-action-store.test.js +10 -0
- package/package.json +6 -6
package/dist/capability.test.js
CHANGED
|
@@ -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.
|
|
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
|
package/dist/chat-contract.d.ts
CHANGED
|
@@ -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
|
|
81
|
+
export declare function dispatchCompanionChat(runtime: SiduriRuntime | {
|
|
82
|
+
runtime: SiduriRuntime;
|
|
83
|
+
}, payload: ChatRequest): Promise<ChatResponse>;
|
package/dist/chat-contract.js
CHANGED
|
@@ -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
|
|
23
|
-
: await
|
|
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'>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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);
|
package/dist/input-normalizer.js
CHANGED
|
@@ -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'
|
|
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 {};
|