File size: 1,541 Bytes
44737f9
37f231b
 
 
 
 
 
 
 
 
1720172
 
 
 
 
 
37f231b
 
1720172
37f231b
 
1720172
37f231b
1720172
37f231b
1720172
 
37f231b
1720172
37f231b
 
1720172
37f231b
1720172
37f231b
1720172
 
37f231b
1720172
37f231b
1720172
 
37f231b
44737f9
37f231b
 
 
 
 
 
 
1720172
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// website/src/lib/api.js
// All Brain calls go through the CF Worker (ultron-api) which proxies to Brain.
// Worker adds X-Ultron-Token from its own secret — website never holds the token.

const BASE = import.meta.env.VITE_API_URL || 'https://ultron-api.ghostdriveg1.workers.dev';

async function req(path, opts = {}) {
  const res = await fetch(`${BASE}${path}`, {
    ...opts,
    headers: { 'Content-Type': 'application/json', ...opts.headers },
  });
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
  return res.json();
}

export const api = {
  // GET /api/health → Brain /health
  health: () => req('/api/health'),

  // POST /api/infer → Brain /infer
  infer: (payload) => req('/api/infer', { method: 'POST', body: JSON.stringify(payload) }),

  // GET /api/keys → Brain /keys
  keys: {
    list: () => req('/api/keys'),
  },

  // Sentinel
  sentinel: {
    trigger: (type) =>
      req('/api/sentinel/event', {
        method: 'POST',
        body: JSON.stringify({ event_type: type, payload: { source: 'website' } }),
      }),
    reports: () => req('/api/sentinel/reports'),
  },

  // Memory
  memory: {
    stm: (channelId) => req(`/api/memory/stm/${channelId}`),
  },

  // R&D loop history
  rd: {
    history: (userId, limit = 20) => req(`/api/rd/history/${userId}?limit=${limit}`),
  },

  // Infrastructure — SpacePromoter topology + infra event log
  infra: {
    promoterStatus: () => req('/api/health').then((d) => d.promoter ?? null),
    events: () => req('/api/infra/events'),
  },
};