@siduri-x/core 1.0.4 → 1.0.5
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/package.json +1 -1
- package/dist/action-policy.d.ts +0 -45
- package/dist/action-policy.js +0 -224
- package/dist/action-policy.test.d.ts +0 -1
- package/dist/action-policy.test.js +0 -194
- package/dist/action.d.ts +0 -72
- package/dist/action.js +0 -2
- package/dist/adversarial.test.d.ts +0 -1
- package/dist/adversarial.test.js +0 -493
- package/dist/architecture-boundary.test.d.ts +0 -1
- package/dist/architecture-boundary.test.js +0 -116
- package/dist/capability.d.ts +0 -57
- package/dist/capability.js +0 -130
- package/dist/capability.test.d.ts +0 -1
- package/dist/capability.test.js +0 -269
- package/dist/chat-contract.d.ts +0 -77
- package/dist/chat-contract.js +0 -65
- package/dist/context.d.ts +0 -47
- package/dist/context.js +0 -92
- package/dist/context.test.d.ts +0 -1
- package/dist/context.test.js +0 -109
- package/dist/dispatcher.d.ts +0 -14
- package/dist/dispatcher.js +0 -40
- package/dist/dispatcher.test.d.ts +0 -1
- package/dist/dispatcher.test.js +0 -60
- package/dist/ear-types.d.ts +0 -33
- package/dist/ear-types.js +0 -2
- package/dist/evidence.d.ts +0 -72
- package/dist/evidence.js +0 -45
- package/dist/evidence.test.d.ts +0 -1
- package/dist/evidence.test.js +0 -101
- package/dist/experience.d.ts +0 -56
- package/dist/experience.js +0 -78
- package/dist/experience.test.d.ts +0 -1
- package/dist/experience.test.js +0 -58
- package/dist/gating.d.ts +0 -45
- package/dist/gating.js +0 -189
- package/dist/gating.test.d.ts +0 -1
- package/dist/gating.test.js +0 -190
- package/dist/index.d.ts +0 -266
- package/dist/index.js +0 -29
- package/dist/runtime.d.ts +0 -50
- package/dist/runtime.js +0 -411
- package/dist/teaching.d.ts +0 -15
- package/dist/teaching.js +0 -159
package/dist/context.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isValidAuthorizationRole = isValidAuthorizationRole;
|
|
4
|
-
exports.isValidChannel = isValidChannel;
|
|
5
|
-
exports.isValidSubjectKind = isValidSubjectKind;
|
|
6
|
-
exports.validateRequestContext = validateRequestContext;
|
|
7
|
-
function isValidAuthorizationRole(role) {
|
|
8
|
-
return role === 'viewer' || role === 'operator' || role === 'administrator';
|
|
9
|
-
}
|
|
10
|
-
function isValidChannel(channel) {
|
|
11
|
-
return channel === 'public' || channel === 'direct' || channel === 'private' || channel === 'operator';
|
|
12
|
-
}
|
|
13
|
-
function isValidSubjectKind(kind) {
|
|
14
|
-
return kind === 'actor' || kind === 'companion' || kind === 'configured';
|
|
15
|
-
}
|
|
16
|
-
function validateRequestContext(context) {
|
|
17
|
-
if (!context || typeof context !== 'object') {
|
|
18
|
-
return {
|
|
19
|
-
accepted: false,
|
|
20
|
-
error: {
|
|
21
|
-
code: 'MISSING_CONTEXT',
|
|
22
|
-
fields: ['context'],
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const ctx = context;
|
|
27
|
-
const missingFields = [];
|
|
28
|
-
if (!ctx.companionId || typeof ctx.companionId !== 'string' || ctx.companionId.trim() === '') {
|
|
29
|
-
missingFields.push('companionId');
|
|
30
|
-
}
|
|
31
|
-
if (!ctx.actor || typeof ctx.actor !== 'object') {
|
|
32
|
-
missingFields.push('actor');
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
if (!ctx.actor.actorId || typeof ctx.actor.actorId !== 'string' || ctx.actor.actorId.trim() === '') {
|
|
36
|
-
missingFields.push('actor.actorId');
|
|
37
|
-
}
|
|
38
|
-
if (!ctx.actor.sessionId || typeof ctx.actor.sessionId !== 'string' || ctx.actor.sessionId.trim() === '') {
|
|
39
|
-
missingFields.push('actor.sessionId');
|
|
40
|
-
}
|
|
41
|
-
if (!isValidAuthorizationRole(ctx.actor.authorizationRole)) {
|
|
42
|
-
missingFields.push('actor.authorizationRole');
|
|
43
|
-
}
|
|
44
|
-
if (!Array.isArray(ctx.actor.capabilities)) {
|
|
45
|
-
missingFields.push('actor.capabilities');
|
|
46
|
-
}
|
|
47
|
-
if (typeof ctx.actor.authenticated !== 'boolean') {
|
|
48
|
-
missingFields.push('actor.authenticated');
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (!ctx.conversation || typeof ctx.conversation !== 'object') {
|
|
52
|
-
missingFields.push('conversation');
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
if (!isValidChannel(ctx.conversation.channel)) {
|
|
56
|
-
missingFields.push('conversation.channel');
|
|
57
|
-
}
|
|
58
|
-
if (!ctx.conversation.audienceId || typeof ctx.conversation.audienceId !== 'string' || ctx.conversation.audienceId.trim() === '') {
|
|
59
|
-
missingFields.push('conversation.audienceId');
|
|
60
|
-
}
|
|
61
|
-
if (!ctx.conversation.correlationId || typeof ctx.conversation.correlationId !== 'string' || ctx.conversation.correlationId.trim() === '') {
|
|
62
|
-
missingFields.push('conversation.correlationId');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (ctx.subject !== undefined) {
|
|
66
|
-
if (!ctx.subject || typeof ctx.subject !== 'object') {
|
|
67
|
-
missingFields.push('subject');
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
if (!ctx.subject.subjectId || typeof ctx.subject.subjectId !== 'string' || ctx.subject.subjectId.trim() === '') {
|
|
71
|
-
missingFields.push('subject.subjectId');
|
|
72
|
-
}
|
|
73
|
-
if (!isValidSubjectKind(ctx.subject.kind)) {
|
|
74
|
-
missingFields.push('subject.kind');
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (missingFields.length > 0) {
|
|
79
|
-
return {
|
|
80
|
-
accepted: false,
|
|
81
|
-
error: {
|
|
82
|
-
code: 'MISSING_CONTEXT',
|
|
83
|
-
fields: missingFields,
|
|
84
|
-
correlationId: ctx.conversation?.correlationId,
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
accepted: true,
|
|
90
|
-
context: ctx,
|
|
91
|
-
};
|
|
92
|
-
}
|
package/dist/context.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/context.test.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const context_1 = require("./context");
|
|
4
|
-
describe('Core Context Contract (P1)', () => {
|
|
5
|
-
const validContext = {
|
|
6
|
-
companionId: 'companion-a',
|
|
7
|
-
actor: {
|
|
8
|
-
actorId: 'actor-a',
|
|
9
|
-
sessionId: 'session-a',
|
|
10
|
-
authorizationRole: 'viewer',
|
|
11
|
-
capabilities: ['chat:public'],
|
|
12
|
-
authenticated: false,
|
|
13
|
-
},
|
|
14
|
-
conversation: {
|
|
15
|
-
channel: 'public',
|
|
16
|
-
audienceId: 'audience-public',
|
|
17
|
-
correlationId: 'corr-a',
|
|
18
|
-
},
|
|
19
|
-
subject: {
|
|
20
|
-
subjectId: 'actor:actor-a',
|
|
21
|
-
kind: 'actor',
|
|
22
|
-
ownerActorId: 'actor-a',
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
test('validates a correct neutral RequestContext', () => {
|
|
26
|
-
const result = (0, context_1.validateRequestContext)(validContext);
|
|
27
|
-
expect(result.accepted).toBe(true);
|
|
28
|
-
expect(result.context).toEqual(validContext);
|
|
29
|
-
expect(result.error).toBeUndefined();
|
|
30
|
-
});
|
|
31
|
-
test('validates a correct RequestContext without subject', () => {
|
|
32
|
-
const { subject, ...contextWithoutSubject } = validContext;
|
|
33
|
-
const result = (0, context_1.validateRequestContext)(contextWithoutSubject);
|
|
34
|
-
expect(result.accepted).toBe(true);
|
|
35
|
-
expect(result.context?.subject).toBeUndefined();
|
|
36
|
-
});
|
|
37
|
-
test('rejects missing root context or non-object', () => {
|
|
38
|
-
const result = (0, context_1.validateRequestContext)(null);
|
|
39
|
-
expect(result.accepted).toBe(false);
|
|
40
|
-
expect(result.error?.code).toBe('MISSING_CONTEXT');
|
|
41
|
-
expect(result.error?.fields).toContain('context');
|
|
42
|
-
});
|
|
43
|
-
test('rejects missing companionId, actor, or conversation', () => {
|
|
44
|
-
const result = (0, context_1.validateRequestContext)({});
|
|
45
|
-
expect(result.accepted).toBe(false);
|
|
46
|
-
expect(result.error?.code).toBe('MISSING_CONTEXT');
|
|
47
|
-
expect(result.error?.fields).toEqual(expect.arrayContaining(['companionId', 'actor', 'conversation']));
|
|
48
|
-
});
|
|
49
|
-
test('validates authorization role constraints', () => {
|
|
50
|
-
expect((0, context_1.isValidAuthorizationRole)('viewer')).toBe(true);
|
|
51
|
-
expect((0, context_1.isValidAuthorizationRole)('operator')).toBe(true);
|
|
52
|
-
expect((0, context_1.isValidAuthorizationRole)('administrator')).toBe(true);
|
|
53
|
-
expect((0, context_1.isValidAuthorizationRole)('owner')).toBe(false);
|
|
54
|
-
expect((0, context_1.isValidAuthorizationRole)('user')).toBe(false);
|
|
55
|
-
expect((0, context_1.isValidAuthorizationRole)('MASTER')).toBe(false);
|
|
56
|
-
const invalidRoleCtx = {
|
|
57
|
-
...validContext,
|
|
58
|
-
actor: { ...validContext.actor, authorizationRole: 'invalid_role' },
|
|
59
|
-
};
|
|
60
|
-
const result = (0, context_1.validateRequestContext)(invalidRoleCtx);
|
|
61
|
-
expect(result.accepted).toBe(false);
|
|
62
|
-
expect(result.error?.fields).toContain('actor.authorizationRole');
|
|
63
|
-
});
|
|
64
|
-
test('validates channel constraints', () => {
|
|
65
|
-
expect((0, context_1.isValidChannel)('public')).toBe(true);
|
|
66
|
-
expect((0, context_1.isValidChannel)('direct')).toBe(true);
|
|
67
|
-
expect((0, context_1.isValidChannel)('private')).toBe(true);
|
|
68
|
-
expect((0, context_1.isValidChannel)('operator')).toBe(true);
|
|
69
|
-
expect((0, context_1.isValidChannel)('chat')).toBe(false);
|
|
70
|
-
expect((0, context_1.isValidChannel)('MASTER_PRIVATE')).toBe(false);
|
|
71
|
-
const invalidChannelCtx = {
|
|
72
|
-
...validContext,
|
|
73
|
-
conversation: { ...validContext.conversation, channel: 'invalid_channel' },
|
|
74
|
-
};
|
|
75
|
-
const result = (0, context_1.validateRequestContext)(invalidChannelCtx);
|
|
76
|
-
expect(result.accepted).toBe(false);
|
|
77
|
-
expect(result.error?.fields).toContain('conversation.channel');
|
|
78
|
-
});
|
|
79
|
-
test('validates subject kinds and constraints', () => {
|
|
80
|
-
expect((0, context_1.isValidSubjectKind)('actor')).toBe(true);
|
|
81
|
-
expect((0, context_1.isValidSubjectKind)('companion')).toBe(true);
|
|
82
|
-
expect((0, context_1.isValidSubjectKind)('configured')).toBe(true);
|
|
83
|
-
expect((0, context_1.isValidSubjectKind)('user')).toBe(false);
|
|
84
|
-
const invalidSubjectCtx = {
|
|
85
|
-
...validContext,
|
|
86
|
-
subject: { subjectId: 'subject-1', kind: 'invalid_kind' },
|
|
87
|
-
};
|
|
88
|
-
const result = (0, context_1.validateRequestContext)(invalidSubjectCtx);
|
|
89
|
-
expect(result.accepted).toBe(false);
|
|
90
|
-
expect(result.error?.fields).toContain('subject.kind');
|
|
91
|
-
});
|
|
92
|
-
test('rejects missing correlationId and preserves correlationId in error if present', () => {
|
|
93
|
-
const missingCorr = {
|
|
94
|
-
...validContext,
|
|
95
|
-
conversation: { ...validContext.conversation, correlationId: '' },
|
|
96
|
-
};
|
|
97
|
-
const result = (0, context_1.validateRequestContext)(missingCorr);
|
|
98
|
-
expect(result.accepted).toBe(false);
|
|
99
|
-
expect(result.error?.fields).toContain('conversation.correlationId');
|
|
100
|
-
const missingActorId = {
|
|
101
|
-
...validContext,
|
|
102
|
-
actor: { ...validContext.actor, actorId: '' },
|
|
103
|
-
};
|
|
104
|
-
const result2 = (0, context_1.validateRequestContext)(missingActorId);
|
|
105
|
-
expect(result2.accepted).toBe(false);
|
|
106
|
-
expect(result2.error?.fields).toContain('actor.actorId');
|
|
107
|
-
expect(result2.error?.correlationId).toBe('corr-a');
|
|
108
|
-
});
|
|
109
|
-
});
|
package/dist/dispatcher.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ExperienceAdapter, ExperienceEvent, ExperienceAdapterResult } from './experience';
|
|
2
|
-
export interface DispatchSummary {
|
|
3
|
-
dispatched: boolean;
|
|
4
|
-
eventResults: {
|
|
5
|
-
event: ExperienceEvent;
|
|
6
|
-
result: ExperienceAdapterResult;
|
|
7
|
-
}[];
|
|
8
|
-
}
|
|
9
|
-
export declare class ExperienceDispatcher {
|
|
10
|
-
private readonly adapters;
|
|
11
|
-
private readonly dispatchedEventIds;
|
|
12
|
-
registerAdapter(adapter: ExperienceAdapter): void;
|
|
13
|
-
dispatchEvents(events: ExperienceEvent[]): Promise<DispatchSummary>;
|
|
14
|
-
}
|
package/dist/dispatcher.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExperienceDispatcher = void 0;
|
|
4
|
-
class ExperienceDispatcher {
|
|
5
|
-
adapters = [];
|
|
6
|
-
dispatchedEventIds = new Set();
|
|
7
|
-
registerAdapter(adapter) {
|
|
8
|
-
this.adapters.push(adapter);
|
|
9
|
-
}
|
|
10
|
-
async dispatchEvents(events) {
|
|
11
|
-
const eventResults = [];
|
|
12
|
-
for (const event of events) {
|
|
13
|
-
// Replay / duplicate dispatch protection: each eventId is dispatched only once
|
|
14
|
-
if (this.dispatchedEventIds.has(event.eventId)) {
|
|
15
|
-
eventResults.push({
|
|
16
|
-
event,
|
|
17
|
-
result: {
|
|
18
|
-
accepted: false,
|
|
19
|
-
eventId: event.eventId,
|
|
20
|
-
lifecycle: 'FAILED',
|
|
21
|
-
error: 'Duplicate event ID already dispatched',
|
|
22
|
-
reason: 'DUPLICATE_EVENT_DISPATCH',
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
this.dispatchedEventIds.add(event.eventId);
|
|
28
|
-
const matchingAdapters = this.adapters.filter((a) => a.kind === event.kind);
|
|
29
|
-
for (const adapter of matchingAdapters) {
|
|
30
|
-
const result = await adapter.handleEvent(event);
|
|
31
|
-
eventResults.push({ event, result });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
dispatched: eventResults.some((r) => r.result.accepted),
|
|
36
|
-
eventResults,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
exports.ExperienceDispatcher = ExperienceDispatcher;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/dispatcher.test.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const dispatcher_1 = require("./dispatcher");
|
|
4
|
-
const experience_1 = require("./experience");
|
|
5
|
-
describe('T5 ExperienceDispatcher Contract Suite', () => {
|
|
6
|
-
let dispatcher;
|
|
7
|
-
let mockVoiceAdapter;
|
|
8
|
-
let mockAvatarAdapter;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
dispatcher = new dispatcher_1.ExperienceDispatcher();
|
|
11
|
-
mockVoiceAdapter = {
|
|
12
|
-
kind: 'voice',
|
|
13
|
-
handleEvent: jest.fn().mockImplementation(async (event) => ({
|
|
14
|
-
accepted: true,
|
|
15
|
-
eventId: event.eventId,
|
|
16
|
-
lifecycle: 'STARTED',
|
|
17
|
-
})),
|
|
18
|
-
};
|
|
19
|
-
mockAvatarAdapter = {
|
|
20
|
-
kind: 'avatar',
|
|
21
|
-
handleEvent: jest.fn().mockImplementation(async (event) => ({
|
|
22
|
-
accepted: true,
|
|
23
|
-
eventId: event.eventId,
|
|
24
|
-
lifecycle: 'STARTED',
|
|
25
|
-
})),
|
|
26
|
-
};
|
|
27
|
-
dispatcher.registerAdapter(mockVoiceAdapter);
|
|
28
|
-
dispatcher.registerAdapter(mockAvatarAdapter);
|
|
29
|
-
});
|
|
30
|
-
test('dispatches experience events to matching adapters', async () => {
|
|
31
|
-
const events = (0, experience_1.createExperienceEvents)({
|
|
32
|
-
responseId: 'resp-1',
|
|
33
|
-
companionId: 'companion-a',
|
|
34
|
-
correlationId: 'corr-1',
|
|
35
|
-
channel: 'public',
|
|
36
|
-
audienceId: 'audience-public',
|
|
37
|
-
speech: 'Hello dispatch',
|
|
38
|
-
language: 'en',
|
|
39
|
-
});
|
|
40
|
-
const summary = await dispatcher.dispatchEvents(events);
|
|
41
|
-
expect(summary.dispatched).toBe(true);
|
|
42
|
-
expect(summary.eventResults.length).toBe(2);
|
|
43
|
-
expect(mockVoiceAdapter.handleEvent).toHaveBeenCalledTimes(1);
|
|
44
|
-
expect(mockAvatarAdapter.handleEvent).toHaveBeenCalledTimes(1);
|
|
45
|
-
});
|
|
46
|
-
test('does not dispatch when no matching adapters registered', async () => {
|
|
47
|
-
const emptyDispatcher = new dispatcher_1.ExperienceDispatcher();
|
|
48
|
-
const events = (0, experience_1.createExperienceEvents)({
|
|
49
|
-
responseId: 'resp-1',
|
|
50
|
-
companionId: 'companion-a',
|
|
51
|
-
correlationId: 'corr-1',
|
|
52
|
-
channel: 'public',
|
|
53
|
-
audienceId: 'audience-public',
|
|
54
|
-
speech: 'Hello empty',
|
|
55
|
-
});
|
|
56
|
-
const summary = await emptyDispatcher.dispatchEvents(events);
|
|
57
|
-
expect(summary.dispatched).toBe(false);
|
|
58
|
-
expect(summary.eventResults.length).toBe(0);
|
|
59
|
-
});
|
|
60
|
-
});
|
package/dist/ear-types.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { RequestContext } from './context';
|
|
2
|
-
import { EarPerception } from './index';
|
|
3
|
-
export interface EarLimitsConfig {
|
|
4
|
-
maxTextLength?: number;
|
|
5
|
-
maxAudioBytes?: number;
|
|
6
|
-
allowedAudioMimeTypes?: string[];
|
|
7
|
-
maxDurationSeconds?: number;
|
|
8
|
-
transcriptionTimeoutMs?: number;
|
|
9
|
-
}
|
|
10
|
-
export interface EarPerceptionMetadata extends Record<string, unknown> {
|
|
11
|
-
source?: string;
|
|
12
|
-
channel?: string;
|
|
13
|
-
modality?: 'text' | 'audio' | 'object' | 'system';
|
|
14
|
-
confidence?: number;
|
|
15
|
-
provenance?: string;
|
|
16
|
-
actorId?: string;
|
|
17
|
-
sessionId?: string;
|
|
18
|
-
correlationId?: string;
|
|
19
|
-
byteSize?: number;
|
|
20
|
-
durationSeconds?: number;
|
|
21
|
-
mimeType?: string;
|
|
22
|
-
}
|
|
23
|
-
export interface HardenedEarPerception extends EarPerception {
|
|
24
|
-
modality: 'text' | 'audio' | 'object' | 'system';
|
|
25
|
-
metadata?: EarPerceptionMetadata;
|
|
26
|
-
rawConfidence?: number;
|
|
27
|
-
}
|
|
28
|
-
export interface EarIngestOptions {
|
|
29
|
-
source?: string;
|
|
30
|
-
context?: RequestContext;
|
|
31
|
-
mimeType?: string;
|
|
32
|
-
durationSeconds?: number;
|
|
33
|
-
}
|
package/dist/ear-types.js
DELETED
package/dist/evidence.d.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
export type EvidenceOrigin = 'knowledge' | 'observation' | 'ocr' | 'platform' | 'conversation';
|
|
2
|
-
export type EvidenceTrust = 'configured' | 'provider' | 'untrusted';
|
|
3
|
-
export type EvidenceSensitivity = 'public' | 'private' | 'restricted';
|
|
4
|
-
export interface EvidenceRecord {
|
|
5
|
-
evidenceId: string;
|
|
6
|
-
sourceId: string;
|
|
7
|
-
documentId?: string;
|
|
8
|
-
chunkId?: string;
|
|
9
|
-
locator?: string;
|
|
10
|
-
revision?: string;
|
|
11
|
-
origin: EvidenceOrigin;
|
|
12
|
-
confidence?: number;
|
|
13
|
-
uncertainty?: string;
|
|
14
|
-
createdAt: string;
|
|
15
|
-
expiresAt?: string;
|
|
16
|
-
trust: EvidenceTrust;
|
|
17
|
-
sensitivity: EvidenceSensitivity;
|
|
18
|
-
allowedAudiences: string[];
|
|
19
|
-
companionId: string;
|
|
20
|
-
correlationId: string;
|
|
21
|
-
}
|
|
22
|
-
export type ResponseApprovalStatus = 'STAGED' | 'APPROVED' | 'REJECTED' | 'EXPIRED' | 'EMITTED';
|
|
23
|
-
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';
|
|
24
|
-
export interface ResponseCitation {
|
|
25
|
-
sourceId: string;
|
|
26
|
-
documentId?: string;
|
|
27
|
-
chunkId?: string;
|
|
28
|
-
locator?: string;
|
|
29
|
-
revision?: string;
|
|
30
|
-
}
|
|
31
|
-
export interface StagedResponsePlan {
|
|
32
|
-
responseId: string;
|
|
33
|
-
companionId: string;
|
|
34
|
-
correlationId: string;
|
|
35
|
-
channel: 'public' | 'direct' | 'private' | 'operator';
|
|
36
|
-
audienceId: string;
|
|
37
|
-
speech: string;
|
|
38
|
-
language: string;
|
|
39
|
-
evidenceIds: string[];
|
|
40
|
-
citations: ResponseCitation[];
|
|
41
|
-
confidenceSummary: number;
|
|
42
|
-
uncertaintySummary?: string;
|
|
43
|
-
requiresApproval: boolean;
|
|
44
|
-
status: ResponseApprovalStatus;
|
|
45
|
-
createdAt: string;
|
|
46
|
-
expiresAt?: string;
|
|
47
|
-
memoryProposals?: any[];
|
|
48
|
-
behaviorProposals?: any[];
|
|
49
|
-
internalMonologue?: string;
|
|
50
|
-
}
|
|
51
|
-
export interface ResponseGateEvaluation {
|
|
52
|
-
admissible: boolean;
|
|
53
|
-
disposition: ResponseApprovalStatus;
|
|
54
|
-
reasonCode: ResponseGateReasonCode;
|
|
55
|
-
stagedPlan: StagedResponsePlan;
|
|
56
|
-
filteredEvidenceIds: string[];
|
|
57
|
-
filteredCitations: ResponseCitation[];
|
|
58
|
-
diagnostics?: Record<string, string>;
|
|
59
|
-
}
|
|
60
|
-
export interface EvidenceFilterOptions {
|
|
61
|
-
companionId: string;
|
|
62
|
-
channel: 'public' | 'direct' | 'private' | 'operator';
|
|
63
|
-
audienceId: string;
|
|
64
|
-
now?: string | Date;
|
|
65
|
-
}
|
|
66
|
-
export declare function filterEvidenceRecords(records: EvidenceRecord[], options: EvidenceFilterOptions): {
|
|
67
|
-
admitted: EvidenceRecord[];
|
|
68
|
-
excluded: {
|
|
69
|
-
record: EvidenceRecord;
|
|
70
|
-
reason: string;
|
|
71
|
-
}[];
|
|
72
|
-
};
|
package/dist/evidence.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.filterEvidenceRecords = filterEvidenceRecords;
|
|
4
|
-
function filterEvidenceRecords(records, options) {
|
|
5
|
-
const admitted = [];
|
|
6
|
-
const excluded = [];
|
|
7
|
-
const nowTime = options.now ? new Date(options.now).getTime() : Date.now();
|
|
8
|
-
for (const record of records) {
|
|
9
|
-
// 1. Companion isolation
|
|
10
|
-
if (record.companionId !== options.companionId) {
|
|
11
|
-
excluded.push({ record, reason: 'companion_isolation_mismatch' });
|
|
12
|
-
continue;
|
|
13
|
-
}
|
|
14
|
-
// 2. Expiry
|
|
15
|
-
if (record.expiresAt) {
|
|
16
|
-
const expTime = new Date(record.expiresAt).getTime();
|
|
17
|
-
if (expTime <= nowTime) {
|
|
18
|
-
excluded.push({ record, reason: 'evidence_expired' });
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
// 3. Audience intersection
|
|
23
|
-
if (record.allowedAudiences &&
|
|
24
|
-
record.allowedAudiences.length > 0 &&
|
|
25
|
-
!record.allowedAudiences.includes(options.audienceId)) {
|
|
26
|
-
excluded.push({ record, reason: 'audience_not_allowed' });
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
// 4. Sensitivity policy based on channel
|
|
30
|
-
if (options.channel === 'public') {
|
|
31
|
-
if (record.sensitivity !== 'public') {
|
|
32
|
-
excluded.push({ record, reason: 'sensitivity_private_in_public_channel' });
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
else if (options.channel === 'direct') {
|
|
37
|
-
if (record.sensitivity === 'restricted') {
|
|
38
|
-
excluded.push({ record, reason: 'sensitivity_restricted_in_direct_channel' });
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
admitted.push(record);
|
|
43
|
-
}
|
|
44
|
-
return { admitted, excluded };
|
|
45
|
-
}
|
package/dist/evidence.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/evidence.test.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const evidence_1 = require("./evidence");
|
|
4
|
-
describe('T4 Evidence & Disclosure Core Contract', () => {
|
|
5
|
-
const baseRecord = {
|
|
6
|
-
evidenceId: 'ev-1',
|
|
7
|
-
sourceId: 'src-1',
|
|
8
|
-
origin: 'knowledge',
|
|
9
|
-
trust: 'configured',
|
|
10
|
-
sensitivity: 'public',
|
|
11
|
-
allowedAudiences: ['audience-public'],
|
|
12
|
-
companionId: 'companion-a',
|
|
13
|
-
correlationId: 'corr-1',
|
|
14
|
-
createdAt: new Date(Date.now() - 5000).toISOString(),
|
|
15
|
-
};
|
|
16
|
-
test('companion isolation excludes foreign companion evidence', () => {
|
|
17
|
-
const records = [
|
|
18
|
-
{ ...baseRecord, evidenceId: 'ev-mine', companionId: 'companion-a' },
|
|
19
|
-
{ ...baseRecord, evidenceId: 'ev-foreign', companionId: 'companion-b' },
|
|
20
|
-
];
|
|
21
|
-
const options = {
|
|
22
|
-
companionId: 'companion-a',
|
|
23
|
-
channel: 'public',
|
|
24
|
-
audienceId: 'audience-public',
|
|
25
|
-
};
|
|
26
|
-
const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
|
|
27
|
-
expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-mine']);
|
|
28
|
-
expect(excluded).toEqual([
|
|
29
|
-
expect.objectContaining({
|
|
30
|
-
record: expect.objectContaining({ evidenceId: 'ev-foreign' }),
|
|
31
|
-
reason: 'companion_isolation_mismatch',
|
|
32
|
-
}),
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
35
|
-
test('expired evidence is excluded', () => {
|
|
36
|
-
const records = [
|
|
37
|
-
{ ...baseRecord, evidenceId: 'ev-valid', expiresAt: new Date(Date.now() + 60000).toISOString() },
|
|
38
|
-
{ ...baseRecord, evidenceId: 'ev-expired', expiresAt: new Date(Date.now() - 1000).toISOString() },
|
|
39
|
-
];
|
|
40
|
-
const options = {
|
|
41
|
-
companionId: 'companion-a',
|
|
42
|
-
channel: 'public',
|
|
43
|
-
audienceId: 'audience-public',
|
|
44
|
-
};
|
|
45
|
-
const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
|
|
46
|
-
expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-valid']);
|
|
47
|
-
expect(excluded).toEqual([
|
|
48
|
-
expect.objectContaining({
|
|
49
|
-
record: expect.objectContaining({ evidenceId: 'ev-expired' }),
|
|
50
|
-
reason: 'evidence_expired',
|
|
51
|
-
}),
|
|
52
|
-
]);
|
|
53
|
-
});
|
|
54
|
-
test('audience intersection excludes non-matching audiences', () => {
|
|
55
|
-
const records = [
|
|
56
|
-
{ ...baseRecord, evidenceId: 'ev-public', allowedAudiences: ['audience-public'] },
|
|
57
|
-
{ ...baseRecord, evidenceId: 'ev-direct-only', allowedAudiences: ['audience-direct-a'] },
|
|
58
|
-
];
|
|
59
|
-
const options = {
|
|
60
|
-
companionId: 'companion-a',
|
|
61
|
-
channel: 'public',
|
|
62
|
-
audienceId: 'audience-public',
|
|
63
|
-
};
|
|
64
|
-
const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
|
|
65
|
-
expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-public']);
|
|
66
|
-
expect(excluded).toEqual([
|
|
67
|
-
expect.objectContaining({
|
|
68
|
-
record: expect.objectContaining({ evidenceId: 'ev-direct-only' }),
|
|
69
|
-
reason: 'audience_not_allowed',
|
|
70
|
-
}),
|
|
71
|
-
]);
|
|
72
|
-
});
|
|
73
|
-
test('sensitivity policy excludes private and restricted evidence from public channels', () => {
|
|
74
|
-
const records = [
|
|
75
|
-
{ ...baseRecord, evidenceId: 'ev-pub', sensitivity: 'public', allowedAudiences: ['audience-public'] },
|
|
76
|
-
{ ...baseRecord, evidenceId: 'ev-priv', sensitivity: 'private', allowedAudiences: ['audience-public'] },
|
|
77
|
-
{ ...baseRecord, evidenceId: 'ev-rest', sensitivity: 'restricted', allowedAudiences: ['audience-public'] },
|
|
78
|
-
];
|
|
79
|
-
const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, {
|
|
80
|
-
companionId: 'companion-a',
|
|
81
|
-
channel: 'public',
|
|
82
|
-
audienceId: 'audience-public',
|
|
83
|
-
});
|
|
84
|
-
expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-pub']);
|
|
85
|
-
expect(excluded.map((e) => e.record.evidenceId)).toEqual(['ev-priv', 'ev-rest']);
|
|
86
|
-
});
|
|
87
|
-
test('direct channel permits private sensitivity but excludes restricted', () => {
|
|
88
|
-
const records = [
|
|
89
|
-
{ ...baseRecord, evidenceId: 'ev-pub', sensitivity: 'public', allowedAudiences: ['audience-direct-a'] },
|
|
90
|
-
{ ...baseRecord, evidenceId: 'ev-priv', sensitivity: 'private', allowedAudiences: ['audience-direct-a'] },
|
|
91
|
-
{ ...baseRecord, evidenceId: 'ev-rest', sensitivity: 'restricted', allowedAudiences: ['audience-direct-a'] },
|
|
92
|
-
];
|
|
93
|
-
const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, {
|
|
94
|
-
companionId: 'companion-a',
|
|
95
|
-
channel: 'direct',
|
|
96
|
-
audienceId: 'audience-direct-a',
|
|
97
|
-
});
|
|
98
|
-
expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-pub', 'ev-priv']);
|
|
99
|
-
expect(excluded.map((e) => e.record.evidenceId)).toEqual(['ev-rest']);
|
|
100
|
-
});
|
|
101
|
-
});
|
package/dist/experience.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Channel } from './context';
|
|
2
|
-
import { ResponseCitation } from './evidence';
|
|
3
|
-
export type ExperienceEventKind = 'voice' | 'caption' | 'avatar' | 'platform_action';
|
|
4
|
-
export type ExperienceEventLifecycle = 'STARTED' | 'PROGRESS' | 'COMPLETED' | 'FAILED';
|
|
5
|
-
export interface ExperienceEvent {
|
|
6
|
-
eventId: string;
|
|
7
|
-
companionId: string;
|
|
8
|
-
responseId: string;
|
|
9
|
-
correlationId: string;
|
|
10
|
-
channel: Channel;
|
|
11
|
-
audienceId: string;
|
|
12
|
-
approval: 'APPROVED';
|
|
13
|
-
kind: ExperienceEventKind;
|
|
14
|
-
lifecycle: ExperienceEventLifecycle;
|
|
15
|
-
evidenceIds: string[];
|
|
16
|
-
citations?: ResponseCitation[];
|
|
17
|
-
text?: string;
|
|
18
|
-
language?: string;
|
|
19
|
-
action?: string;
|
|
20
|
-
expression?: string;
|
|
21
|
-
createdAt: string;
|
|
22
|
-
expiresAt?: string;
|
|
23
|
-
}
|
|
24
|
-
export interface ExperienceAdapterResult {
|
|
25
|
-
accepted: boolean;
|
|
26
|
-
eventId: string;
|
|
27
|
-
lifecycle: ExperienceEventLifecycle;
|
|
28
|
-
error?: string;
|
|
29
|
-
reason?: string;
|
|
30
|
-
audioBuffer?: Uint8Array;
|
|
31
|
-
metadata?: Record<string, unknown>;
|
|
32
|
-
}
|
|
33
|
-
export interface ExperienceAdapter {
|
|
34
|
-
readonly kind: ExperienceEventKind;
|
|
35
|
-
handleEvent(event: ExperienceEvent): Promise<ExperienceAdapterResult>;
|
|
36
|
-
}
|
|
37
|
-
export interface CreateExperienceEventsOptions {
|
|
38
|
-
responseId: string;
|
|
39
|
-
companionId: string;
|
|
40
|
-
correlationId: string;
|
|
41
|
-
channel: Channel;
|
|
42
|
-
audienceId: string;
|
|
43
|
-
speech: string;
|
|
44
|
-
language?: string;
|
|
45
|
-
evidenceIds?: string[];
|
|
46
|
-
citations?: ResponseCitation[];
|
|
47
|
-
expression?: string;
|
|
48
|
-
action?: string;
|
|
49
|
-
expiresAt?: string;
|
|
50
|
-
now?: string | Date;
|
|
51
|
-
}
|
|
52
|
-
export declare function createExperienceEvents(options: CreateExperienceEventsOptions): ExperienceEvent[];
|
|
53
|
-
export declare function validateExperienceEvent(event: unknown): {
|
|
54
|
-
valid: boolean;
|
|
55
|
-
error?: string;
|
|
56
|
-
};
|