@siduri-x/api 1.0.5 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+
2
+ > @siduri-x/api@2.0.2 build /home/zagin/Projects/vxnus-studio/projects/siduri-x/apps/api
3
+ > tsc
4
+
@@ -0,0 +1,43 @@
1
+
2
+ > @siduri-x/api@2.0.2 test /home/zagin/Projects/vxnus-studio/projects/siduri-x/apps/api
3
+ > jest --config jest.config.json
4
+
5
+ PASS src/boot.test.ts (12.448 s)
6
+ PASS src/index.test.ts (12.646 s)
7
+ PASS src/t7-release.test.ts (12.705 s)
8
+ PASS src/knowledge.test.ts (12.82 s)
9
+ PASS src/context-mapper.test.ts
10
+ PASS src/runtime.test.ts
11
+ ● Console
12
+
13
+ console.error
14
+ [SiduriRuntime] Knowledge search failed: E-Teyvat is down
15
+
16
+ 21 | extKnowledge && shouldQueryKnowledge && typeof extKnowledge.search === 'function'
17
+ 22 | ? extKnowledge.search(perceivedText).catch((e) => {
18
+ > 23 | console.error('[SiduriRuntime] Knowledge search failed:', e.message);
19
+ | ^
20
+ 24 | subsystemDiagnostics['knowledge'] = `UNAVAILABLE: ${e.message}`;
21
+ 25 | return [];
22
+ 26 | })
23
+
24
+ at ../../packages/core/dist/context-retriever.js:23:25
25
+ at async Promise.all (index 0)
26
+ at retrieveRuntimeContext (../../packages/core/dist/context-retriever.js:19:78)
27
+ at contextRetrievalStage (../../packages/core/dist/perception-pipeline.js:66:30)
28
+ at PerceptionPipeline.execute (../../packages/core/dist/perception-pipeline.js:21:34)
29
+ at Object.<anonymous> (src/runtime.test.ts:74:22)
30
+
31
+ PASS src/auth.test.ts
32
+ PASS src/smoke.test.ts
33
+ PASS src/teach-mode.test.ts
34
+ PASS src/t5-experience.test.ts
35
+ PASS src/t4-gating.test.ts (13.84 s)
36
+ PASS src/t6-security.test.ts (14.624 s)
37
+ PASS src/b0-b6.test.ts (13.796 s)
38
+ 
39
+ Test Suites: 13 passed, 13 total
40
+ Tests: 86 passed, 86 total
41
+ Snapshots: 0 total
42
+ Time: 17.47 s
43
+ Ran all test suites.
package/dist/app.d.ts CHANGED
@@ -1,40 +1,8 @@
1
1
  import { Express } from 'express';
2
2
  import { SiduriRuntime } from './runtime';
3
- import { VoiceConfig } from '@siduri-x/voice';
4
- import { EKnowledgeConfig } from '@siduri-x/knowledge';
5
- import { OpenRouterVisionConfig } from '@siduri-x/vision';
6
- import { Live2DAdapterConfig } from '@siduri-x/body';
7
3
  import { FixtureObservationOrgan } from '@siduri-x/observation';
