Bug fix (committed separately):
social-fast-coordinator: stage_transition used non-existent currentStage
New client functions:
nomgap-client: nomgapFastingCreateSession, nomgapProtocolGet,
nomgapSocialListGroupFasts (+ GroupFastDoc)
peakpulse-client: peakpulseRoutesList, peakpulseSyncStatus
lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStats,
lysnraiTranscriptsExportBatch
chronomind-client: chronomindRoutineGet, chronomindSharedTimerShare
New MCP tools (12):
mindlyst.briefs.generate — trigger daily brief via mindlystBriefCreate
mindlyst.memory.getTriageResult — extract TriageResult sub-doc only
nomgap.fasting.createSession — start new fast with protocolId
nomgap.protocols.get — single protocol lookup
nomgap.social.listGroupFasts — list group fast sessions
peakpulse.routes.list — list GPS r
Bug fix (committed separately):
social-fast-coordinator: stage_transition used non-existent currentStage
ats social-fast-coordinator: staon
New client functions:
nomgap-client: nomgapFastingCreateSession, nomgarai nomgaens.rotate nomgapSocialListGroupFasts (+ GroupFastDoc)
d. peakpulse-client: peakpulseRoutesList, peakpulseSyncStaturg lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStati lysnraiTranscriptsExpor us chronomind-client: chronomindRoutineGet, chrerver total: 126 tools across 17 namespaces
208 lines
7.2 KiB
TypeScript
208 lines
7.2 KiB
TypeScript
/**
|
|
* LysnrAI backend client — typed HTTP wrappers for the lysnrai-backend (port 4015).
|
|
*
|
|
* Auth: Bearer token from the caller's JWT (same JWT_SECRET as platform-service).
|
|
*/
|
|
|
|
import { config } from './config.js';
|
|
|
|
export interface LysnraiClientOptions {
|
|
token?: string;
|
|
requestId?: string;
|
|
}
|
|
|
|
// ── Shared fetch helper ────────────────────────────────────────────────────
|
|
|
|
async function lysnraiFetch<T>(
|
|
path: string,
|
|
init: RequestInit,
|
|
opts: LysnraiClientOptions
|
|
): Promise<T> {
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),
|
|
...(opts.requestId ? { 'x-request-id': opts.requestId } : {}),
|
|
};
|
|
const res = await fetch(`${config.LYSNRAI_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(`lysnrai-backend ${init.method ?? 'GET'} ${path} → ${res.status}: ${body}`);
|
|
}
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
// ── Transcripts ────────────────────────────────────────────────────────────
|
|
|
|
export interface TranscriptDoc {
|
|
id: string;
|
|
userId: string;
|
|
productId: string;
|
|
rawText?: string;
|
|
cleanedText?: string;
|
|
wordCount?: number;
|
|
duration?: number;
|
|
tokensUsed?: number;
|
|
context?: string;
|
|
source?: string;
|
|
language?: string;
|
|
extractions?: unknown[];
|
|
extractionMetadata?: Record<string, unknown>;
|
|
extractedAt?: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
export function lysnraiTranscriptsList(
|
|
params: { limit?: number; offset?: number },
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ transcripts: TranscriptDoc[]; 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 lysnraiFetch(`/transcripts${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiTranscriptGet(
|
|
id: string,
|
|
opts: LysnraiClientOptions
|
|
): Promise<TranscriptDoc> {
|
|
return lysnraiFetch(`/transcripts/${id}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiTranscriptRunExtraction(
|
|
transcriptId: string,
|
|
opts: LysnraiClientOptions
|
|
): Promise<TranscriptDoc> {
|
|
return lysnraiFetch(`/transcripts/${transcriptId}/extract`, { method: 'POST' }, opts);
|
|
}
|
|
|
|
// ── STT status ─────────────────────────────────────────────────────────────
|
|
|
|
export interface SttStatusResult {
|
|
productId: string;
|
|
primary: 'azure' | 'whisper' | 'none';
|
|
azureConfigured: boolean;
|
|
whisperConfigured: boolean;
|
|
azureRegion: string | null;
|
|
generatedAt: string;
|
|
}
|
|
|
|
export function lysnraiSttGetBackendStatus(opts: LysnraiClientOptions): Promise<SttStatusResult> {
|
|
return lysnraiFetch('/transcripts/stt-status', { method: 'GET' }, opts);
|
|
}
|
|
|
|
// ── Sessions ───────────────────────────────────────────────────────────────
|
|
|
|
export interface SessionDoc {
|
|
id: string;
|
|
userId: string;
|
|
productId: string;
|
|
title: string;
|
|
status: 'active' | 'composed' | 'archived';
|
|
entries: unknown[];
|
|
composedText: string | null;
|
|
composedAt: string | null;
|
|
compositionRating: number | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export function lysnraiSessionGet(
|
|
sessionId: string,
|
|
opts: LysnraiClientOptions
|
|
): Promise<SessionDoc> {
|
|
return lysnraiFetch(`/sessions/${sessionId}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiSessionsList(
|
|
params: { limit?: number; offset?: number; status?: string },
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ sessions: SessionDoc[]; 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));
|
|
if (params.status) qs.set('status', params.status);
|
|
const q = qs.toString();
|
|
return lysnraiFetch(`/sessions${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
// ── Organisations ──────────────────────────────────────────────────────────
|
|
|
|
export interface OrgDoc {
|
|
id: string;
|
|
name: string;
|
|
ownerId: string;
|
|
productId: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
export function lysnraiOrgGet(orgId: string, opts: LysnraiClientOptions): Promise<OrgDoc> {
|
|
return lysnraiFetch(`/orgs/${orgId}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiOrgsList(
|
|
params: { limit?: number; offset?: number },
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ organizations: OrgDoc[] }> {
|
|
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 lysnraiFetch(`/orgs${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
// ── API tokens ─────────────────────────────────────────────────────────────
|
|
|
|
export interface ApiTokenDoc {
|
|
id: string;
|
|
userId: string;
|
|
productId: string;
|
|
name: string;
|
|
lastUsedAt: string | null;
|
|
createdAt: string;
|
|
}
|
|
|
|
export function lysnraiApiTokensList(
|
|
params: { limit?: number; offset?: number },
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ tokens: ApiTokenDoc[] }> {
|
|
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 lysnraiFetch(`/api-tokens${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiApiTokenCreate(
|
|
input: { name: string },
|
|
opts: LysnraiClientOptions
|
|
): Promise<ApiTokenDoc & { rawToken: string }> {
|
|
return lysnraiFetch('/api-tokens', { method: 'POST', body: JSON.stringify(input) }, opts);
|
|
}
|
|
|
|
export function lysnraiApiTokenRevoke(
|
|
tokenId: string,
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ success: boolean }> {
|
|
return lysnraiFetch(`/api-tokens/${tokenId}`, { method: 'DELETE' }, opts);
|
|
}
|
|
|
|
export function lysnraiSessionsStats(opts: LysnraiClientOptions): Promise<Record<string, unknown>> {
|
|
return lysnraiFetch('/sessions/stats', { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function lysnraiTranscriptsExportBatch(
|
|
params: { format?: 'json' | 'txt'; limit?: number },
|
|
opts: LysnraiClientOptions
|
|
): Promise<{ exportUrl: string; count: number; format: string; generatedAt: string }> {
|
|
const qs = new URLSearchParams();
|
|
if (params.format) qs.set('format', params.format);
|
|
if (params.limit !== undefined) qs.set('limit', String(params.limit));
|
|
const q = qs.toString();
|
|
return lysnraiFetch(`/transcripts/export${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|