MCP tool gaps filled (DOMAIN_PRODUCTS.md alignment): - jarvis.memory.create — POST /jarvis/agents/:agentId/memory (sessionId, type, content, importance, tags, expiresAt) - jarvis.teams.listMembers — GET /jarvis/teams/:teamId/members (role, status, joinedAt) - nomgap.fasting.getSession — GET /fasting/sessions/:id (client func already existed, MCP tool was missing) - peakpulse.weather.getSnapshot — extracts weather field from peakpulseSessionGet response New A2A pipelines (all registered in server.ts): - transcript-extraction-pipeline.ts: lysnrai.transcripts.runExtractionPipeline - TranscriptCollectorAgent -> ExtractionBatchAgent -> ExtractionReportAgent - Queries transcripts missing extractedAt, runs extraction, returns batch report + dryRun support - sync-conflict-pipeline.ts: chronomind.sync.diagnoseConflicts - ConflictDetectorAgent -> SyncStateInspectorAgent -> DiagnosticsSessionAgent -> ConflictReportAgent - Queries telemetry for sync_conflict events, classifies pattern, creates diagnostics session on conflict - route-safety-pipeline.ts: peakpulse.sessions.assessSafety - SessionDataAgent -> RouteProfileAgent -> SafetyAnalysisAgent -> SafetyReportAgent - Fetches GPS + weather, evaluates UV/wind/altitude/speed risk factors, enriches with extraction entities Client additions (jarvis-client.ts): jarvisMemoryCreate, jarvisTeamsListMembers + JarvisTeamMemberDoc interface MCP server total: 93 tools across 17 namespaces
288 lines
9.0 KiB
TypeScript
288 lines
9.0 KiB
TypeScript
/**
|
|
* JarvisJr backend client — typed HTTP wrappers for the jarvisjr-backend (port 4012).
|
|
*
|
|
* Auth: Bearer token from the caller's JWT (same JWT_SECRET as platform-service).
|
|
*/
|
|
|
|
import { config } from './config.js';
|
|
|
|
export interface JarvisClientOptions {
|
|
token?: string;
|
|
requestId?: string;
|
|
}
|
|
|
|
// ── Shared fetch helper ────────────────────────────────────────────────────
|
|
|
|
async function jarvisFetch<T>(
|
|
path: string,
|
|
init: RequestInit,
|
|
opts: JarvisClientOptions
|
|
): 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.JARVISJR_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(`jarvisjr-backend ${init.method ?? 'GET'} ${path} → ${res.status}: ${body}`);
|
|
}
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
// ── Agents ─────────────────────────────────────────────────────────────────
|
|
|
|
export interface JarvisAgentDoc {
|
|
id: string;
|
|
userId: string;
|
|
productId: string;
|
|
name: string;
|
|
role: string;
|
|
systemPrompt: string;
|
|
voiceId?: string;
|
|
coachingFramework?: string;
|
|
accentColor?: string;
|
|
welcomeMessage?: string;
|
|
sessionLength?: number;
|
|
difficultyLevel?: string;
|
|
language?: string;
|
|
privacyLevel?: string;
|
|
checkInSchedule?: string;
|
|
isTemplate?: boolean;
|
|
templateSource?: string;
|
|
totalSessions: number;
|
|
lastSessionAt: string | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface AgentCreateInput {
|
|
name: string;
|
|
role: string;
|
|
systemPrompt: string;
|
|
voiceId?: string;
|
|
coachingFramework?: string;
|
|
accentColor?: string;
|
|
welcomeMessage?: string;
|
|
sessionLength?: number;
|
|
difficultyLevel?: 'beginner' | 'intermediate' | 'advanced';
|
|
language?: string;
|
|
privacyLevel?: 'standard' | 'strict';
|
|
}
|
|
|
|
export function jarvisAgentCreate(
|
|
input: AgentCreateInput,
|
|
opts: JarvisClientOptions
|
|
): Promise<JarvisAgentDoc> {
|
|
return jarvisFetch('/jarvis/agents', { method: 'POST', body: JSON.stringify(input) }, opts);
|
|
}
|
|
|
|
export function jarvisAgentsList(
|
|
params: { limit?: number; offset?: number },
|
|
opts: JarvisClientOptions
|
|
): Promise<{ agents: JarvisAgentDoc[]; 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 jarvisFetch(`/jarvis/agents${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function jarvisAgentDuplicate(
|
|
agentId: string,
|
|
opts: JarvisClientOptions
|
|
): Promise<JarvisAgentDoc> {
|
|
return jarvisFetch(`/jarvis/agents/${agentId}/duplicate`, { method: 'POST' }, opts);
|
|
}
|
|
|
|
// ── Sessions ───────────────────────────────────────────────────────────────
|
|
|
|
export interface JarvisSessionDoc {
|
|
id: string;
|
|
userId: string;
|
|
productId: string;
|
|
agentId: string;
|
|
mode: string;
|
|
status: 'active' | 'completed';
|
|
summary?: string;
|
|
coachingNotes?: string[];
|
|
skillMetrics?: Record<string, number>;
|
|
duration?: number;
|
|
messageCount: number;
|
|
createdAt: string;
|
|
completedAt: string | null;
|
|
}
|
|
|
|
export interface JarvisSessionStats {
|
|
totalSessions: number;
|
|
totalDurationMinutes: number;
|
|
currentStreak: number;
|
|
longestStreak: number;
|
|
perAgent: Record<string, { sessions: number; avgDuration: number }>;
|
|
}
|
|
|
|
export function jarvisSessionsList(
|
|
params: { limit?: number; offset?: number; agentId?: string },
|
|
opts: JarvisClientOptions
|
|
): Promise<{ sessions: JarvisSessionDoc[]; 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.agentId) qs.set('agentId', params.agentId);
|
|
const q = qs.toString();
|
|
return jarvisFetch(`/jarvis/sessions${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function jarvisSessionsGetStats(opts: JarvisClientOptions): Promise<JarvisSessionStats> {
|
|
return jarvisFetch('/jarvis/sessions/stats', { method: 'GET' }, opts);
|
|
}
|
|
|
|
// ── Memory ─────────────────────────────────────────────────────────────────
|
|
|
|
export interface JarvisMemoryDoc {
|
|
id: string;
|
|
agentId: string;
|
|
userId: string;
|
|
productId: string;
|
|
sessionId?: string;
|
|
type: 'skill_note' | 'preference' | 'goal' | 'context' | 'exercise';
|
|
content: string;
|
|
importance: number;
|
|
tags?: string[];
|
|
createdAt: string;
|
|
expiresAt?: string;
|
|
}
|
|
|
|
export function jarvisMemoryList(
|
|
agentId: string,
|
|
params: {
|
|
type?: string;
|
|
minImportance?: number;
|
|
limit?: number;
|
|
offset?: number;
|
|
},
|
|
opts: JarvisClientOptions
|
|
): Promise<{ memories: JarvisMemoryDoc[]; total: number }> {
|
|
const qs = new URLSearchParams();
|
|
if (params.type) qs.set('type', params.type);
|
|
if (params.minImportance !== undefined) qs.set('minImportance', String(params.minImportance));
|
|
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 jarvisFetch(
|
|
`/jarvis/agents/${agentId}/memory${q ? `?${q}` : ''}`,
|
|
{ method: 'GET' },
|
|
opts
|
|
);
|
|
}
|
|
|
|
// ── Marketplace admin ─────────────────────────────────────────────────────
|
|
|
|
export function jarvisMarketplaceListPending(
|
|
opts: JarvisClientOptions
|
|
): Promise<{ listings: unknown[]; total: number }> {
|
|
return jarvisFetch('/marketplace/admin/pending', { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function jarvisMarketplaceCertify(
|
|
listingId: string,
|
|
decision: { decision: 'approved' | 'rejected'; notes?: string },
|
|
opts: JarvisClientOptions
|
|
): Promise<unknown> {
|
|
const action = decision.decision === 'approved' ? 'approve' : 'reject';
|
|
return jarvisFetch(
|
|
`/marketplace/admin/${listingId}/${action}`,
|
|
{ method: 'POST', body: JSON.stringify(decision) },
|
|
opts
|
|
);
|
|
}
|
|
|
|
export function jarvisMarketplaceGetListing(
|
|
listingId: string,
|
|
opts: JarvisClientOptions
|
|
): Promise<Record<string, unknown>> {
|
|
return jarvisFetch(`/marketplace/listings/${listingId}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function jarvisMarketplaceSuspend(
|
|
listingId: string,
|
|
reason: string,
|
|
opts: JarvisClientOptions
|
|
): Promise<unknown> {
|
|
return jarvisFetch(
|
|
`/marketplace/admin/${listingId}/suspend`,
|
|
{ method: 'POST', body: JSON.stringify({ reason }) },
|
|
opts
|
|
);
|
|
}
|
|
|
|
export function jarvisMarketplaceFeature(
|
|
listingId: string,
|
|
featured: boolean,
|
|
opts: JarvisClientOptions
|
|
): Promise<unknown> {
|
|
return jarvisFetch(
|
|
`/marketplace/admin/${listingId}/feature`,
|
|
{ method: 'POST', body: JSON.stringify({ featured }) },
|
|
opts
|
|
);
|
|
}
|
|
|
|
export function jarvisMemoryPrune(
|
|
agentId: string,
|
|
opts: JarvisClientOptions
|
|
): Promise<{ pruned: number }> {
|
|
return jarvisFetch(`/jarvis/agents/${agentId}/memory/prune`, { method: 'POST' }, opts);
|
|
}
|
|
|
|
export function jarvisMemoryGetContext(
|
|
agentId: string,
|
|
limit: number | undefined,
|
|
opts: JarvisClientOptions
|
|
): Promise<{ memories: JarvisMemoryDoc[]; count: number }> {
|
|
const qs = limit !== undefined ? `?limit=${limit}` : '';
|
|
return jarvisFetch(`/jarvis/agents/${agentId}/memory/context${qs}`, { method: 'GET' }, opts);
|
|
}
|
|
|
|
export function jarvisMemoryCreate(
|
|
agentId: string,
|
|
input: {
|
|
sessionId: string;
|
|
type: 'skill_note' | 'preference' | 'goal' | 'context' | 'exercise';
|
|
content: string;
|
|
importance?: number;
|
|
tags?: string[];
|
|
expiresAt?: string | null;
|
|
},
|
|
opts: JarvisClientOptions
|
|
): Promise<JarvisMemoryDoc> {
|
|
return jarvisFetch(
|
|
`/jarvis/agents/${agentId}/memory`,
|
|
{ method: 'POST', body: JSON.stringify({ ...input, agentId }) },
|
|
opts
|
|
);
|
|
}
|
|
|
|
// ── Teams ─────────────────────────────────────────────────────────────────
|
|
|
|
export interface JarvisTeamMemberDoc {
|
|
userId: string;
|
|
teamId: string;
|
|
role: 'owner' | 'manager' | 'member';
|
|
status: 'active' | 'invited' | 'removed';
|
|
joinedAt: string;
|
|
invitedBy?: string;
|
|
}
|
|
|
|
export function jarvisTeamsListMembers(
|
|
teamId: string,
|
|
opts: JarvisClientOptions
|
|
): Promise<{ members: JarvisTeamMemberDoc[]; total: number }> {
|
|
return jarvisFetch(`/jarvis/teams/${teamId}/members`, { method: 'GET' }, opts);
|
|
}
|