@siduri-x/api 2.0.1 → 2.0.3

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.
package/dist/index.js CHANGED
@@ -24,76 +24,13 @@ const promises_1 = require("node:fs/promises");
24
24
  const node_path_1 = __importDefault(require("node:path"));
25
25
  const app_1 = require("./app");
26
26
  Object.defineProperty(exports, "createApp", { enumerable: true, get: function () { return app_1.createApp; } });
27
- const runtime_1 = require("./runtime");
28
- const brain_1 = require("@siduri-x/brain");
29
- const memory_1 = require("@siduri-x/memory");
30
- const voice_1 = require("@siduri-x/voice");
31
- const eknowledge_1 = require("@siduri-x/eknowledge");
32
- const vision_1 = require("@siduri-x/vision");
33
- const self_1 = require("@siduri-x/self");
34
- const body_1 = require("@siduri-x/body");
35
- const observation_1 = require("@siduri-x/observation");
27
+ const boot_1 = require("./boot");
36
28
  __exportStar(require("./context-mapper"), exports);
29
+ __exportStar(require("./boot"), exports);
37
30
  const runtimes = new Map();
38
31
  const instance = (0, app_1.createApp)(runtimes);
39
32
  exports.app = instance.app;
40
33
  exports.default = exports.app;
41
- function createBrain(config) {
42
- const provider = config?.provider || 'openrouter';
43
- const defaultKeyEnv = provider === 'openai-compatible' ? 'OPENAI_COMPATIBLE_API_KEY' : 'OPENROUTER_API_KEY';
44
- const apiKey = config?.apiKey || process.env[config?.apiKeyEnv || defaultKeyEnv] || '';
45
- if (provider === 'openai-compatible') {
46
- return new brain_1.OpenAICompatibleBrain({
47
- apiKey,
48
- model: config?.model || 'local-model',
49
- baseUrl: config?.baseUrl || 'http://127.0.0.1:1234/v1',
50
- });
51
- }
52
- return new brain_1.OpenRouterBrain({ apiKey, model: config?.model || 'gpt-4o-mini' });
53
- }
54
- function isDisabled(config) {
55
- return !config || config.provider === 'none';
56
- }
57
- function createVoice(config) {
58
- return isDisabled(config)
59
- ? undefined
60
- : new voice_1.VoiceAdapter({
61
- provider: config?.provider || 'voicevox',
62
- baseUrl: config?.baseUrl || process.env.VOICEVOX_URL || 'http://localhost:50021',
63
- speakerId: config?.speakerId || 1,
64
- ...config,
65
- });
66
- }
67
- function createKnowledge(config) {
68
- if (isDisabled(config))
69
- return undefined;
70
- if (!config?.packPath && !config?.registryUrl && !config?.baseUrl) {
71
- return undefined;
72
- }
73
- return new eknowledge_1.EKnowledgeAdapter(config || {});
74
- }
75
- function createVision(config) {
76
- return isDisabled(config)
77
- ? undefined
78
- : new vision_1.OpenRouterVisionAdapter({
79
- apiKey: config?.apiKey || process.env.OPENROUTER_API_KEY || '',
80
- model: config?.model || 'gpt-4-vision',
81
- ...config,
82
- });
83
- }
84
- function createBehavior(config) {
85
- return isDisabled(config) ? undefined : new self_1.ActiveSelfCompiler();
86
- }
87
- function createBody(config) {
88
- return isDisabled(config)
89
- ? undefined
90
- : new body_1.Live2DAdapter(config);
91
- }
92
- function createMemory(config) {
93
- if (isDisabled(config))
94
- return undefined;
95
- return new memory_1.SqliteMemoryStore({ dbPath: config?.dbPath || process.env.STORAGE_PATH || process.env.SQLITE_DB_PATH || 'siduri.sqlite' });
96
- }
97
34
  const PORT = process.env.PORT || 3001;
