| |
| |
| |
| import { apiRequest } from './client' |
|
|
| export const AGENTIC_DEMO_ENABLED = |
| (import.meta.env.VITE_AGENTIC_DEMO_ENABLED as string | undefined) !== 'false' |
|
|
| export interface ModelStatus { |
| behavioural_model: string |
| model_version: string |
| feature_version: string |
| reason_codes_version: string |
| shadow_only: boolean |
| affects_payment: boolean |
| label: string |
| } |
|
|
| export interface RiskView { |
| band: 'low' | 'uncertain' | 'elevated' | 'high' | 'model_unavailable' |
| recommend_step_up: boolean |
| reason_codes: string[] |
| confidence: string |
| model_version: string |
| feature_version: string |
| shadow: boolean |
| } |
|
|
| export interface AuthRecommendation { |
| recommended_method: string |
| meets_pdp_minimum: boolean |
| } |
|
|
| export interface AuditSummary { |
| verified: boolean |
| length: number |
| protection_level: string |
| } |
|
|
| |
| export interface OrchestrateResult { |
| decision: 'allow' | 'deny' | 'step_up' |
| reason_codes: string[] |
| required_auth: string[] |
| agent_state: string |
| risk: RiskView | null |
| auth_recommendation: AuthRecommendation | null |
| rails: { ranked: string[]; eligible_only: boolean } | null |
| explanation: { locale: string; messages: string[]; reason_codes: string[] } | null |
| payment: { id: string; status: string } | null |
| audit: AuditSummary | null |
| fallback: string | null |
| labels: Record<string, string> |
| } |
|
|
| export interface ScenarioInput { |
| payee_ref: string |
| amount_minor: number |
| known_payees?: string[] |
| history_payments?: number |
| recent_24h?: number |
| consent?: boolean |
| approve?: boolean |
| locale?: string |
| now?: number |
| } |
|
|
| |
| |
| |
| |
| export type ConsentPurpose = 'service_essential' | 'optional_personalization' | 'optional_federation' |
| export type PurposeKind = 'required_processing' | 'optional_consent' |
| export type ConsentStatus = 'not_granted' | 'granted' | 'withdrawn' |
|
|
| export interface PurposeMeta { |
| purpose_kind: PurposeKind |
| withdrawable: boolean |
| version: number |
| updated_at: number |
| status?: ConsentStatus |
| state?: string |
| } |
|
|
| export interface ProfileStatus { |
| subject: string |
| policy_version: string |
| record_version: number |
| profile_generation?: number |
| purposes: Record<ConsentPurpose, PurposeMeta> |
| personalization_enabled: boolean |
| federation_enrolled: boolean |
| personalization_without_shared_learning: boolean |
| affects_payment: boolean |
| authoritative: boolean |
| storage_consistency: { backend: string; durable_multi_replica: boolean; note: string } |
| label: string |
| } |
|
|
| export interface DifferentialPrivacyDetail { |
| differential_privacy: string |
| budget_exhausted: boolean |
| candidate_privacy_eligibility: string |
| cumulative_epsilon?: number | null |
| budget_epsilon?: number | null |
| production_privacy_guarantee: boolean |
| note: string |
| } |
|
|
| export interface FederatedStatus { |
| client_type: string |
| real_device_training: string |
| native_local_only_training: string |
| real_user_data_used: boolean |
| federation: string |
| secure_aggregation: string |
| differential_privacy: string |
| differential_privacy_detail: DifferentialPrivacyDetail |
| automatic_model_promotion: boolean |
| affects_payment_authorization: boolean |
| candidate_status: string |
| candidate_promotable: boolean |
| disclaimer: string |
| label: string |
| aggregators?: string[] |
| } |
|
|
| export interface DeleteProfileResult { |
| subject: string |
| profile: string |
| deleted_now: boolean |
| deleted_categories: string[] |
| retained_categories: string[] |
| retention_reason: string |
| retired_generation: number |
| audit_reference: string |
| erasure_type: string |
| affects_payment: boolean |
| note: string |
| } |
|
|
| function requestId(): string { |
| const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto |
| return c?.randomUUID ? c.randomUUID() : `req-${Date.now()}-${Math.random().toString(16).slice(2)}` |
| } |
|
|
| export function modelStatus(signal?: AbortSignal): Promise<ModelStatus> { |
| return apiRequest<ModelStatus>('/ai/v1/models/status', { signal }) |
| } |
|
|
| export function profileStatus(signal?: AbortSignal): Promise<ProfileStatus> { |
| return apiRequest<ProfileStatus>('/ai/v1/profile/status', { signal }) |
| } |
|
|
| export function setConsent(purpose: ConsentPurpose, grant: boolean, expectedVersion?: number, signal?: AbortSignal): Promise<ProfileStatus> { |
| return apiRequest<ProfileStatus>('/ai/v1/consent', { |
| body: { purpose, grant, request_id: requestId(), expected_version: expectedVersion }, signal, |
| }) |
| } |
|
|
| export function deleteProfile(signal?: AbortSignal): Promise<DeleteProfileResult> { |
| return apiRequest<DeleteProfileResult>('/ai/v1/profile', { method: 'DELETE', body: { request_id: requestId() }, signal }) |
| } |
|
|
| export function federatedStatus(signal?: AbortSignal): Promise<FederatedStatus> { |
| return apiRequest<FederatedStatus>('/ai/v1/federated/status', { signal }) |
| } |
|
|
| export function demoPayee(iban: string, signal?: AbortSignal): Promise<{ payee_ref: string; display: string }> { |
| return apiRequest('/ai/v1/demo/payee', { body: { iban }, signal }) |
| } |
|
|
| export function orchestrate(input: ScenarioInput, signal?: AbortSignal): Promise<OrchestrateResult> { |
| return apiRequest<OrchestrateResult>('/ai/v1/demo/orchestrate', { body: input, signal }) |
| } |
|
|