@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.
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +43 -0
- package/dist/app.d.ts +2 -34
- package/dist/app.js +208 -127
- package/dist/b0-b6.test.js +1 -1
- package/dist/boot.d.ts +92 -0
- package/dist/boot.js +146 -0
- package/dist/boot.test.d.ts +1 -0
- package/dist/boot.test.js +84 -0
- package/dist/context-mapper.d.ts +3 -1
- package/dist/context-mapper.js +84 -13
- package/dist/context-mapper.test.js +116 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +13 -88
- package/dist/index.test.js +4 -4
- package/dist/knowledge.test.d.ts +1 -0
- package/dist/knowledge.test.js +138 -0
- package/dist/t4-gating.test.js +1 -1
- package/dist/t5-experience.test.js +1 -1
- package/dist/t6-security.test.js +115 -3
- package/dist/t7-release.test.js +1 -1
- package/dist/teach-mode.test.d.ts +1 -0
- package/dist/teach-mode.test.js +136 -0
- package/package.json +27 -23
- package/src/app.ts +223 -170
- package/src/b0-b6.test.ts +1 -1
- package/src/boot.test.ts +103 -0
- package/src/boot.ts +190 -0
- package/src/context-mapper.test.ts +127 -0
- package/src/context-mapper.ts +94 -13
- package/src/index.test.ts +4 -4
- package/src/index.ts +14 -99
- package/src/knowledge.test.ts +156 -0
- package/src/t4-gating.test.ts +1 -1
- package/src/t5-experience.test.ts +1 -1
- package/src/t6-security.test.ts +126 -2
- package/src/t7-release.test.ts +1 -1
- package/src/teach-mode.test.ts +152 -0
|
@@ -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
|
+
[999D[K
|
|
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 {
|
|
9
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
174
|
-
|
|
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
|
|
210
|
-
|
|
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.
|
|
231
|
-
runtime.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 || '',
|
package/dist/b0-b6.test.js
CHANGED
|
@@ -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: '
|
|
44
|
+
memory: { provider: 'sqlite' },
|
|
45
45
|
knowledge: { provider: 'e-knowledge' },
|
|
46
46
|
behavior: { provider: 'active-self' },
|
|
47
47
|
voice: { provider: 'none' },
|