@siduri-x/core 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action-executor.d.ts +12 -0
- package/dist/action-executor.js +50 -0
- package/dist/action-policy.js +4 -9
- package/dist/architecture-boundary.test.js +1 -0
- package/dist/capability.d.ts +8 -0
- package/dist/capability.js +31 -4
- package/dist/chat-contract.d.ts +5 -1
- package/dist/chat-contract.js +26 -23
- package/dist/cognition-planner.d.ts +15 -0
- package/dist/cognition-planner.js +23 -0
- package/dist/context-retriever.d.ts +24 -0
- package/dist/context-retriever.js +92 -0
- package/dist/context.d.ts +11 -13
- package/dist/context.js +3 -23
- package/dist/context.test.js +7 -40
- package/dist/evidence.d.ts +12 -8
- package/dist/evidence.js +6 -4
- package/dist/experience-emitter.d.ts +21 -0
- package/dist/experience-emitter.js +48 -0
- package/dist/experience.d.ts +6 -5
- package/dist/experience.js +3 -2
- package/dist/experience.test.js +5 -4
- package/dist/gating.d.ts +3 -2
- package/dist/gating.js +4 -8
- package/dist/index.d.ts +27 -43
- package/dist/index.js +14 -0
- package/dist/input-normalizer.d.ts +14 -0
- package/dist/input-normalizer.js +58 -0
- package/dist/input-normalizer.test.d.ts +1 -0
- package/dist/input-normalizer.test.js +39 -0
- package/dist/intent-classifier.d.ts +24 -0
- package/dist/intent-classifier.js +53 -0
- package/dist/intent-classifier.test.d.ts +1 -0
- package/dist/intent-classifier.test.js +68 -0
- package/dist/memory-settler.d.ts +27 -0
- package/dist/memory-settler.js +95 -0
- package/dist/mouth-types.d.ts +85 -0
- package/dist/mouth-types.js +2 -0
- package/dist/perception-cycle.test.d.ts +1 -0
- package/dist/perception-cycle.test.js +155 -0
- package/dist/prompt-compiler.d.ts +20 -0
- package/dist/prompt-compiler.js +57 -0
- package/dist/prompt-compiler.test.d.ts +1 -0
- package/dist/prompt-compiler.test.js +76 -0
- package/dist/proposals.d.ts +30 -0
- package/dist/proposals.js +2 -0
- package/dist/response-envelope.d.ts +25 -0
- package/dist/response-envelope.js +64 -0
- package/dist/runtime-facades.test.d.ts +1 -0
- package/dist/runtime-facades.test.js +69 -0
- package/dist/runtime.d.ts +79 -15
- package/dist/runtime.js +327 -326
- package/dist/session-history.d.ts +20 -0
- package/dist/session-history.js +55 -0
- package/dist/session-history.test.d.ts +1 -0
- package/dist/session-history.test.js +38 -0
- package/dist/sqlite-action-store.d.ts +20 -0
- package/dist/sqlite-action-store.js +225 -0
- package/dist/sqlite-action-store.test.d.ts +1 -0
- package/dist/sqlite-action-store.test.js +252 -0
- package/package.json +1 -1
package/dist/evidence.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MemoryProposal, BehaviorProposal } from './proposals';
|
|
1
2
|
export type EvidenceOrigin = 'knowledge' | 'observation' | 'ocr' | 'platform' | 'conversation';
|
|
2
3
|
export type EvidenceTrust = 'configured' | 'provider' | 'untrusted';
|
|
3
4
|
export type EvidenceSensitivity = 'public' | 'private' | 'restricted';
|
|
@@ -14,10 +15,11 @@ export interface EvidenceRecord {
|
|
|
14
15
|
createdAt: string;
|
|
15
16
|
expiresAt?: string;
|
|
16
17
|
trust: EvidenceTrust;
|
|
17
|
-
sensitivity
|
|
18
|
-
allowedAudiences
|
|
18
|
+
sensitivity?: EvidenceSensitivity;
|
|
19
|
+
allowedAudiences?: string[];
|
|
19
20
|
companionId: string;
|
|
20
21
|
correlationId: string;
|
|
22
|
+
[key: string]: unknown;
|
|
21
23
|
}
|
|
22
24
|
export type ResponseApprovalStatus = 'STAGED' | 'APPROVED' | 'REJECTED' | 'EXPIRED' | 'EMITTED';
|
|
23
25
|
export type ResponseGateReasonCode = 'APPROVED_DIRECT' | 'APPROVAL_REQUIRED' | 'UNKNOWN_APPROVAL_ID' | 'APPROVAL_ID_MISMATCH' | 'COMPANION_MISMATCH' | 'AUDIENCE_MISMATCH' | 'EVIDENCE_EXPIRED' | 'EVIDENCE_SENSITIVITY_EXCLUDED' | 'UNRESOLVED_LOW_CONFIDENCE' | 'EMPTY_SPEECH' | 'PROPOSAL_VALIDATION_FAILED' | 'EXPLICITLY_REJECTED';
|
|
@@ -32,8 +34,8 @@ export interface StagedResponsePlan {
|
|
|
32
34
|
responseId: string;
|
|
33
35
|
companionId: string;
|
|
34
36
|
correlationId: string;
|
|
35
|
-
channel
|
|
36
|
-
audienceId
|
|
37
|
+
channel?: string;
|
|
38
|
+
audienceId?: string;
|
|
37
39
|
speech: string;
|
|
38
40
|
language: string;
|
|
39
41
|
evidenceIds: string[];
|
|
@@ -44,9 +46,10 @@ export interface StagedResponsePlan {
|
|
|
44
46
|
status: ResponseApprovalStatus;
|
|
45
47
|
createdAt: string;
|
|
46
48
|
expiresAt?: string;
|
|
47
|
-
memoryProposals?:
|
|
48
|
-
behaviorProposals?:
|
|
49
|
+
memoryProposals?: MemoryProposal[];
|
|
50
|
+
behaviorProposals?: BehaviorProposal[];
|
|
49
51
|
internalMonologue?: string;
|
|
52
|
+
[key: string]: unknown;
|
|
50
53
|
}
|
|
51
54
|
export interface ResponseGateEvaluation {
|
|
52
55
|
admissible: boolean;
|
|
@@ -59,9 +62,10 @@ export interface ResponseGateEvaluation {
|
|
|
59
62
|
}
|
|
60
63
|
export interface EvidenceFilterOptions {
|
|
61
64
|
companionId: string;
|
|
62
|
-
channel
|
|
63
|
-
audienceId
|
|
65
|
+
channel?: string;
|
|
66
|
+
audienceId?: string;
|
|
64
67
|
now?: string | Date;
|
|
68
|
+
[key: string]: unknown;
|
|
65
69
|
}
|
|
66
70
|
export declare function filterEvidenceRecords(records: EvidenceRecord[], options: EvidenceFilterOptions): {
|
|
67
71
|
admitted: EvidenceRecord[];
|
package/dist/evidence.js
CHANGED
|
@@ -19,16 +19,18 @@ function filterEvidenceRecords(records, options) {
|
|
|
19
19
|
continue;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
// 3.
|
|
23
|
-
if (
|
|
22
|
+
// 3. Optional audience intersection (audience-public is accessible everywhere)
|
|
23
|
+
if (options.audienceId &&
|
|
24
|
+
record.allowedAudiences &&
|
|
24
25
|
record.allowedAudiences.length > 0 &&
|
|
26
|
+
!record.allowedAudiences.includes('audience-public') &&
|
|
25
27
|
!record.allowedAudiences.includes(options.audienceId)) {
|
|
26
28
|
excluded.push({ record, reason: 'audience_not_allowed' });
|
|
27
29
|
continue;
|
|
28
30
|
}
|
|
29
|
-
// 4.
|
|
31
|
+
// 4. Optional channel sensitivity policy (if channel explicitly specified)
|
|
30
32
|
if (options.channel === 'public') {
|
|
31
|
-
if (record.sensitivity !== 'public') {
|
|
33
|
+
if (record.sensitivity && record.sensitivity !== 'public') {
|
|
32
34
|
excluded.push({ record, reason: 'sensitivity_private_in_public_channel' });
|
|
33
35
|
continue;
|
|
34
36
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RequestContext, StagedResponsePlan, ResponseGateEvaluation, ExperienceDispatcher, ExperienceEvent, ExperienceAdapter, VoiceOrgan, BodyOrgan } from './index';
|
|
2
|
+
export interface ExperienceEmissionParams {
|
|
3
|
+
companionId: string;
|
|
4
|
+
requestContext: RequestContext;
|
|
5
|
+
stagedPlan: StagedResponsePlan;
|
|
6
|
+
gateEval: ResponseGateEvaluation;
|
|
7
|
+
speech: string;
|
|
8
|
+
language: string;
|
|
9
|
+
dispatcher: ExperienceDispatcher;
|
|
10
|
+
voice?: VoiceOrgan | ExperienceAdapter;
|
|
11
|
+
body?: BodyOrgan | ExperienceAdapter;
|
|
12
|
+
}
|
|
13
|
+
export interface ExperienceEmissionResult {
|
|
14
|
+
experienceEvents: ExperienceEvent[];
|
|
15
|
+
speechId?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates ExperienceEvents, dispatches them through the ExperienceDispatcher,
|
|
19
|
+
* and coordinates backward-compatible fallbacks for legacy Voice/Body adapters.
|
|
20
|
+
*/
|
|
21
|
+
export declare function emitExperienceEvents(params: ExperienceEmissionParams): Promise<ExperienceEmissionResult>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitExperienceEvents = emitExperienceEvents;
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
/**
|
|
6
|
+
* Creates ExperienceEvents, dispatches them through the ExperienceDispatcher,
|
|
7
|
+
* and coordinates backward-compatible fallbacks for legacy Voice/Body adapters.
|
|
8
|
+
*/
|
|
9
|
+
async function emitExperienceEvents(params) {
|
|
10
|
+
const { companionId, requestContext, stagedPlan, gateEval, speech, language, dispatcher, voice, body, } = params;
|
|
11
|
+
const experienceEvents = (0, index_1.createExperienceEvents)({
|
|
12
|
+
responseId: stagedPlan.responseId,
|
|
13
|
+
companionId,
|
|
14
|
+
correlationId: requestContext.conversation.correlationId,
|
|
15
|
+
channel: requestContext.conversation?.channel,
|
|
16
|
+
audienceId: requestContext.conversation?.audienceId,
|
|
17
|
+
speech,
|
|
18
|
+
language: language || 'ja',
|
|
19
|
+
evidenceIds: gateEval.filteredEvidenceIds,
|
|
20
|
+
citations: gateEval.filteredCitations,
|
|
21
|
+
expression: 'neutral',
|
|
22
|
+
action: 'talk',
|
|
23
|
+
expiresAt: stagedPlan.expiresAt,
|
|
24
|
+
});
|
|
25
|
+
const dispatchResult = await dispatcher.dispatchEvents(experienceEvents);
|
|
26
|
+
let speechId;
|
|
27
|
+
const voiceResult = dispatchResult.eventResults.find((r) => r.event.kind === 'voice');
|
|
28
|
+
if (voiceResult?.result?.metadata?.speechId) {
|
|
29
|
+
speechId = voiceResult.result.metadata.speechId;
|
|
30
|
+
}
|
|
31
|
+
else if (voice &&
|
|
32
|
+
typeof voice.handleEvent !== 'function' &&
|
|
33
|
+
typeof voice.enqueueSpeech === 'function') {
|
|
34
|
+
speechId = voice.enqueueSpeech(speech, language || 'ja', 1);
|
|
35
|
+
}
|
|
36
|
+
if (body && typeof body.handleEvent !== 'function') {
|
|
37
|
+
if (typeof body.setExpression === 'function') {
|
|
38
|
+
body.setExpression('neutral');
|
|
39
|
+
}
|
|
40
|
+
if (typeof body.act === 'function') {
|
|
41
|
+
body.act('talk');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
experienceEvents,
|
|
46
|
+
speechId,
|
|
47
|
+
};
|
|
48
|
+
}
|
package/dist/experience.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Channel } from './context';
|
|
2
1
|
import { ResponseCitation } from './evidence';
|
|
3
2
|
export type ExperienceEventKind = 'voice' | 'caption' | 'avatar' | 'platform_action';
|
|
4
3
|
export type ExperienceEventLifecycle = 'STARTED' | 'PROGRESS' | 'COMPLETED' | 'FAILED';
|
|
@@ -7,8 +6,8 @@ export interface ExperienceEvent {
|
|
|
7
6
|
companionId: string;
|
|
8
7
|
responseId: string;
|
|
9
8
|
correlationId: string;
|
|
10
|
-
channel
|
|
11
|
-
audienceId
|
|
9
|
+
channel?: string;
|
|
10
|
+
audienceId?: string;
|
|
12
11
|
approval: 'APPROVED';
|
|
13
12
|
kind: ExperienceEventKind;
|
|
14
13
|
lifecycle: ExperienceEventLifecycle;
|
|
@@ -20,6 +19,7 @@ export interface ExperienceEvent {
|
|
|
20
19
|
expression?: string;
|
|
21
20
|
createdAt: string;
|
|
22
21
|
expiresAt?: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
23
|
}
|
|
24
24
|
export interface ExperienceAdapterResult {
|
|
25
25
|
accepted: boolean;
|
|
@@ -38,8 +38,8 @@ export interface CreateExperienceEventsOptions {
|
|
|
38
38
|
responseId: string;
|
|
39
39
|
companionId: string;
|
|
40
40
|
correlationId: string;
|
|
41
|
-
channel
|
|
42
|
-
audienceId
|
|
41
|
+
channel?: string;
|
|
42
|
+
audienceId?: string;
|
|
43
43
|
speech: string;
|
|
44
44
|
language?: string;
|
|
45
45
|
evidenceIds?: string[];
|
|
@@ -48,6 +48,7 @@ export interface CreateExperienceEventsOptions {
|
|
|
48
48
|
action?: string;
|
|
49
49
|
expiresAt?: string;
|
|
50
50
|
now?: string | Date;
|
|
51
|
+
[key: string]: unknown;
|
|
51
52
|
}
|
|
52
53
|
export declare function createExperienceEvents(options: CreateExperienceEventsOptions): ExperienceEvent[];
|
|
53
54
|
export declare function validateExperienceEvent(event: unknown): {
|
package/dist/experience.js
CHANGED
|
@@ -62,8 +62,9 @@ function validateExperienceEvent(event) {
|
|
|
62
62
|
return { valid: false, error: 'Missing or invalid responseId' };
|
|
63
63
|
if (!e.correlationId || typeof e.correlationId !== 'string')
|
|
64
64
|
return { valid: false, error: 'Missing or invalid correlationId' };
|
|
65
|
-
if (
|
|
66
|
-
return { valid: false, error: '
|
|
65
|
+
if (e.audienceId !== undefined && typeof e.audienceId !== 'string') {
|
|
66
|
+
return { valid: false, error: 'Invalid audienceId: must be a string' };
|
|
67
|
+
}
|
|
67
68
|
if (e.approval !== 'APPROVED')
|
|
68
69
|
return { valid: false, error: 'Event approval must be APPROVED' };
|
|
69
70
|
if (!['voice', 'caption', 'avatar', 'platform_action'].includes(e.kind)) {
|
package/dist/experience.test.js
CHANGED
|
@@ -50,9 +50,10 @@ describe('T5 Experience Event Contract Suite', () => {
|
|
|
50
50
|
const events = (0, experience_1.createExperienceEvents)(baseEventOptions);
|
|
51
51
|
const missingCompanion = { ...events[0], companionId: '' };
|
|
52
52
|
expect((0, experience_1.validateExperienceEvent)(missingCompanion).valid).toBe(false);
|
|
53
|
-
const
|
|
54
|
-
expect((0, experience_1.validateExperienceEvent)(
|
|
55
|
-
const
|
|
56
|
-
|
|
53
|
+
const missingResponseId = { ...events[0], responseId: '' };
|
|
54
|
+
expect((0, experience_1.validateExperienceEvent)(missingResponseId).valid).toBe(false);
|
|
55
|
+
const withoutAudience = { ...events[0] };
|
|
56
|
+
delete withoutAudience.audienceId;
|
|
57
|
+
expect((0, experience_1.validateExperienceEvent)(withoutAudience).valid).toBe(true);
|
|
57
58
|
});
|
|
58
59
|
});
|
package/dist/gating.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { RequestContext } from './context';
|
|
2
|
+
import { MemoryProposal, BehaviorProposal } from './proposals';
|
|
2
3
|
import { EvidenceRecord, StagedResponsePlan, ResponseGateEvaluation, ResponseCitation } from './evidence';
|
|
3
4
|
export interface StageResponseOptions {
|
|
4
5
|
requestContext: RequestContext;
|
|
5
6
|
candidateSpeech: string;
|
|
6
7
|
candidateLanguage: string;
|
|
7
8
|
internalMonologue?: string;
|
|
8
|
-
memoryProposals?:
|
|
9
|
-
behaviorProposals?:
|
|
9
|
+
memoryProposals?: MemoryProposal[];
|
|
10
|
+
behaviorProposals?: BehaviorProposal[];
|
|
10
11
|
evidenceRecords?: EvidenceRecord[];
|
|
11
12
|
citations?: ResponseCitation[];
|
|
12
13
|
requiresApproval?: boolean;
|
package/dist/gating.js
CHANGED
|
@@ -34,14 +34,13 @@ class ResponseGatingEngine {
|
|
|
34
34
|
}
|
|
35
35
|
const requiresApproval = options.requiresApproval !== undefined
|
|
36
36
|
? options.requiresApproval
|
|
37
|
-
:
|
|
38
|
-
evidenceRecords.some((e) => e.origin === 'ocr' || e.trust === 'untrusted');
|
|
37
|
+
: evidenceRecords.some((e) => e.origin === 'ocr' || e.trust === 'untrusted');
|
|
39
38
|
const staged = {
|
|
40
39
|
responseId: generateId('resp'),
|
|
41
40
|
companionId: requestContext.companionId,
|
|
42
41
|
correlationId: requestContext.conversation.correlationId,
|
|
43
|
-
channel: requestContext.conversation
|
|
44
|
-
audienceId: requestContext.conversation
|
|
42
|
+
channel: requestContext.conversation?.channel,
|
|
43
|
+
audienceId: requestContext.conversation?.audienceId,
|
|
45
44
|
speech: options.candidateSpeech,
|
|
46
45
|
language: options.candidateLanguage,
|
|
47
46
|
evidenceIds,
|
|
@@ -118,7 +117,7 @@ class ResponseGatingEngine {
|
|
|
118
117
|
filteredEvidenceIds: admittedEvidenceIds,
|
|
119
118
|
filteredCitations,
|
|
120
119
|
diagnostics: {
|
|
121
|
-
detail: 'Response plan requires
|
|
120
|
+
detail: 'Response plan requires approval before external emission',
|
|
122
121
|
excludedEvidenceCount: String(excluded.length),
|
|
123
122
|
},
|
|
124
123
|
};
|
|
@@ -147,9 +146,6 @@ class ResponseGatingEngine {
|
|
|
147
146
|
if (plan.correlationId !== options.correlationId) {
|
|
148
147
|
return { success: false, reason: 'APPROVAL_ID_MISMATCH' };
|
|
149
148
|
}
|
|
150
|
-
if (options.audienceId && plan.audienceId !== options.audienceId) {
|
|
151
|
-
return { success: false, reason: 'AUDIENCE_MISMATCH' };
|
|
152
|
-
}
|
|
153
149
|
if (plan.status === 'EXPIRED') {
|
|
154
150
|
return { success: false, reason: 'EVIDENCE_EXPIRED' };
|
|
155
151
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './context';
|
|
2
|
+
export * from './proposals';
|
|
2
3
|
export * from './evidence';
|
|
3
4
|
export * from './gating';
|
|
4
5
|
export * from './experience';
|
|
@@ -7,14 +8,28 @@ export * from './action';
|
|
|
7
8
|
export * from './action-policy';
|
|
8
9
|
export * from './ear-types';
|
|
9
10
|
export * from './capability';
|
|
11
|
+
export * from './sqlite-action-store';
|
|
10
12
|
export * from './teaching';
|
|
11
13
|
export * from './runtime';
|
|
12
14
|
export * from './chat-contract';
|
|
15
|
+
export * from './input-normalizer';
|
|
16
|
+
export * from './intent-classifier';
|
|
17
|
+
export * from './context-retriever';
|
|
18
|
+
export * from './prompt-compiler';
|
|
19
|
+
export * from './cognition-planner';
|
|
20
|
+
export * from './memory-settler';
|
|
21
|
+
export * from './action-executor';
|
|
22
|
+
export * from './experience-emitter';
|
|
23
|
+
export * from './response-envelope';
|
|
24
|
+
export * from './session-history';
|
|
25
|
+
import { EvidenceRecord } from './evidence';
|
|
13
26
|
import { ActionIntent } from './action';
|
|
27
|
+
import { RequestContext } from './context';
|
|
14
28
|
import { EarIngestOptions } from './ear-types';
|
|
29
|
+
import { ClaimType, ClaimAuthority, ClaimStatus, SourceEvent, MemoryProposal, BehaviorProposal } from './proposals';
|
|
15
30
|
export interface OrganConfig {
|
|
16
31
|
provider: string;
|
|
17
|
-
[key: string]:
|
|
32
|
+
[key: string]: unknown;
|
|
18
33
|
}
|
|
19
34
|
export interface CompanionConfig {
|
|
20
35
|
id: string;
|
|
@@ -38,36 +53,6 @@ export interface BrainContext {
|
|
|
38
53
|
recentMessages: Message[];
|
|
39
54
|
recipient?: MemoryScope;
|
|
40
55
|
}
|
|
41
|
-
export type ClaimType = 'semantic' | 'preference' | 'episodic' | 'relationship';
|
|
42
|
-
export type ClaimAuthority = 'user_explicit' | 'user_correction' | 'import' | 'repeated_dialogue' | 'inference' | 'observation';
|
|
43
|
-
export type ClaimStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'SESSION_ONLY' | 'EXPIRED' | 'SUPERSEDED' | 'REVOKED';
|
|
44
|
-
export interface SourceEvent {
|
|
45
|
-
id: string;
|
|
46
|
-
sourceType: string;
|
|
47
|
-
occurredAt: string;
|
|
48
|
-
payload: Record<string, unknown>;
|
|
49
|
-
schemaVersion?: number;
|
|
50
|
-
}
|
|
51
|
-
export interface MemoryProposal {
|
|
52
|
-
subject: string;
|
|
53
|
-
predicate: string;
|
|
54
|
-
value: string;
|
|
55
|
-
content?: string;
|
|
56
|
-
provenance?: string;
|
|
57
|
-
claimType?: ClaimType;
|
|
58
|
-
sensitivity?: string;
|
|
59
|
-
allowedAudiences?: string[];
|
|
60
|
-
sourceEventId?: string;
|
|
61
|
-
}
|
|
62
|
-
export interface BehaviorProposal {
|
|
63
|
-
directive: string;
|
|
64
|
-
priority: number;
|
|
65
|
-
subject?: string;
|
|
66
|
-
predicate?: string;
|
|
67
|
-
value?: string;
|
|
68
|
-
memoryClass?: 'identity' | 'relationship' | 'behavioral' | 'semantic' | 'episodic';
|
|
69
|
-
sourceEventId?: string;
|
|
70
|
-
}
|
|
71
56
|
export interface ResponsePlan {
|
|
72
57
|
speech: string;
|
|
73
58
|
language: string;
|
|
@@ -79,7 +64,7 @@ export interface ResponsePlan {
|
|
|
79
64
|
export interface BrainOrgan {
|
|
80
65
|
generatePlan(context: BrainContext): Promise<ResponsePlan>;
|
|
81
66
|
}
|
|
82
|
-
export type MemoryScope = '
|
|
67
|
+
export type MemoryScope = 'companion' | 'user' | string;
|
|
83
68
|
export interface Claim {
|
|
84
69
|
id: string;
|
|
85
70
|
subject: string;
|
|
@@ -87,7 +72,7 @@ export interface Claim {
|
|
|
87
72
|
value: string;
|
|
88
73
|
status: ClaimStatus;
|
|
89
74
|
evidence?: string[];
|
|
90
|
-
scope
|
|
75
|
+
scope?: MemoryScope;
|
|
91
76
|
companionId: string;
|
|
92
77
|
provenance?: string;
|
|
93
78
|
sourceEventId?: string;
|
|
@@ -95,19 +80,18 @@ export interface Claim {
|
|
|
95
80
|
authority?: ClaimAuthority;
|
|
96
81
|
userConfirmation?: 'explicit' | 'implied' | 'none';
|
|
97
82
|
sensitivity?: string;
|
|
98
|
-
allowedAudiences?: string[];
|
|
99
83
|
confidence?: number;
|
|
100
84
|
assertedAt?: string;
|
|
101
85
|
validFrom?: string;
|
|
102
86
|
validUntil?: string;
|
|
103
87
|
supersedes?: string;
|
|
104
88
|
replaces?: string;
|
|
89
|
+
[key: string]: unknown;
|
|
105
90
|
}
|
|
106
91
|
export interface BehaviorDirective {
|
|
107
92
|
id: string;
|
|
108
93
|
companionId: string;
|
|
109
94
|
directive: string;
|
|
110
|
-
scopeMatcher: string[];
|
|
111
95
|
priority: number;
|
|
112
96
|
status: 'PENDING' | 'ACTIVE' | 'DISABLED' | 'SUPERSEDED' | 'REJECTED' | 'REVOKED' | 'EXPIRED';
|
|
113
97
|
supersedesId?: string;
|
|
@@ -115,22 +99,21 @@ export interface BehaviorDirective {
|
|
|
115
99
|
subject?: string;
|
|
116
100
|
predicate?: string;
|
|
117
101
|
value?: string;
|
|
118
|
-
allowedAudiences?: string[];
|
|
119
102
|
validFrom?: string;
|
|
120
103
|
validUntil?: string;
|
|
104
|
+
[key: string]: unknown;
|
|
121
105
|
}
|
|
122
106
|
export interface MemoryQueryOptions {
|
|
123
|
-
channel?: 'public' | 'direct' | 'private' | 'operator';
|
|
124
|
-
audienceId?: string;
|
|
125
107
|
sensitivity?: string;
|
|
126
108
|
limit?: number;
|
|
127
109
|
minConfidence?: number;
|
|
128
110
|
now?: string | Date;
|
|
111
|
+
[key: string]: unknown;
|
|
129
112
|
}
|
|
130
113
|
export interface MemoryOrgan {
|
|
131
114
|
initialize(companionId: string): Promise<void>;
|
|
132
115
|
proposeClaim(claim: Omit<Claim, 'id' | 'status' | 'companionId'>): Promise<Claim>;
|
|
133
|
-
searchClaims(query: string, scopeOrOptions
|
|
116
|
+
searchClaims(query: string, scopeOrOptions?: MemoryScope | MemoryQueryOptions, limit?: number): Promise<Claim[]>;
|
|
134
117
|
getClaims(limit?: number): Promise<Claim[]>;
|
|
135
118
|
getPendingClaims(limit?: number): Promise<Claim[]>;
|
|
136
119
|
approveClaim(id: string): Promise<void>;
|
|
@@ -146,7 +129,7 @@ export interface MemoryOrgan {
|
|
|
146
129
|
disableDirective(id: string): Promise<void>;
|
|
147
130
|
expireDirective?(id: string): Promise<void>;
|
|
148
131
|
supersedeClaim?(id: string, replacement: Omit<Claim, 'id' | 'status' | 'companionId'>): Promise<Claim>;
|
|
149
|
-
updateClaim?(id: string, updates: Partial<Pick<Claim, 'subject' | 'predicate' | 'value' | 'scope' | 'sensitivity' | 'confidence' | 'validFrom' | 'validUntil'
|
|
132
|
+
updateClaim?(id: string, updates: Partial<Pick<Claim, 'subject' | 'predicate' | 'value' | 'scope' | 'sensitivity' | 'confidence' | 'validFrom' | 'validUntil'>>): Promise<Claim>;
|
|
150
133
|
resetMemory?(): Promise<void>;
|
|
151
134
|
addSourceEvent?(event: SourceEvent): Promise<SourceEvent>;
|
|
152
135
|
getSourceEvent?(id: string): Promise<SourceEvent | undefined>;
|
|
@@ -179,14 +162,12 @@ export interface ActiveSelfProjection {
|
|
|
179
162
|
render(): string;
|
|
180
163
|
}
|
|
181
164
|
export interface BehaviorContext {
|
|
182
|
-
activeRole: string;
|
|
183
165
|
directives: BehaviorDirective[];
|
|
184
166
|
companionId?: string;
|
|
185
|
-
channel?: 'public' | 'direct' | 'private' | 'operator';
|
|
186
|
-
audienceId?: string;
|
|
187
167
|
actorId?: string;
|
|
188
168
|
sessionId?: string;
|
|
189
169
|
now?: string;
|
|
170
|
+
[key: string]: unknown;
|
|
190
171
|
}
|
|
191
172
|
export interface BehaviorOrgan {
|
|
192
173
|
compile(context: BehaviorContext): Promise<string>;
|
|
@@ -197,6 +178,7 @@ export interface KnowledgeItem {
|
|
|
197
178
|
provenance: string;
|
|
198
179
|
revision: string;
|
|
199
180
|
citations: KnowledgeCitation[];
|
|
181
|
+
evidenceRecord?: EvidenceRecord;
|
|
200
182
|
}
|
|
201
183
|
export interface KnowledgeCitation {
|
|
202
184
|
sourceId: string;
|
|
@@ -218,6 +200,7 @@ export interface EarPerception {
|
|
|
218
200
|
export interface EarOrgan {
|
|
219
201
|
listen(source: string, payload: unknown, options?: EarIngestOptions): Promise<EarPerception>;
|
|
220
202
|
transcribeAudio?(audio: Uint8Array): Promise<string>;
|
|
203
|
+
classifyIntent?(text: string, context?: RequestContext): Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
221
204
|
}
|
|
222
205
|
export interface BodyOrgan {
|
|
223
206
|
setExpression(expression: string): void;
|
|
@@ -264,3 +247,4 @@ export interface HealthProbeResult {
|
|
|
264
247
|
details?: Record<string, unknown>;
|
|
265
248
|
}
|
|
266
249
|
export type HealthProbeFn = (context: HealthProbeContext) => Promise<HealthProbeResult> | HealthProbeResult;
|
|
250
|
+
export * from './mouth-types';
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
// Export neutral context types and validator
|
|
18
18
|
__exportStar(require("./context"), exports);
|
|
19
|
+
__exportStar(require("./proposals"), exports);
|
|
19
20
|
__exportStar(require("./evidence"), exports);
|
|
20
21
|
__exportStar(require("./gating"), exports);
|
|
21
22
|
__exportStar(require("./experience"), exports);
|
|
@@ -24,6 +25,19 @@ __exportStar(require("./action"), exports);
|
|
|
24
25
|
__exportStar(require("./action-policy"), exports);
|
|
25
26
|
__exportStar(require("./ear-types"), exports);
|
|
26
27
|
__exportStar(require("./capability"), exports);
|
|
28
|
+
__exportStar(require("./sqlite-action-store"), exports);
|
|
27
29
|
__exportStar(require("./teaching"), exports);
|
|
28
30
|
__exportStar(require("./runtime"), exports);
|
|
29
31
|
__exportStar(require("./chat-contract"), exports);
|
|
32
|
+
__exportStar(require("./input-normalizer"), exports);
|
|
33
|
+
__exportStar(require("./intent-classifier"), exports);
|
|
34
|
+
__exportStar(require("./context-retriever"), exports);
|
|
35
|
+
__exportStar(require("./prompt-compiler"), exports);
|
|
36
|
+
__exportStar(require("./cognition-planner"), exports);
|
|
37
|
+
__exportStar(require("./memory-settler"), exports);
|
|
38
|
+
__exportStar(require("./action-executor"), exports);
|
|
39
|
+
__exportStar(require("./experience-emitter"), exports);
|
|
40
|
+
__exportStar(require("./response-envelope"), exports);
|
|
41
|
+
__exportStar(require("./session-history"), exports);
|
|
42
|
+
// Mouth (Communication & Output Delivery)
|
|
43
|
+
__exportStar(require("./mouth-types"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Message, RequestContext, EarOrgan } from './index';
|
|
2
|
+
export interface NormalizedInput {
|
|
3
|
+
perceivedText: string;
|
|
4
|
+
sanitizedText: string;
|
|
5
|
+
requestContext: RequestContext;
|
|
6
|
+
role: 'OWNER' | 'VIEWER' | 'OPERATOR';
|
|
7
|
+
isContextObject: boolean;
|
|
8
|
+
boundedHistory: Message[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Validates raw user input, synthesizes RequestContext, normalizes history,
|
|
12
|
+
* and routes input through EarOrgan if available.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeUserInput(message: string, roleOrContext: ("OWNER" | "VIEWER" | "OPERATOR" | RequestContext | string) | undefined, history: Message[] | undefined, companionId: string, ear?: EarOrgan): Promise<NormalizedInput>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeUserInput = normalizeUserInput;
|
|
4
|
+
/**
|
|
5
|
+
* Validates raw user input, synthesizes RequestContext, normalizes history,
|
|
6
|
+
* and routes input through EarOrgan if available.
|
|
7
|
+
*/
|
|
8
|
+
async function normalizeUserInput(message, roleOrContext = 'OWNER', history = [], companionId, ear) {
|
|
9
|
+
if (typeof message !== 'string' || !message.trim() || message.length > 4000) {
|
|
10
|
+
throw new Error('message must be a non-empty string of at most 4000 characters');
|
|
11
|
+
}
|
|
12
|
+
if (!Array.isArray(history) ||
|
|
13
|
+
history.length > 20 ||
|
|
14
|
+
history.some((item) => !item || !['user', 'assistant'].includes(item.role) || typeof item.content !== 'string')) {
|
|
15
|
+
throw new Error('history must contain at most 20 user/assistant messages');
|
|
16
|
+
}
|
|
17
|
+
const isContextObject = typeof roleOrContext === 'object' && roleOrContext !== null;
|
|
18
|
+
const role = isContextObject
|
|
19
|
+
? (roleOrContext.actor?.authorizationRole === 'viewer' ? 'VIEWER' : 'OWNER')
|
|
20
|
+
: roleOrContext;
|
|
21
|
+
const requestContext = isContextObject
|
|
22
|
+
? roleOrContext
|
|
23
|
+
: {
|
|
24
|
+
companionId,
|
|
25
|
+
actor: {
|
|
26
|
+
actorId: role === 'VIEWER' ? 'anonymous-session' : 'owner-user',
|
|
27
|
+
sessionId: `sess-${companionId}`,
|
|
28
|
+
authorizationRole: role === 'VIEWER' ? 'viewer' : 'administrator',
|
|
29
|
+
capabilities: role === 'VIEWER' ? ['chat'] : ['chat', 'memory:approve', 'action:execute'],
|
|
30
|
+
authenticated: role !== 'VIEWER',
|
|
31
|
+
},
|
|
32
|
+
conversation: {
|
|
33
|
+
channel: 'direct',
|
|
34
|
+
correlationId: `corr-${Date.now()}`,
|
|
35
|
+
},
|
|
36
|
+
source: 'local',
|
|
37
|
+
};
|
|
38
|
+
// Universal Perception: Route user input through EarOrgan if available
|
|
39
|
+
let perceivedText = message;
|
|
40
|
+
if (ear && typeof ear.listen === 'function') {
|
|
41
|
+
const perception = await ear.listen('text_chat', message, {
|
|
42
|
+
context: requestContext,
|
|
43
|
+
});
|
|
44
|
+
perceivedText = perception.text || message;
|
|
45
|
+
}
|
|
46
|
+
const boundedHistory = history.map((item) => ({
|
|
47
|
+
role: item.role,
|
|
48
|
+
content: item.content.slice(0, 2000).replace(/\0/g, ''),
|
|
49
|
+
}));
|
|
50
|
+
return {
|
|
51
|
+
perceivedText,
|
|
52
|
+
sanitizedText: message,
|
|
53
|
+
requestContext,
|
|
54
|
+
role,
|
|
55
|
+
isContextObject,
|
|
56
|
+
boundedHistory,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const input_normalizer_1 = require("./input-normalizer");
|
|
4
|
+
describe('InputNormalizer', () => {
|
|
5
|
+
test('rejects empty or oversized messages', async () => {
|
|
6
|
+
await expect((0, input_normalizer_1.normalizeUserInput)('', 'OWNER', [], 'comp-1')).rejects.toThrow('message must be a non-empty string of at most 4000 characters');
|
|
7
|
+
await expect((0, input_normalizer_1.normalizeUserInput)(' ', 'OWNER', [], 'comp-1')).rejects.toThrow('message must be a non-empty string of at most 4000 characters');
|
|
8
|
+
const oversized = 'a'.repeat(4001);
|
|
9
|
+
await expect((0, input_normalizer_1.normalizeUserInput)(oversized, 'OWNER', [], 'comp-1')).rejects.toThrow('message must be a non-empty string of at most 4000 characters');
|
|
10
|
+
});
|
|
11
|
+
test('rejects oversized history or invalid message roles', async () => {
|
|
12
|
+
const invalidHistory = Array(21).fill({ role: 'user', content: 'hi' });
|
|
13
|
+
await expect((0, input_normalizer_1.normalizeUserInput)('hi', 'OWNER', invalidHistory, 'comp-1')).rejects.toThrow('history must contain at most 20 user/assistant messages');
|
|
14
|
+
const malformedRole = [{ role: 'bad_role', content: 'test' }];
|
|
15
|
+
await expect((0, input_normalizer_1.normalizeUserInput)('hi', 'OWNER', malformedRole, 'comp-1')).rejects.toThrow('history must contain at most 20 user/assistant messages');
|
|
16
|
+
});
|
|
17
|
+
test('normalizes role string into full RequestContext and strips null bytes from history', async () => {
|
|
18
|
+
const historyWithNulls = [{ role: 'user', content: 'hello\0world' }];
|
|
19
|
+
const result = await (0, input_normalizer_1.normalizeUserInput)('hello', 'OWNER', historyWithNulls, 'comp-1');
|
|
20
|
+
expect(result.role).toBe('OWNER');
|
|
21
|
+
expect(result.requestContext.companionId).toBe('comp-1');
|
|
22
|
+
expect(result.requestContext.actor.authorizationRole).toBe('administrator');
|
|
23
|
+
expect(result.requestContext.actor.authenticated).toBe(true);
|
|
24
|
+
expect(result.boundedHistory[0].content).toBe('helloworld');
|
|
25
|
+
});
|
|
26
|
+
test('routes input through EarOrgan when present', async () => {
|
|
27
|
+
const mockEar = {
|
|
28
|
+
listen: jest.fn().mockResolvedValue({
|
|
29
|
+
id: 'perc-1',
|
|
30
|
+
source: 'text_chat',
|
|
31
|
+
text: 'transcribed text',
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
const result = await (0, input_normalizer_1.normalizeUserInput)('raw text', 'VIEWER', [], 'comp-1', mockEar);
|
|
36
|
+
expect(mockEar.listen).toHaveBeenCalledWith('text_chat', 'raw text', expect.anything());
|
|
37
|
+
expect(result.perceivedText).toBe('transcribed text');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RequestContext } from './index';
|
|
2
|
+
import { extractDeterministicTeaching } from './teaching';
|
|
3
|
+
export interface IntentClassification {
|
|
4
|
+
normalizedMessage: string;
|
|
5
|
+
explicitTeaching: ReturnType<typeof extractDeterministicTeaching>;
|
|
6
|
+
isTeachingLike: boolean;
|
|
7
|
+
isSelfIdentityRequest: boolean;
|
|
8
|
+
isGreeting: boolean;
|
|
9
|
+
shouldQueryKnowledge: boolean;
|
|
10
|
+
confidence?: number;
|
|
11
|
+
classifierOrigin?: 'heuristic' | 'cognitive' | 'ear';
|
|
12
|
+
}
|
|
13
|
+
export type CognitiveIntentClassifier = (text: string, context: RequestContext) => Promise<Partial<IntentClassification>> | Partial<IntentClassification>;
|
|
14
|
+
/**
|
|
15
|
+
* Evaluates domain heuristics and intent classification for user messages.
|
|
16
|
+
* Determines if deterministic teaching is present and whether external knowledge
|
|
17
|
+
* retrieval is appropriate.
|
|
18
|
+
*/
|
|
19
|
+
export declare function classifyInputIntent(text: string, context: RequestContext, overrides?: Partial<IntentClassification>): IntentClassification;
|
|
20
|
+
/**
|
|
21
|
+
* Asynchronously classifies intent, allowing an EarOrgan or cognitive model
|
|
22
|
+
* to provide semantic classification before falling back to heuristics.
|
|
23
|
+
*/
|
|
24
|
+
export declare function classifyInputIntentAsync(text: string, context: RequestContext, classifier?: CognitiveIntentClassifier): Promise<IntentClassification>;
|