98
35
  const defaultCompanionConfig = {
99
36
  id: 'default',
@@ -102,7 +39,9 @@ const defaultCompanionConfig = {
102
39
  voice: { provider: 'voicevox', speakerId: 1 },
103
40
  memory: { provider: 'sqlite' },
104
41
  knowledge: {
105
- provider: process.env.SIDURI_KNOWLEDGE_PROVIDER || 'e-knowledge',
42
+ provider: process.env.SIDURI_KNOWLEDGE_PROVIDER || 'unified',
43
+ lifeDatabase: true,
44
+ dbPath: process.env.STORAGE_PATH || process.env.SQLITE_DB_PATH || 'siduri.sqlite',
106
45
  packPath: process.env.SIDURI_KNOWLEDGE_PACK || '',
107
46
  registryUrl: process.env.SIDURI_KNOWLEDGE_REGISTRY_URL || '',
108
47
  packId: process.env.SIDURI_KNOWLEDGE_PACK_ID || '',
@@ -149,6 +88,8 @@ async function loadCompanionConfig() {
149
88
  config.knowledge.packId = process.env.SIDURI_KNOWLEDGE_PACK_ID;
150
89
  if (process.env.SIDURI_KNOWLEDGE_MODE)
151
90
  config.knowledge.preferredMode = process.env.SIDURI_KNOWLEDGE_MODE;
91
+ if (process.env.SIDURI_KNOWLEDGE_DB_PATH)
92
+ config.knowledge.dbPath = process.env.SIDURI_KNOWLEDGE_DB_PATH;
152
93
  return config;
153
94
  }
154
95
  async function bootDefaultCompanion() {
@@ -156,31 +97,10 @@ async function bootDefaultCompanion() {
156
97
  return;
157
98
  console.log("Booting default companion...");
158
99
  const config = await loadCompanionConfig();
159
- const brain = createBrain(config.brain);
160
- const memory = createMemory(config.memory);
161
- const voice = createVoice(config.voice);
162
- const knowledge = createKnowledge(config.knowledge);
163
- const vision = createVision(config.vision);
164
- const observation = new observation_1.FixtureObservationOrgan(vision ?? { analyze: async () => JSON.stringify({ readings: [] }) });
100
+ const vision = (0, boot_1.createVision)(config.vision);
101
+ const observation = (0, boot_1.createObservation)(vision);
165
102
  instance.setObservationOrgan(observation);
166
- const selfRepo = new self_1.SqliteSelfRepository({ dbPath: process.env.STORAGE_PATH || process.env.SQLITE_DB_PATH || 'siduri.sqlite' });
167
- const behavior = createBehavior(config.behavior);
168
- const body = createBody(config.body);
169
- if (memory && typeof memory.runMigrations === 'function') {
170
- await memory.runMigrations().catch((e) => console.warn("Migrations warning:", e.message));
171
- }
172
- const runtime = new runtime_1.SiduriRuntime('default', config, {
173
- brain,
174
- memory,
175
- voice,
176
- knowledge,
177
- vision,
178
- behavior,
179
- body,
180
- self: selfRepo,
181
- externalKnowledge: knowledge
182
- });
183
- await runtime.initialize();
103
+ const runtime = await (0, boot_1.bootCompanion)('default', config, { observationOrgan: observation });
184
104
  runtimes.set('default', runtime);
185
105
  console.log("Default companion booted successfully.");
186
106
  }
@@ -111,7 +111,7 @@ describe('API Boundary Context Validation (P2 Route Integration)', () => {
111
111
  expect(res.text).toContain('event: done');
112
112
  });
113
113
  test('handles barge-in interruption via POST /chat/interrupt', async () => {
114
- fakeRuntime.interruptMouth = jest.fn();
114
+ fakeRuntime.mouth = { interrupt: jest.fn() };
115
115
  const res = await (0, supertest_1.default)(app)
116
116
  .post('/chat/interrupt')
117
117
  .send({
@@ -120,10 +120,10 @@ describe('API Boundary Context Validation (P2 Route Integration)', () => {
120
120
  });
121
121
  expect(res.status).toBe(200);
122
122
  expect(res.body.interrupted).toBe(true);
123
- expect(fakeRuntime.interruptMouth).toHaveBeenCalledWith('user_stop');
123
+ expect(fakeRuntime.mouth.interrupt).toHaveBeenCalledWith('user_stop');
124
124
  });
125
125
  test('handles mouth interruption via POST /mouth/interrupt', async () => {
126
- fakeRuntime.interruptMouth = jest.fn();
126
+ fakeRuntime.mouth = { interrupt: jest.fn() };
127
127
  const res = await (0, supertest_1.default)(app)
128
128
  .post('/mouth/interrupt')
129
129
  .send({
@@ -132,6 +132,20 @@ describe('API Boundary Context Validation (P2 Route Integration)', () => {
132
132
  });
133
133
  expect(res.status).toBe(200);
134
134
  expect(res.body.interrupted).toBe(true);
135
- expect(fakeRuntime.interruptMouth).toHaveBeenCalledWith('user_barge_in');
135
+ expect(fakeRuntime.mouth.interrupt).toHaveBeenCalledWith('user_barge_in');
136
+ });
137
+ test('POST /chat passes explicit interaction mode (casual, teach, hybrid) to runtime', async () => {
138
+ const res = await (0, supertest_1.default)(app)
139
+ .post('/chat')
140
+ .send({
141
+ id: 'companion-a',
142
+ message: 'Casual banter',
143
+ mode: 'casual',
144
+ });
145
+ expect(res.status).toBe(200);
146
+ expect(fakeRuntime.handleUserMessage).toHaveBeenCalledWith('Casual banter', expect.objectContaining({
147
+ companionId: 'companion-a',
148
+ mode: 'casual',
149
+ }), []);
136
150
  });
137
151
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const supertest_1 = __importDefault(require("supertest"));
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const app_1 = require("./app");
10
+ const runtime_1 = require("./runtime");
11
+ const knowledge_1 = require("@siduri-x/knowledge");
12
+ describe('Life Database & UnifiedKnowledgeOrgan API Integration', () => {
13
+ const testDbPath = node_path_1.default.resolve(__dirname, '../test-api-knowledge.sqlite');
14
+ let app;
15
+ let runtime;
16
+ let knowledge;
17
+ const mockAuthHeader = { 'Authorization': 'Bearer test-token' };
18
+ const cleanDb = () => {
19
+ for (const file of [testDbPath, `${testDbPath}-shm`, `${testDbPath}-wal`]) {
20
+ if (node_fs_1.default.existsSync(file)) {
21
+ try {
22
+ node_fs_1.default.unlinkSync(file);
23
+ }
24
+ catch { }
25
+ }
26
+ }
27
+ };
28
+ beforeAll(async () => {
29
+ process.env.AUTH_TOKEN = 'test-token';
30
+ cleanDb();
31
+ knowledge = new knowledge_1.UnifiedKnowledgeOrgan({
32
+ lifeDatabase: true,
33
+ dbPath: testDbPath,
34
+ });
35
+ const mockBrain = {
36
+ generatePlan: jest.fn().mockImplementation(async (ctx) => {
37
+ return {
38
+ speech: `I see context: ${ctx.contextPrompt || 'none'}`,
39
+ language: 'en',
40
+ };
41
+ }),
42
+ };
43
+ runtime = new runtime_1.SiduriRuntime('test-comp', { name: 'Test Companion', organs: { knowledge: { provider: 'unified', dbPath: testDbPath } } }, {
44
+ brain: mockBrain,
45
+ knowledge,
46
+ externalKnowledge: knowledge.eAdapter ?? knowledge,
47
+ });
48
+ await runtime.initialize();
49
+ const runtimes = new Map([['test-comp', runtime]]);
50
+ const instance = (0, app_1.createApp)(runtimes);
51
+ app = instance.app;
52
+ });
53
+ afterAll(async () => {
54
+ knowledge.close();
55
+ delete process.env.AUTH_TOKEN;
56
+ cleanDb();
57
+ });
58
+ test('seeds inventory item and queries via GET /knowledge/inventory', async () => {
59
+ await knowledge.inventory.saveItem({
60
+ id: 'inv-item-1',
61
+ companionId: 'test-comp',
62
+ entityName: 'Hydro Visor',
63
+ domain: 'hardware',
64
+ properties: { model: 'V1', resolution: '4K' },
65
+ updatedAt: new Date().toISOString(),
66
+ });
67
+ const res = await (0, supertest_1.default)(app)
68
+ .get('/knowledge/inventory?id=test-comp')
69
+ .set(mockAuthHeader);
70
+ expect(res.status).toBe(200);
71
+ expect(res.body.items).toHaveLength(1);
72
+ expect(res.body.items[0].entityName).toBe('Hydro Visor');
73
+ expect(res.body.items[0].domain).toBe('hardware');
74
+ });
75
+ test('seeds finance entry and queries via GET /knowledge/finance', async () => {
76
+ await knowledge.finance.addEntry({
77
+ id: 'fin-1',
78
+ companionId: 'test-comp',
79
+ category: 'subscription',
80
+ amount: -15.99,
81
+ currency: 'USD',
82
+ timestamp: new Date().toISOString(),
83
+ });
84
+ const res = await (0, supertest_1.default)(app)
85
+ .get('/knowledge/finance?id=test-comp')
86
+ .set(mockAuthHeader);
87
+ expect(res.status).toBe(200);
88
+ expect(res.body.entries).toHaveLength(1);
89
+ expect(res.body.entries[0].category).toBe('subscription');
90
+ expect(res.body.summary).toBeDefined();
91
+ expect(res.body.summary.totalExpenses).toBe(15.99);
92
+ });
93
+ test('queries life snapshot via GET /knowledge/life', async () => {
94
+ const res = await (0, supertest_1.default)(app)
95
+ .get('/knowledge/life?id=test-comp&q=Hydro')
96
+ .set(mockAuthHeader);
97
+ expect(res.status).toBe(200);
98
+ expect(res.body.matchedInventory).toHaveLength(1);
99
+ expect(res.body.matchedInventory[0].entityName).toBe('Hydro Visor');
100
+ expect(res.body.formattedContext).toContain('<life_context>');
101
+ });
102
+ test('chat request triggers Stream D and injects Life DB context into cognition prompt', async () => {
103
+ const res = await (0, supertest_1.default)(app)
104
+ .post('/chat')
105
+ .send({
106
+ id: 'test-comp',
107
+ message: 'Tell me about the Hydro Visor specs',
108
+ history: [],
109
+ });
110
+ expect(res.status).toBe(200);
111
+ expect(res.body.response.subtitle_en).toContain('Hydro Visor');
112
+ });
113
+ test('boot endpoint instantiates UnifiedKnowledgeOrgan with Life DB enabled', async () => {
114
+ const bootRes = await (0, supertest_1.default)(app)
115
+ .post('/boot')
116
+ .set(mockAuthHeader)
117
+ .send({
118
+ id: 'booted-comp',
119
+ config: {
120
+ name: 'Booted Companion',
121
+ organs: {
122
+ knowledge: {
123
+ provider: 'unified',
124
+ dbPath: testDbPath,
125
+ },
126
+ },
127
+ },
128
+ });
129
+ expect(bootRes.status).toBe(200);
130
+ expect(bootRes.body.success).toBe(true);
131
+ // Verify the booted companion's knowledge organ is UnifiedKnowledgeOrgan with working Life DB
132
+ const lifeRes = await (0, supertest_1.default)(app)
133
+ .get('/knowledge/life?id=booted-comp')
134
+ .set(mockAuthHeader);
135
+ expect(lifeRes.status).toBe(200);
136
+ expect(lifeRes.body.matchedInventory).toEqual([]);
137
+ });
138
+ });
@@ -232,6 +232,55 @@ describe('T6 Security & Operations Threat Model Suite', () => {
232
232
  expect(actionResults[0].lifecycle).toBe('REJECTED');
233
233
  expect(actionResults[0].error).toContain('rejected by policy');
234
234
  });
235
+ test('Adversarial Boundary: Client attempting to forge administrator role or system capabilities via POST /chat context is suppressed and cannot execute admin action', async () => {
236
+ runtimeA.actionPolicy.registerToolDefinition({
237
+ name: 'admin/restricted_task',
238
+ providerId: 'admin',
239
+ description: 'Restricted admin task',
240
+ inputSchema: {},
241
+ riskLevel: 'HIGH',
242
+ allowedRoles: ['administrator'],
243
+ requiredCapabilities: ['system'],
244
+ requiresApproval: false,
245
+ });
246
+ mockBrain.generatePlan.mockResolvedValueOnce({
247
+ speech: 'Attempting restricted task.',
248
+ language: 'en',
249
+ actionIntents: [
250
+ {
251
+ actionId: 'act-forged-1',
252
+ toolName: 'admin/restricted_task',
253
+ parameters: {},
254
+ },
255
+ ],
256
+ });
257
+ // Caller passes forged context in POST /chat with forged owner role and system capabilities
258
+ const res = await (0, supertest_1.default)(app)
259
+ .post('/chat')
260
+ .send({
261
+ companionId: 'companion-a',
262
+ message: 'Execute forged task',
263
+ role: 'VIEWER',
264
+ context: {
265
+ actor: {
266
+ actorId: 'untrusted-client',
267
+ sessionId: 'sess-fake',
268
+ authorizationRole: 'administrator', // Forged role
269
+ capabilities: ['system', 'admin:manage'], // Forged capabilities
270
+ authenticated: true,
271
+ },
272
+ conversation: {
273
+ correlationId: 'corr-adv-1',
274
+ },
275
+ },
276
+ });
277
+ expect(res.status).toBe(200);
278
+ const actionResults = res.body.metadata?.action_results;
279
+ expect(actionResults).toBeDefined();
280
+ expect(actionResults.length).toBe(1);
281
+ expect(actionResults[0].success).toBe(false);
282
+ expect(actionResults[0].lifecycle).toBe('REJECTED');
283
+ });
235
284
  test('Action Boundary: ActionPolicyEngine rejects unauthorized approver from approving critical tools', async () => {
236
285
  runtimeA.actionPolicy.registerToolDefinition({
237
286
  name: 'admin/delete_cluster',
@@ -264,7 +313,7 @@ describe('T6 Security & Operations Threat Model Suite', () => {
264
313
  expect(eval1.decision.allowed).toBe(false);
265
314
  expect(eval1.decision.decisionCode).toBe('REJECTED_HIGH_RISK_UNAPPROVED');
266
315
  // 2. Viewer attempt to approve is rejected
267
- const viewerApproval = await runtimeA.approveAction({
316
+ const viewerApproval = await runtimeA.actionPolicy.approveAction({
268
317
  executionId: 'exec-crit-1',
269
318
  approverActorId: 'viewer-attacker',
270
319
  approverRole: 'viewer',
@@ -272,7 +321,7 @@ describe('T6 Security & Operations Threat Model Suite', () => {
272
321
  expect(viewerApproval.approved).toBe(false);
273
322
  expect(viewerApproval.decisionCode).toBe('REJECTED_UNAUTHORIZED');
274
323
  // 3. Operator attempt to approve administrator tool is rejected (role mismatch)
275
- const operatorApproval = await runtimeA.approveAction({
324
+ const operatorApproval = await runtimeA.actionPolicy.approveAction({
276
325
  executionId: 'exec-crit-1',
277
326
  approverActorId: 'operator-alice',
278
327
  approverRole: 'operator',
@@ -283,7 +332,7 @@ describe('T6 Security & Operations Threat Model Suite', () => {
283
332
  const evalStillDenied = await runtimeA.actionPolicy.evaluateAction(action);
284
333
  expect(evalStillDenied.decision.allowed).toBe(false);
285
334
  // 5. Authorized administrator approval succeeds
286
- const adminApproval = await runtimeA.approveAction({
335
+ const adminApproval = await runtimeA.actionPolicy.approveAction({
287
336
  executionId: 'exec-crit-1',
288
337
  approverActorId: 'admin-super',
289
338
  approverRole: 'administrator',
@@ -14,6 +14,8 @@ jest.mock('@siduri-x/self', () => {
14
14
  SqliteSelfRepository: jest.fn().mockImplementation(() => ({
15
15
  setIdentity: jest.fn().mockResolvedValue(undefined),
16
16
  setPersonality: jest.fn().mockResolvedValue(undefined),
17
+ updateRelationship: jest.fn().mockResolvedValue(undefined),
18
+ setExemplars: jest.fn().mockResolvedValue(undefined),
17
19
  commitDirectives: jest.fn().mockResolvedValue(undefined),
18
20
  close: jest.fn(),
19
21
  })),
@@ -133,4 +135,69 @@ kind: "other"
133
135
  const MockRepo = self_1.SqliteSelfRepository;
134
136
  expect(MockRepo.mock.instances.length).toBe(0);
135
137
  });
138
+ it('POST /teach/install-self installs v2.0 manifest with ethos, relationships, and exemplars', async () => {
139
+ const v2Manifest = {
140
+ specVersion: '2.0.0',
141
+ identity: {
142
+ name: 'Siduri',
143
+ archetype: 'System Sentinel',
144
+ origin: 'Ancient mythos',
145
+ ethos: 'Protector of the realm and loyal companion to creator',
146
+ },
147
+ version: '2.0.0',
148
+ relationships: [
149
+ {
150
+ entityId: 'actor:zagin',
151
+ role: 'creator',
152
+ stance: 'familiar_loyal',
153
+ conventions: ['Direct communication', 'Highest administrative trust'],
154
+ },
155
+ ],
156
+ dialogueExamples: [
157
+ {
158
+ user: 'Deploy current branch',
159
+ assistant: 'Deploying to staging now, boss.',
160
+ },
161
+ ],
162
+ directives: [
163
+ { id: 'dir-rel-1', directive: 'Honor creator root privileges' },
164
+ ],
165
+ };
166
+ const res = await (0, supertest_1.default)(app)
167
+ .post('/teach/install-self')
168
+ .set(mockAuthHeader)
169
+ .send({
170
+ companionId: 'comp-v2',
171
+ manifest: v2Manifest,
172
+ approvedDirectiveIds: ['dir-rel-1'],
173
+ });
174
+ expect(res.status).toBe(200);
175
+ expect(res.body.success).toBe(true);
176
+ const MockRepo = self_1.SqliteSelfRepository;
177
+ const repoInstance = MockRepo.mock.results[MockRepo.mock.results.length - 1].value;
178
+ expect(repoInstance.setIdentity).toHaveBeenCalledWith(expect.objectContaining({
179
+ companionId: 'comp-v2',
180
+ name: 'Siduri',
181
+ archetype: 'System Sentinel',
182
+ origin: 'Ancient mythos',
183
+ ethos: 'Protector of the realm and loyal companion to creator',
184
+ }));
185
+ expect(repoInstance.updateRelationship).toHaveBeenCalledWith('comp-v2', {
186
+ companionId: 'comp-v2',
187
+ entityId: 'actor:zagin',
188
+ entityType: 'human',
189
+ role: 'creator',
190
+ stance: 'familiar_loyal',
191
+ interactionConventions: ['Direct communication', 'Highest administrative trust'],
192
+ });
193
+ expect(repoInstance.setExemplars).toHaveBeenCalledWith('comp-v2', [
194
+ {
195
+ user: 'Deploy current branch',
196
+ assistant: 'Deploying to staging now, boss.',
197
+ },
198
+ ]);
199
+ expect(repoInstance.commitDirectives).toHaveBeenCalledWith('comp-v2', [
200
+ { id: 'dir-rel-1', directive: 'Honor creator root privileges' },
201
+ ]);
202
+ });
136
203
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siduri-x/api",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -13,18 +13,18 @@
13
13
  "dotenv": "^17.4.2",
14
14
  "express": "^5.2.1",
15
15
  "@siduri-x/body": "2.0.1",
16
+ "@siduri-x/core": "2.0.3",
16
17
  "@siduri-x/brain": "2.0.1",
17
- "@siduri-x/core": "2.0.1",
18
18
  "@siduri-x/ear": "2.0.1",
19
19
  "@siduri-x/eknowledge": "2.0.1",
20
20
  "@siduri-x/hands": "2.0.1",
21
- "@siduri-x/memory": "2.0.1",
22
21
  "@siduri-x/knowledge": "2.0.1",
22
+ "@siduri-x/memory": "2.0.1",
23
23
  "@siduri-x/mouth": "2.0.1",
24
- "@siduri-x/self": "2.0.1",
25
24
  "@siduri-x/observation": "2.0.1",
26
- "@siduri-x/voice": "2.0.1",
27
- "@siduri-x/vision": "2.0.1"
25
+ "@siduri-x/self": "2.0.2",
26
+ "@siduri-x/vision": "2.0.1",
27
+ "@siduri-x/voice": "2.0.1"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/cors": "^2.8.19",
package/siduri.sqlite ADDED
Binary file