|
1 | | -import { CircuitBreaker } from './circuitBreaker'; |
2 | | -import type { ModelProvider, ModelResponse } from './types'; |
| 1 | +import { CircuitBreaker } from './circuitBreaker' |
| 2 | +import type { ModelProvider, ModelResponse } from './types' |
| 3 | +import { calculateDemographicParity } from './fairness' |
| 4 | +import { generateCAE } from './interpretability' |
3 | 5 |
|
4 | | -type Intent = 'casual' | 'actionable' | 'analytical' | 'sensitive'; |
5 | | -export type RouteDecision = { intent: Intent; target: 'surface' | 'depth'; reason: string }; |
| 6 | +type Intent = 'casual' | 'actionable' | 'analytical' | 'sensitive' |
| 7 | +export type RouteDecision = { intent: Intent, target: 'surface' | 'depth', reason: string } |
6 | 8 |
|
7 | 9 | export class Orchestrator { |
8 | | - private breakerDepth = new CircuitBreaker(3, 15000); |
9 | | - constructor(private surface: ModelProvider, private depth: ModelProvider, private intentDetect: (msg: string) => Intent) {} |
10 | | - |
11 | | - route(input: string, override?: 'surface' | 'depth'): RouteDecision { |
12 | | - if (override) return { intent: this.intentDetect(input), target: override, reason: 'user_override' }; |
13 | | - const intent = this.intentDetect(input); |
14 | | - const target = intent === 'analytical' ? 'depth' : 'surface'; |
15 | | - return { intent, target, reason: 'policy' }; |
| 10 | + private breakerDepth = new CircuitBreaker(3, 15000) |
| 11 | + constructor (private surface: ModelProvider, private depth: ModelProvider, private intentDetect: (msg: string) => Intent) {} |
| 12 | + |
| 13 | + route (input: string, override?: 'surface' | 'depth'): RouteDecision { |
| 14 | + if (override) return { intent: this.intentDetect(input), target: override, reason: 'user_override' } |
| 15 | + const intent = this.intentDetect(input) |
| 16 | + const target = intent === 'analytical' ? 'depth' : 'surface' |
| 17 | + return { intent, target, reason: 'policy' } |
16 | 18 | } |
17 | 19 |
|
18 | | - async respond(input: string, stream = true): Promise<ModelResponse> { |
19 | | - const decision = this.route(input); |
20 | | - const primary = decision.target === 'depth' ? this.depth : this.surface; |
21 | | - const fallback = decision.target === 'depth' ? this.surface : this.depth; |
| 20 | + async respond (input: string, stream = true): Promise<ModelResponse> { |
| 21 | + const decision = this.route(input) |
| 22 | + const primary = decision.target === 'depth' ? this.depth : this.surface |
| 23 | + const fallback = decision.target === 'depth' ? this.surface : this.depth |
22 | 24 |
|
23 | 25 | if (decision.target === 'depth' && !this.breakerDepth.canPass()) { |
24 | | - return this.surface.invoke(this.decorate(input, { fallback: 'depth_breaker_open' })); |
| 26 | + return this.surface.invoke(this.decorate(input, { fallback: 'depth_breaker_open' })) |
25 | 27 | } |
26 | 28 |
|
27 | 29 | try { |
28 | 30 | const res = stream && primary.supportsStreaming |
29 | 31 | ? await primary.stream(this.decorate(input, decision)) |
30 | | - : await primary.invoke(this.decorate(input, decision)); |
31 | | - if (decision.target === 'depth') this.breakerDepth.recordSuccess(); |
32 | | - return res; |
| 32 | + : await primary.invoke(this.decorate(input, decision)) |
| 33 | + |
| 34 | + if (decision.target === 'depth') this.breakerDepth.recordSuccess() |
| 35 | + |
| 36 | + // MAS FEAT & HKMA Compliance for MoE expert nodes (depth layer) |
| 37 | + if (decision.target === 'depth' && res.text) { |
| 38 | + // MAS FEAT: Demographic Parity |
| 39 | + res.meta.fairness = calculateDemographicParity(input, res.text) |
| 40 | + // HKMA Ethics: Contextual Attribution Envelopes (CAE) |
| 41 | + res.meta.cae = generateCAE(input, res.text) |
| 42 | + } |
| 43 | + |
| 44 | + return res |
33 | 45 | } catch (e) { |
34 | | - if (decision.target === 'depth') this.breakerDepth.recordFailure(); |
35 | | - return fallback.invoke(this.decorate(input, { fallback: 'primary_failed' })); |
| 46 | + if (decision.target === 'depth') this.breakerDepth.recordFailure() |
| 47 | + return fallback.invoke(this.decorate(input, { fallback: 'primary_failed' })) |
36 | 48 | } |
37 | 49 | } |
38 | 50 |
|
39 | | - private decorate(input: string, meta: Record<string, unknown>): string { |
40 | | - return `<!-- orchestration:${JSON.stringify(meta)} -->\n${input}`; |
| 51 | + private decorate (input: string, meta: Record<string, unknown>): string { |
| 52 | + return `<!-- orchestration:${JSON.stringify(meta)} -->\n${input}` |
41 | 53 | } |
42 | 54 | } |
0 commit comments