8
- import { DefaultHandsOrganConfig } from '@siduri-x/hands';
9
- import { EarOrganConfig } from '@siduri-x/ear';
10
- import { DefaultMouthOrganConfig } from '@siduri-x/mouth';
11
- export interface AppBrainConfig {
12
- provider?: 'openrouter' | 'openai-compatible' | string;
13
- model?: string;
14
- apiKey?: string;
15
- apiKeyEnv?: string;
16
- baseUrl?: string;
17
- timeoutMs?: number;
18
- [key: string]: unknown;
19
- }
20
- export interface AppBehaviorConfig {
21
- provider?: 'active_self' | 'none' | string;
22
- preset?: string;
23
- [key: string]: unknown;
24
- }
25
- export interface AppBootCompanionConfig {
26
- name: string;
27
- brain?: AppBrainConfig;
28
- voice?: VoiceConfig;
29
- knowledge?: EKnowledgeConfig;
30
- vision?: OpenRouterVisionConfig;
31
- behavior?: AppBehaviorConfig;
32
- body?: Live2DAdapterConfig;
33
- hands?: DefaultHandsOrganConfig;
34
- ear?: EarOrganConfig;
35
- mouth?: DefaultMouthOrganConfig;
36
- [key: string]: unknown;
37
- }
4
+ import { bootCompanion, AppBrainConfig, AppBehaviorConfig, AppBootCompanionConfig, BootCompanionOptions } from './boot';
5
+ export { AppBrainConfig, AppBehaviorConfig, AppBootCompanionConfig, BootCompanionOptions, bootCompanion, };
38
6
  export interface AppInstance {
39
7
  app: Express;
40
8
  runtimes: Map<string, SiduriRuntime>;
package/dist/app.js CHANGED
@@ -3,119 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.bootCompanion = void 0;
6
7
  exports.createApp = createApp;
7
8
  const express_1 = __importDefault(require("express"));
8
9
  const cors_1 = __importDefault(require("cors"));
9
10
  const cors_2 = require("./cors");
10
11
  const runtime_1 = require("./runtime");
11
- const brain_1 = require("@siduri-x/brain");
12
- const memory_1 = require("@siduri-x/memory");
13
- const voice_1 = require("@siduri-x/voice");
14
- const knowledge_1 = require("@siduri-x/knowledge");
15
- const vision_1 = require("@siduri-x/vision");
16
- const behavior_1 = require("@siduri-x/behavior");
17
- const body_1 = require("@siduri-x/body");
18
- const hands_1 = require("@siduri-x/hands");
19
- const ear_1 = require("@siduri-x/ear");
20
- const mouth_1 = require("@siduri-x/mouth");
12
+ const self_1 = require("@siduri-x/self");
21
13
  const auth_1 = require("./auth");
22
14
  const context_mapper_1 = require("./context-mapper");
15
+ const boot_1 = require("./boot");
16
+ Object.defineProperty(exports, "bootCompanion", { enumerable: true, get: function () { return boot_1.bootCompanion; } });
23
17
  function createApp(runtimes = new Map()) {
24
18
  const app = (0, express_1.default)();
25
19
  app.use((0, cors_1.default)((0, cors_2.createCorsOptions)()));
26
20
  app.use(express_1.default.json());
27
21
  let observationOrgan;
28
- function createBrain(config) {
29
- const provider = config?.provider || 'openrouter';
30
- const defaultKeyEnv = provider === 'openai-compatible' ? 'OPENAI_COMPATIBLE_API_KEY' : 'OPENROUTER_API_KEY';
31
- const apiKey = config?.apiKey || process.env[config?.apiKeyEnv || defaultKeyEnv] || '';
32
- if (provider === 'openai-compatible') {
33
- return new brain_1.OpenAICompatibleBrain({
34
- apiKey,
35
- model: config?.model || 'local-model',
36
- baseUrl: config?.baseUrl || 'http://127.0.0.1:1234/v1',
37
- });
38
- }
39
- return new brain_1.OpenRouterBrain({ apiKey, model: config?.model || 'gpt-4o-mini' });
40
- }
41
- function isDisabled(config) {
42
- return !config || config.provider === 'none';
43
- }
44
- function createVoice(config) {
45
- return isDisabled(config)
46
- ? undefined
47
- : new voice_1.VoiceAdapter({
48
- provider: config?.provider || 'voicevox',
49
- baseUrl: config?.baseUrl || process.env.VOICEVOX_URL || 'http://localhost:50021',
50
- speakerId: config?.speakerId || 1,
51
- ...config,
52
- });
53
- }
54
- function createKnowledge(config) {
55
- return isDisabled(config) ? undefined : new knowledge_1.EKnowledgeAdapter(config || {});
56
- }
57
- function createVision(config) {
58
- return isDisabled(config)
59
- ? undefined
60
- : new vision_1.OpenRouterVisionAdapter({
61
- apiKey: config?.apiKey || process.env.OPENROUTER_API_KEY || '',
62
- model: config?.model || 'gpt-4-vision',
63
- ...config,
64
- });
65
- }
66
- function createBehavior(config) {
67
- return isDisabled(config) ? undefined : new behavior_1.ActiveSelfCompiler();
68
- }
69
- function createBody(config) {
70
- return isDisabled(config)
71
- ? undefined
72
- : new body_1.Live2DAdapter(config);
73
- }
74
- function createHands(config) {
75
- return isDisabled(config)
76
- ? new hands_1.DefaultHandsOrgan()
77
- : new hands_1.DefaultHandsOrgan(config);
78
- }
79
- function createEar(config) {
80
- return isDisabled(config)
81
- ? new ear_1.DefaultEarOrgan()
82
- : new ear_1.DefaultEarOrgan(config);
83
- }
84
- function createMouth(config, voice) {
85
- return isDisabled(config)
86
- ? new mouth_1.DefaultMouthOrgan({ voice })
87
- : new mouth_1.DefaultMouthOrgan({ ...config, voice });
88
- }
89
22
  app.post('/boot', auth_1.requireAuth, async (req, res) => {
90
23
  try {
91
24
  const { id, config } = req.body;
92
25
  if (runtimes.has(id)) {
93
26
  return res.status(400).json({ error: "Already booted" });
94
27
  }
95
- const brain = createBrain(config.brain);
96
- const memory = new memory_1.PostgresMemoryOrgan({ connectionString: process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:5432/siduri' });
97
- const voice = createVoice(config.voice);
98
- const knowledge = createKnowledge(config.knowledge);
99
- const vision = createVision(config.vision);
100
- const behavior = createBehavior(config.behavior);
101
- const body = createBody(config.body);
102
- const hands = createHands(config.hands);
103
- const ear = createEar(config.ear);
104
- const mouth = createMouth(config.mouth, voice);
105
- const runtime = new runtime_1.SiduriRuntime(id, config, {
106
- brain,
107
- memory,
108
- voice,
109
- knowledge,
110
- vision,
111
- behavior,
112
- body,
113
- hands,
114
- ear,
115
- mouth,
116
- observation: observationOrgan,
117
- });
118
- await runtime.initialize();
28
+ const runtime = await (0, boot_1.bootCompanion)(id, config, { observationOrgan });
119
29
  runtimes.set(id, runtime);
120
30
  res.json({ success: true, id });
121
31
  }
@@ -162,16 +72,83 @@ function createApp(runtimes = new Map()) {
162
72
  });
163
73
  });
164
74
  app.put('/me', auth_1.requireAuth, (req, res) => res.json({ success: true }));
75
+ // TEACH MODE ENDPOINTS
76
+ app.post('/teach/upload-self', auth_1.requireAuth, async (req, res) => {
77
+ try {
78
+ const { content } = req.body;
79
+ if (!content)
80
+ return res.status(400).json({ error: "Missing content" });
81
+ const parsed = self_1.SelfPackageParser.parse(content);
82
+ res.json(parsed);
83
+ }
84
+ catch (e) {
85
+ res.status(500).json({ error: e.message });
86
+ }
87
+ });
88
+ app.post('/teach/install-self', auth_1.requireAuth, async (req, res) => {
89
+ try {
90
+ const { companionId, manifest, approvedDirectiveIds } = req.body;
91
+ if (!companionId || !manifest || !Array.isArray(approvedDirectiveIds)) {
92
+ return res.status(400).json({ error: "Missing required fields" });
93
+ }
94
+ if (!manifest.identity || !manifest.identity.name) {
95
+ return res.status(400).json({ error: "Invalid manifest: missing identity.name" });
96
+ }
97
+ const directivesToCommit = manifest.directives?.filter((d) => approvedDirectiveIds.includes(d.id)) || [];
98
+ for (const d of directivesToCommit) {
99
+ if (!d || typeof d.directive !== 'string') {
100
+ return res.status(400).json({ error: "Invalid directive entry: missing directive string" });
101
+ }
102
+ const scan = (0, self_1.scanDirective)(d.directive);
103
+ if (!scan.safe) {
104
+ return res.status(400).json({
105
+ error: `Safety check failed for directive: ${scan.reason}`,
106
+ directiveId: d.id,
107
+ reason: scan.reason,
108
+ });
109
+ }
110
+ }
111
+ const repo = new self_1.SqliteSelfRepository({ dbPath: process.env.STORAGE_PATH || process.env.SQLITE_DB_PATH || 'siduri.sqlite' });
112
+ try {
113
+ await repo.setIdentity({
114
+ companionId,
115
+ name: manifest.identity.name,
116
+ archetype: manifest.identity.archetype,
117
+ version: manifest.version || '1.0.0',
118
+ updatedAt: new Date().toISOString(),
119
+ });
120
+ if (manifest.personality) {
121
+ await repo.setPersonality(companionId, manifest.personality);
122
+ }
123
+ if (directivesToCommit.length > 0) {
124
+ await repo.commitDirectives(companionId, directivesToCommit);
125
+ }
126
+ }
127
+ finally {
128
+ repo.close();
129
+ }
130
+ res.json({ success: true });
131
+ }
132
+ catch (e) {
133
+ res.status(500).json({ error: e.message });
134
+ }
135
+ });
165
136
  // CHAT (API context boundary validation)
166
137
  app.post('/chat', auth_1.attachIdentity, async (req, res) => {
167
138
  const { id, message, history } = req.body;
168
139
  const identity = req.identity;
169
- // Single-owner companion model: map request context directly
140
+ const local = (0, auth_1.isLocalRequest)(req);
141
+ const hasConfiguredToken = Boolean(process.env.AUTH_TOKEN || process.env.OPERATOR_TOKEN || process.env.OWNER_TOKEN);
142
+ const isLocalDirectOwner = local && !hasConfiguredToken;
143
+ const authenticated = identity?.authenticated || isLocalDirectOwner;
144
+ const serverRole = identity?.authenticated ? identity.role : (isLocalDirectOwner ? 'OWNER' : 'VIEWER');
145
+ // Single-owner companion model: map request context directly with server identity enforcement
170
146
  const mappingResult = (0, context_mapper_1.mapRequestContext)({
171
147
  ...req.body,
172
148
  id: id || req.body.companionId,
173
- authenticated: identity?.authenticated ?? true,
174
- source: identity?.source ?? 'local',
149
+ authenticated,
150
+ serverRole,
151
+ source: identity?.source ?? (local ? 'local' : 'external'),
175
152
  generateCorrelationId: true,
176
153
  });
177
154
  if (!mappingResult.accepted) {
@@ -203,11 +180,17 @@ function createApp(runtimes = new Map()) {
203
180
  app.post('/chat/stream', auth_1.attachIdentity, async (req, res) => {
204
181
  const { id, message, history } = req.body;
205
182
  const identity = req.identity;
183
+ const local = (0, auth_1.isLocalRequest)(req);
184
+ const hasConfiguredToken = Boolean(process.env.AUTH_TOKEN || process.env.OPERATOR_TOKEN || process.env.OWNER_TOKEN);
185
+ const isLocalDirectOwner = local && !hasConfiguredToken;
186
+ const authenticated = identity?.authenticated || isLocalDirectOwner;
187
+ const serverRole = identity?.authenticated ? identity.role : (isLocalDirectOwner ? 'OWNER' : 'VIEWER');
206
188
  const mappingResult = (0, context_mapper_1.mapRequestContext)({
207
189
  ...req.body,
208
190
  id: id || req.body.companionId,
209
- authenticated: identity?.authenticated ?? true,
210
- source: identity?.source ?? 'local',
191
+ authenticated,
192
+ serverRole,
193
+ source: identity?.source ?? (local ? 'local' : 'external'),
211
194
  generateCorrelationId: true,
212
195
  });
213
196
  if (!mappingResult.accepted) {
@@ -227,8 +210,8 @@ function createApp(runtimes = new Map()) {
227
210
  const abortController = new AbortController();
228
211
  const onClose = () => {
229
212
  abortController.abort('client_disconnect');
230
- if (typeof runtime.interruptMouth === 'function') {
231
- runtime.interruptMouth('client_disconnect');
213
+ if (runtime.mouth && typeof runtime.mouth.interrupt === 'function') {
214
+ runtime.mouth.interrupt('client_disconnect');
232
215
  }
233
216
  };
234
217
  req.on('close', onClose);
@@ -247,7 +230,9 @@ function createApp(runtimes = new Map()) {
247
230
  if (avatarEvent) {
248
231
  res.write(`event: avatar\ndata: ${JSON.stringify(avatarEvent)}\n\n`);
249
232
  }
250
- const speechText = response.delivery?.text || response.response?.subtitle_en || response.response?.spoken_ja || '';
233
+ const maxStreamLen = Number(process.env.SIDURI_MAX_RESPONSE_CHARS || 8000);
234
+ const rawSpeechText = response.delivery?.text || response.response?.subtitle_en || response.response?.spoken_ja || '';
235
+ const speechText = rawSpeechText.slice(0, maxStreamLen);
251
236
  const utterance = {
252
237
  utteranceId: response.response_id || 'utt-stream',
253
238
  companionId,
@@ -293,11 +278,15 @@ function createApp(runtimes = new Map()) {
293
278
  const runtime = companionId ? runtimes.get(companionId) : undefined;
294
279
  const reason = req.body?.reason || 'user_barge_in';
295
280
  if (runtime) {
296
- runtime.interruptMouth(reason);
281
+ if (runtime.mouth && typeof runtime.mouth.interrupt === 'function') {
282
+ runtime.mouth.interrupt(reason);
283
+ }
297
284
  return res.json({ success: true, interrupted: true, companionId, reason });
298
285
  }
299
286
  for (const r of runtimes.values()) {
300
- r.interruptMouth(reason);
287
+ if (r.mouth && typeof r.mouth.interrupt === 'function') {
288
+ r.mouth.interrupt(reason);
289
+ }
301
290
  }
302
291
  return res.json({ success: true, interrupted: true, reason });
303
292
  });
@@ -306,11 +295,15 @@ function createApp(runtimes = new Map()) {
306
295
  const runtime = companionId ? runtimes.get(companionId) : undefined;
307
296
  const reason = req.body?.reason || 'user_barge_in';
308
297
  if (runtime) {
309
- runtime.interruptMouth(reason);
298
+ if (runtime.mouth && typeof runtime.mouth.interrupt === 'function') {
299
+ runtime.mouth.interrupt(reason);
300
+ }
310
301
  return res.json({ success: true, interrupted: true, companionId, reason });
311
302
  }
312
303
  for (const r of runtimes.values()) {
313
- r.interruptMouth(reason);
304
+ if (r.mouth && typeof r.mouth.interrupt === 'function') {
305
+ r.mouth.interrupt(reason);
306
+ }
314
307
  }
315
308
  return res.json({ success: true, interrupted: true, reason });
316
309
  });
@@ -323,7 +316,7 @@ function createApp(runtimes = new Map()) {
323
316
  if (!runtime.memory)
324
317
  return res.json({ proposals: [] });
325
318
  try {
326
- const proposals = await runtime.getPendingClaims();
319
+ const proposals = await runtime.memory.getPendingClaims();
327
320
  res.json({ proposals });
328
321
  }
329
322
  catch (e) {
@@ -338,7 +331,7 @@ function createApp(runtimes = new Map()) {
338
331
  if (!runtime.memory)
339
332
  return res.json({ items: [] });
340
333
  try {
341
- const items = await runtime.getClaims();
334
+ const items = await runtime.memory.getClaims();
342
335
  res.json({ items });
343
336
  }
344
337
  catch (e) {
@@ -353,7 +346,7 @@ function createApp(runtimes = new Map()) {
353
346
  if (!runtime.memory)
354
347
  return res.json({ claims: [] });
355
348
  try {
356
- const claims = await runtime.getClaims();
349
+ const claims = await runtime.memory.getClaims();
357
350
  res.json({ claims });
358
351
  }
359
352
  catch (e) {
@@ -368,13 +361,101 @@ function createApp(runtimes = new Map()) {
368
361
  if (!runtime.memory)
369
362
  return res.json({ directives: [] });
370
363
  try {
371
- const directives = await runtime.getDirectives();
364
+ const directives = await runtime.memory.getDirectives();
372
365
  res.json({ directives });
373
366
  }
374
367
  catch (e) {
375
368
  res.status(500).json({ error: e.message });
376
369
  }
377
370
  });
371
+ // KNOWLEDGE / LIFE DB GETTERS
372
+ app.get('/knowledge/life', auth_1.requireAuth, async (req, res) => {
373
+ const id = req.query.id || Array.from(runtimes.keys())[0];
374
+ const runtime = runtimes.get(id);
375
+ if (!runtime)
376
+ return res.status(404).json({ error: "Companion not found" });
377
+ const query = req.query.q || '';
378
+ if (!runtime.knowledge || typeof runtime.knowledge.queryLifeContext !== 'function') {
379
+ return res.json({ matchedInventory: [], recentFinances: [], upcomingSchedule: [], preferences: [], formattedContext: '' });
380
+ }
381
+ try {
382
+ const result = await runtime.knowledge.queryLifeContext(id, query);
383
+ res.json(result);
384
+ }
385
+ catch (e) {
386
+ res.status(500).json({ error: e.message });
387
+ }
388
+ });
389
+ app.get('/knowledge/inventory', auth_1.requireAuth, async (req, res) => {
390
+ const id = req.query.id || Array.from(runtimes.keys())[0];
391
+ const runtime = runtimes.get(id);
392
+ if (!runtime)
393
+ return res.status(404).json({ error: "Companion not found" });
394
+ const domain = req.query.domain;
395
+ if (!runtime.knowledge || !runtime.knowledge.inventory) {
396
+ return res.json({ items: [] });
397
+ }
398
+ try {
399
+ const items = await runtime.knowledge.inventory.getItems(id, domain);
400
+ res.json({ items });
401
+ }
402
+ catch (e) {
403
+ res.status(500).json({ error: e.message });
404
+ }
405
+ });
406
+ app.get('/knowledge/finance', auth_1.requireAuth, async (req, res) => {
407
+ const id = req.query.id || Array.from(runtimes.keys())[0];
408
+ const runtime = runtimes.get(id);
409
+ if (!runtime)
410
+ return res.status(404).json({ error: "Companion not found" });
411
+ if (!runtime.knowledge || !runtime.knowledge.finance) {
412
+ return res.json({ summary: null, entries: [] });
413
+ }
414
+ try {
415
+ const limit = Number(req.query.limit || 20);
416
+ const [summary, entries] = await Promise.all([
417
+ runtime.knowledge.finance.getSummary(id),
418
+ runtime.knowledge.finance.getEntries(id, limit),
419
+ ]);
420
+ res.json({ summary, entries });
421
+ }
422
+ catch (e) {
423
+ res.status(500).json({ error: e.message });
424
+ }
425
+ });
426
+ app.get('/knowledge/schedule', auth_1.requireAuth, async (req, res) => {
427
+ const id = req.query.id || Array.from(runtimes.keys())[0];
428
+ const runtime = runtimes.get(id);
429
+ if (!runtime)
430
+ return res.status(404).json({ error: "Companion not found" });
431
+ if (!runtime.knowledge || !runtime.knowledge.schedule) {
432
+ return res.json({ items: [] });
433
+ }
434
+ try {
435
+ const items = await runtime.knowledge.schedule.getUpcoming(id);
436
+ res.json({ items });
437
+ }
438
+ catch (e) {
439
+ res.status(500).json({ error: e.message });
440
+ }
441
+ });
442
+ app.get('/knowledge/preferences', auth_1.requireAuth, async (req, res) => {
443
+ const id = req.query.id || Array.from(runtimes.keys())[0];
444
+ const runtime = runtimes.get(id);
445
+ if (!runtime)
446
+ return res.status(404).json({ error: "Companion not found" });
447
+ const category = req.query.category;
448
+ if (!runtime.knowledge || !runtime.knowledge.preferences) {
449
+ return res.json({ preferences: [] });
450
+ }
451
+ try {
452
+ const preferences = await runtime.knowledge.preferences.getPreferences(id, category);
453
+ res.json({ preferences });
454
+ }
455
+ catch (e) {
456
+ res.status(500).json({ error: e.message });
457
+ }
458
+ });
378
459
  // MEMORY MUTATIONS - PROPOSALS
379
460
  app.post('/memory/proposals/update', auth_1.requireAuth, async (req, res) => {
380
461
  const id = req.body.companionId || Array.from(runtimes.keys())[0];
@@ -389,7 +470,7 @@ function createApp(runtimes = new Map()) {
389
470
  if (!claimId) {
390
471
  return res.status(400).json({ error: "Missing required claim id" });
391
472
  }
392
- const updated = await runtime.updateClaim(claimId, req.body.updates || req.body);
473
+ const updated = await runtime.memory.updateClaim(claimId, req.body.updates || req.body);
393
474
  res.json({ success: true, claim: updated });
394
475
  }
395
476
  catch (e) {
@@ -404,7 +485,7 @@ function createApp(runtimes = new Map()) {
404
485
  if (!runtime.memory)
405
486
  return res.status(400).json({ error: "Memory organ not configured" });
406
487
  try {
407
- await runtime.approveClaim(req.body.id);
488
+ await runtime.memory.approveClaim(req.body.id);
408
489
  res.json({ approved: true });
409
490
  }
410
491
  catch (e) {
@@ -419,7 +500,7 @@ function createApp(runtimes = new Map()) {
419
500
  if (!runtime.memory)
420
501
  return res.status(400).json({ error: "Memory organ not configured" });
421
502
  try {
422
- await runtime.rejectClaim(req.body.id);
503
+ await runtime.memory.rejectClaim(req.body.id);
423
504
  res.json({ rejected: true });
424
505
  }
425
506
  catch (e) {
@@ -435,7 +516,7 @@ function createApp(runtimes = new Map()) {
435
516
  if (!runtime.memory)
436
517
  return res.status(400).json({ error: "Memory organ not configured" });
437
518
  try {
438
- await runtime.approveDirective(req.body.id);
519
+ await runtime.memory.approveDirective(req.body.id);
439
520
  res.json({ approved: true });
440
521
  }
441
522
  catch (e) {
@@ -450,7 +531,7 @@ function createApp(runtimes = new Map()) {
450
531
  if (!runtime.memory)
451
532
  return res.status(400).json({ error: "Memory organ not configured" });
452
533
  try {
453
- await runtime.rejectDirective(req.body.id);
534
+ await runtime.memory.rejectDirective(req.body.id);
454
535
  res.json({ rejected: true });
455
536
  }
456
537
  catch (e) {
@@ -465,7 +546,7 @@ function createApp(runtimes = new Map()) {
465
546
  if (!runtime.memory)
466
547
  return res.status(400).json({ error: "Memory organ not configured" });
467
548
  try {
468
- await runtime.revokeDirective(req.body.id);
549
+ await runtime.memory.revokeDirective(req.body.id);
469
550
  res.json({ revoked: true });
470
551
  }
471
552
  catch (e) {
@@ -480,7 +561,7 @@ function createApp(runtimes = new Map()) {
480
561
  if (!runtime.memory)
481
562
  return res.status(400).json({ error: "Memory organ not configured" });
482
563
  try {
483
- await runtime.disableDirective(req.body.id);
564
+ await runtime.memory.disableDirective(req.body.id);
484
565
  res.json({ disabled: true });
485
566
  }
486
567
  catch (e) {
@@ -498,7 +579,7 @@ function createApp(runtimes = new Map()) {
498
579
  return res.status(400).json({ error: "Memory organ does not support reset" });
499
580
  }
500
581
  try {
501
- await runtime.resetMemory();
582
+ await runtime.memory.resetMemory();
502
583
  res.json({ reset: true });
503
584
  }
504
585
  catch (e) {
@@ -510,7 +591,7 @@ function createApp(runtimes = new Map()) {
510
591
  const runtime = runtimes.get(companionId);
511
592
  if (!runtime)
512
593
  return res.status(404).json({ accepted: false, error: 'Companion not found' });
513
- const staged = runtime.stageResponse({
594
+ const staged = runtime.gating.stageResponse({
514
595
  requestContext: {
515
596
  companionId,
516
597
  actor: {
@@ -544,13 +625,13 @@ function createApp(runtimes = new Map()) {
544
625
  let responseId = req.body?.responseId;
545
626
  let correlationId = req.body?.correlation_id;
546
627
  if (!responseId && correlationId) {
547
- const found = runtime.findStagedPlanByCorrelation(companionId, correlationId);
628
+ const found = runtime.gating.findStagedPlanByCorrelation(companionId, correlationId);
548
629
  if (found) {
549
630
  responseId = found.responseId;
550
631
  }
551
632
  }
552
633
  else if (responseId && !correlationId) {
553
- const found = runtime.getStagedPlan(responseId);
634
+ const found = runtime.gating.getStagedPlan(responseId);
554
635
  if (found) {
555
636
  correlationId = found.correlationId;
556
637
  }
@@ -558,7 +639,7 @@ function createApp(runtimes = new Map()) {
558
639
  if (!responseId) {
559
640
  return res.status(400).json({ approved: false, error: 'UNKNOWN_APPROVAL_ID' });
560
641
  }
561
- const result = runtime.approveResponse({
642
+ const result = runtime.gating.approveResponse({
562
643
  responseId,
563
644
  companionId,
564
645
  correlationId: correlationId || '',
@@ -567,7 +648,7 @@ function createApp(runtimes = new Map()) {
567
648
  return res.status(400).json({ approved: false, error: result.reason });
568
649
  }
569
650
  // Now evaluated as approved
570
- const evaluation = runtime.evaluateGate(result.plan);
651
+ const evaluation = runtime.gating.evaluateGate(result.plan);
571
652
  res.json({
572
653
  approved: true,
573
654
  status: evaluation.disposition,
@@ -584,13 +665,13 @@ function createApp(runtimes = new Map()) {
584
665
  let responseId = req.body?.responseId;
585
666
  let correlationId = req.body?.correlation_id;
586
667
  if (!responseId && correlationId) {
587
- const found = runtime.findStagedPlanByCorrelation(companionId, correlationId);
668
+ const found = runtime.gating.findStagedPlanByCorrelation(companionId, correlationId);
588
669
  if (found) {
589
670
  responseId = found.responseId;
590
671
  }
591
672
  }
592
673
  else if (responseId && !correlationId) {
593
- const found = runtime.getStagedPlan(responseId);
674
+ const found = runtime.gating.getStagedPlan(responseId);
594
675
  if (found) {
595
676
  correlationId = found.correlationId;
596
677
  }
@@ -598,7 +679,7 @@ function createApp(runtimes = new Map()) {
598
679
  if (!responseId) {
599
680
  return res.status(400).json({ rejected: false, error: 'UNKNOWN_APPROVAL_ID' });
600
681
  }
601
- const result = runtime.rejectResponse({
682
+ const result = runtime.gating.rejectResponse({
602
683
  responseId,
603
684
  companionId,
604
685
  correlationId: correlationId || '',
@@ -41,7 +41,7 @@ describe('T0 B0 & B6 Runtime Proof Suite', () => {
41
41
  const config = {
42
42
  name: 'NeutralCompanion',
43
43
  brain: { provider: 'openrouter' },
44
- memory: { provider: 'postgres' },
44
+ memory: { provider: 'sqlite' },
45
45
  knowledge: { provider: 'e-knowledge' },
46
46
  behavior: { provider: 'active-self' },
47
47
  voice: { provider: 'none' },