learning_ai_common_plat/services/mcp-server/src/lib/mindlyst-client.ts
saravanakumardb1 654de4ed2e feat(mcp-server): add 4 A2A pipelines — DailyBrief, MarketplaceCert, SafetyMonitor, SyncDiagnostics
- DailyBriefGenerationPipeline (mindlyst.brief.generate): fans out memory items across all brains, runs memory-insight extraction per brain, assembles and stores DailyBriefDoc
- MarketplaceCertificationPipeline (jarvis.marketplace.runCertification): ingestion validation, content safety via triage extraction, heuristic quality scoring, approve/reject/pending_human_review decision
- SafetyMonitorAgent (nomgap.safety.check + nomgap.safety.getThresholds): 5-tier threshold table, push notifications, A2A handoff for 72h+ fasts
- SyncDiagnosticsAgent (peakpulse.sync.diagnose): failure pattern classification from telemetry, conditional platform diagnostics session, log/trace capture, root cause + extraction entity report
- Add 3 missing client functions: mindlystBriefCreate, nomgapFastingSessionGet, jarvisMarketplaceGetListing
- MCP server now at 91 tools across 16 namespaces
2026-03-05 14:22:25 -08:00

243 lines
7.9 KiB
TypeScript

/**
* MindLyst backend client — typed HTTP wrappers for the mindlyst-backend (port 4014).
*
* Auth: Bearer token from the caller's JWT (same JWT_SECRET as platform-service).
* Admin callers may pass x-admin-user-id to operate on behalf of any user.
*/
import { config } from './config.js';
export interface MindlystClientOptions {
token?: string;
requestId?: string;
/** When set (admin only) — overrides the JWT sub used as userId in backend routes */
adminUserId?: string;
}
// ── Shared fetch helper ────────────────────────────────────────────────────
async function mindlystFetch<T>(
path: string,
init: RequestInit,
opts: MindlystClientOptions
): Promise<T> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),
...(opts.requestId ? { 'x-request-id': opts.requestId } : {}),
...(opts.adminUserId ? { 'x-admin-user-id': opts.adminUserId } : {}),
};
const res = await fetch(`${config.MINDLYST_BACKEND_URL}/api${path}`, {
...init,
headers: { ...((init.headers as Record<string, string>) ?? {}), ...headers },
signal: AbortSignal.timeout(15_000),
});
if (!res.ok) {
const body = await res.text().catch(() => '');
throw new Error(`mindlyst-backend ${init.method ?? 'GET'} ${path}${res.status}: ${body}`);
}
return res.json() as Promise<T>;
}
// ── Memory items ───────────────────────────────────────────────────────────
export interface MemoryItemDoc {
id: string;
productId: string;
userId: string;
sourceType: string;
captureSurface: string;
rawContent: string;
triageResult: {
contentType: string;
summary?: string;
urgencyScore: number;
emotionScore: number;
confidenceScore: number;
suggestedBrainId: string;
entities: string[];
suggestedActions: string[];
};
brainIds: string[];
actedOn: boolean;
actedOnAt: string | null;
nudgeCount: number;
reminderAt?: string;
isSensitive: boolean;
createdAt: string;
updatedAt: string;
}
export function mindlystMemoryList(
params: {
brainId?: string;
filter?: 'forgotten' | 'completed_today';
limit?: number;
offset?: number;
productId?: string;
},
opts: MindlystClientOptions
): Promise<{ items: MemoryItemDoc[]; limit: number; offset: number }> {
const qs = new URLSearchParams();
if (params.brainId) qs.set('brainId', params.brainId);
if (params.filter) qs.set('filter', params.filter);
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
if (params.productId) qs.set('productId', params.productId);
const q = qs.toString();
return mindlystFetch(`/memory-items${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}
export function mindlystMemoryGetItem(
itemId: string,
opts: MindlystClientOptions
): Promise<MemoryItemDoc> {
return mindlystFetch(`/memory-items/${itemId}`, { method: 'GET' }, opts);
}
export function mindlystMemoryRetriage(
itemId: string,
opts: MindlystClientOptions
): Promise<MemoryItemDoc> {
return mindlystFetch(`/memory-items/${itemId}/retriage`, { method: 'POST' }, opts);
}
export function mindlystMemoryPatch(
itemId: string,
action: 'mark_done' | 'mark_undone' | 'increment_nudge' | 'set_reminder',
reminderAt: string | undefined,
opts: MindlystClientOptions
): Promise<MemoryItemDoc> {
return mindlystFetch(
`/memory-items/${itemId}`,
{ method: 'PATCH', body: JSON.stringify({ action, ...(reminderAt ? { reminderAt } : {}) }) },
opts
);
}
export function mindlystMemoryReassign(
itemId: string,
newBrainId: string,
opts: MindlystClientOptions
): Promise<MemoryItemDoc> {
return mindlystFetch(
`/memory-items/${itemId}/reassign`,
{ method: 'PUT', body: JSON.stringify({ newBrainId }) },
opts
);
}
// ── Brains ─────────────────────────────────────────────────────────────────
export interface BrainDoc {
id: string;
userId: string;
productId: string;
name: string;
rolePrompt?: string;
tone?: string;
colorFrom?: string;
colorTo?: string;
createdAt: string;
updatedAt: string | null;
}
export function mindlystBrainsList(
params: { limit?: number; offset?: number },
opts: MindlystClientOptions
): Promise<{ items: BrainDoc[]; total: number; limit: number; offset: number }> {
const qs = new URLSearchParams();
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
const q = qs.toString();
return mindlystFetch(`/brains${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}
// ── Daily briefs ───────────────────────────────────────────────────────────
export interface DailyBriefDoc {
id: string;
userId: string;
productId: string;
date: string;
greeting?: string;
priorityItems: unknown[];
brainSummaries: Record<string, string>;
streakMessage?: string;
motivationalQuote?: string;
createdAt: string;
}
export function mindlystBriefCreate(
body: {
date: string;
greeting?: string;
priorityItems?: unknown[];
brainSummaries?: Record<string, string>;
streakMessage?: string;
motivationalQuote?: string;
},
opts: MindlystClientOptions
): Promise<DailyBriefDoc> {
return mindlystFetch('/daily-briefs', { method: 'POST', body: JSON.stringify(body) }, opts);
}
export function mindlystBriefsGetToday(opts: MindlystClientOptions): Promise<DailyBriefDoc> {
return mindlystFetch('/daily-briefs/today', { method: 'GET' }, opts);
}
export function mindlystBriefsList(
params: { limit?: number; offset?: number },
opts: MindlystClientOptions
): Promise<{ items: DailyBriefDoc[]; total: number }> {
const qs = new URLSearchParams();
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
const q = qs.toString();
return mindlystFetch(`/daily-briefs${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}
// ── Streaks ────────────────────────────────────────────────────────────────
export interface StreakDoc {
id: string;
userId: string;
productId: string;
currentStreak: number;
longestStreak: number;
lastActiveDate: string;
streakFreezeAvailable: boolean;
totalActiveDays: number;
createdAt: string;
updatedAt: string;
}
export function mindlystStreaksGet(opts: MindlystClientOptions): Promise<StreakDoc> {
return mindlystFetch('/streaks', { method: 'GET' }, opts);
}
// ── Reflections ────────────────────────────────────────────────────────────
export interface ReflectionDoc {
id: string;
userId: string;
productId: string;
weekStartDate: string;
themes: string[];
highlights: string[];
challenges: string[];
summary?: string;
createdAt: string;
}
export function mindlystReflectionsList(
params: { limit?: number; offset?: number },
opts: MindlystClientOptions
): Promise<{ items: ReflectionDoc[]; total: number }> {
const qs = new URLSearchParams();
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
const q = qs.toString();
return mindlystFetch(`/reflections${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}