@vxnus/siduri 0.1.7 → 0.1.10
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/builtin-manifests.js +32 -4
- package/dist/clean-machine-e2e.test.js +29 -23
- package/dist/configurators/index.d.ts +1 -0
- package/dist/configurators/index.js +4 -0
- package/dist/configurators/mouth.d.ts +2 -0
- package/dist/configurators/mouth.js +15 -0
- package/dist/configurators/voice.js +116 -2
- package/dist/configurators.test.js +32 -0
- package/dist/discovery.test.js +5 -3
- package/dist/generator.js +126 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/release-check.js +14 -12
- package/dist/web-template.js +2 -1
- package/package.json +1 -1
- package/dist/web-dist/404/index.html +0 -1
- package/dist/web-dist/404.html +0 -1
- package/dist/web-dist/__next.__PAGE__.txt +0 -34
- package/dist/web-dist/__next._full.txt +0 -31
- package/dist/web-dist/__next._tree.txt +0 -3
- package/dist/web-dist/_next/static/chunks/0bncolc2nuzmo.css +0 -1
- package/dist/web-dist/_next/static/chunks/0cz1d0mv5g_q7.js +0 -1
- package/dist/web-dist/_next/static/chunks/0uwih7sydv413.js +0 -1
- package/dist/web-dist/_next/static/chunks/0xe6aaej0xsj8.js +0 -30
- package/dist/web-dist/_next/static/chunks/10rmct1ax-opq.js +0 -1
- package/dist/web-dist/_next/static/chunks/1_yae15ffa5f6.js +0 -1
- package/dist/web-dist/_next/static/chunks/2kcqevsmv6kh2.js +0 -31
- package/dist/web-dist/_next/static/chunks/2s3d1bfr0l4b0.js +0 -1
- package/dist/web-dist/_next/static/chunks/32z87id9k6i2z.js +0 -22
- package/dist/web-dist/_next/static/chunks/3bx2gs3idjmo1.js +0 -1
- package/dist/web-dist/_next/static/chunks/turbopack-3eipe4c-imn5l.js +0 -1
- package/dist/web-dist/_next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- package/dist/web-dist/_next/static/uvsK8ULhL7fHQMR8sr_JL/_buildManifest.js +0 -11
- package/dist/web-dist/_next/static/uvsK8ULhL7fHQMR8sr_JL/_clientMiddlewareManifest.js +0 -1
- package/dist/web-dist/_next/static/uvsK8ULhL7fHQMR8sr_JL/_ssgManifest.js +0 -1
- package/dist/web-dist/_not-found/__next._full.txt +0 -17
- package/dist/web-dist/_not-found/__next._not-found.__PAGE__.txt +0 -23
- package/dist/web-dist/_not-found/__next._tree.txt +0 -3
- package/dist/web-dist/_not-found/index.html +0 -1
- package/dist/web-dist/_not-found/index.txt +0 -17
- package/dist/web-dist/chat/__next._full.txt +0 -18
- package/dist/web-dist/chat/__next._tree.txt +0 -3
- package/dist/web-dist/chat/__next.chat.__PAGE__.txt +0 -24
- package/dist/web-dist/chat/index.html +0 -1
- package/dist/web-dist/chat/index.txt +0 -18
- package/dist/web-dist/favicon.ico +0 -0
- package/dist/web-dist/index.html +0 -1
- package/dist/web-dist/index.txt +0 -31
- package/dist/web-dist/live2d/live2dcubismcore.min.js +0 -9
- package/dist/web-dist/operator/__next._full.txt +0 -18
- package/dist/web-dist/operator/__next._tree.txt +0 -3
- package/dist/web-dist/operator/__next.operator.__PAGE__.txt +0 -24
- package/dist/web-dist/operator/index.html +0 -1
- package/dist/web-dist/operator/index.txt +0 -18
|
@@ -5,7 +5,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
5
5
|
{
|
|
6
6
|
name: '@siduri-x/behavior',
|
|
7
7
|
organType: 'behavior',
|
|
8
|
-
version: '1.0.
|
|
8
|
+
version: '1.0.6',
|
|
9
9
|
displayName: 'Behavior (Active Self Directives)',
|
|
10
10
|
description: 'Atomic directive state machine and personality projection compiler',
|
|
11
11
|
entrypoint: './dist/index.js',
|
|
@@ -66,7 +66,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
66
66
|
{
|
|
67
67
|
name: '@siduri-x/brain',
|
|
68
68
|
organType: 'brain',
|
|
69
|
-
version: '1.0.
|
|
69
|
+
version: '1.0.5',
|
|
70
70
|
displayName: 'Brain (Cognition & Planning)',
|
|
71
71
|
description: 'Provider-neutral LLM reasoning, response planning, and proposal generation',
|
|
72
72
|
entrypoint: './dist/index.js',
|
|
@@ -272,7 +272,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
272
272
|
{
|
|
273
273
|
name: '@siduri-x/memory',
|
|
274
274
|
organType: 'memory',
|
|
275
|
-
version: '1.0.
|
|
275
|
+
version: '1.0.6',
|
|
276
276
|
displayName: 'Memory (PostgreSQL FTS Claims)',
|
|
277
277
|
description: 'Relational semantic claims with Full-Text Search and companion isolation',
|
|
278
278
|
entrypoint: './dist/index.js',
|
|
@@ -324,7 +324,7 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
324
324
|
{
|
|
325
325
|
name: '@siduri-x/observation',
|
|
326
326
|
organType: 'observation',
|
|
327
|
-
version: '1.0.
|
|
327
|
+
version: '1.0.3',
|
|
328
328
|
displayName: 'Observation (Screen Perception & Frame Ingest)',
|
|
329
329
|
description: 'Screen capture frame ingest, SHA-256 deduplication, and visual grounding for Eyes/Vision',
|
|
330
330
|
entrypoint: './dist/index.js',
|
|
@@ -460,5 +460,33 @@ exports.BUILTIN_ORGAN_MANIFESTS = [
|
|
|
460
460
|
],
|
|
461
461
|
database: null,
|
|
462
462
|
healthCheck: null
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: '@siduri-x/mouth',
|
|
466
|
+
organType: 'mouth',
|
|
467
|
+
version: '1.0.0',
|
|
468
|
+
displayName: 'Mouth (Communication & UI Delivery)',
|
|
469
|
+
description: 'Decoupled output delivery organ formatting cognitive decisions for web interfaces',
|
|
470
|
+
entrypoint: './dist/index.js',
|
|
471
|
+
factory: 'DefaultMouthOrgan',
|
|
472
|
+
configKey: 'mouth',
|
|
473
|
+
configSchema: {
|
|
474
|
+
type: 'object',
|
|
475
|
+
properties: {
|
|
476
|
+
defaultMedium: {
|
|
477
|
+
type: 'string',
|
|
478
|
+
enum: ['web'],
|
|
479
|
+
default: 'web'
|
|
480
|
+
},
|
|
481
|
+
maxTextLength: {
|
|
482
|
+
type: 'number',
|
|
483
|
+
default: 8000
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
environment: [],
|
|
488
|
+
services: [],
|
|
489
|
+
database: null,
|
|
490
|
+
healthCheck: null
|
|
463
491
|
}
|
|
464
492
|
];
|
|
@@ -12,20 +12,26 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
12
12
|
const repoRoot = node_path_1.default.resolve(__dirname, '../..');
|
|
13
13
|
const tempPackDir = node_path_1.default.resolve(__dirname, '../temp-packs-e2e');
|
|
14
14
|
const cleanMachineRoot = node_path_1.default.resolve(__dirname, '../temp-clean-machine-e2e');
|
|
15
|
+
const getPkgVer = (dir) => JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve(repoRoot, dir, 'package.json'), 'utf8')).version;
|
|
15
16
|
const ALL_CANONICAL_PACKAGES = [
|
|
16
|
-
{ filter: '@siduri-x/core', tarName:
|
|
17
|
-
{ filter: '@siduri-x/brain', tarName:
|
|
18
|
-
{ filter: '@siduri-x/memory', tarName:
|
|
19
|
-
{ filter: '@siduri-x/knowledge', tarName:
|
|
20
|
-
{ filter: '@siduri-x/behavior', tarName:
|
|
21
|
-
{ filter: '@siduri-x/ear', tarName:
|
|
22
|
-
{ filter: '@siduri-x/vision', tarName:
|
|
23
|
-
{ filter: '@siduri-x/hands', tarName:
|
|
24
|
-
{ filter: '@siduri-x/body', tarName:
|
|
25
|
-
{ filter: '@siduri-x/voice', tarName:
|
|
26
|
-
{ filter: '@siduri-x/observation', tarName:
|
|
27
|
-
{ filter: '@
|
|
17
|
+
{ filter: '@siduri-x/core', tarName: `siduri-x-core-${getPkgVer('packages/core')}.tgz`, isOrgan: false },
|
|
18
|
+
{ filter: '@siduri-x/brain', tarName: `siduri-x-brain-${getPkgVer('packages/organs/brain')}.tgz`, isOrgan: true },
|
|
19
|
+
{ filter: '@siduri-x/memory', tarName: `siduri-x-memory-${getPkgVer('packages/organs/memory')}.tgz`, isOrgan: true },
|
|
20
|
+
{ filter: '@siduri-x/knowledge', tarName: `siduri-x-knowledge-${getPkgVer('packages/organs/knowledge')}.tgz`, isOrgan: true },
|
|
21
|
+
{ filter: '@siduri-x/behavior', tarName: `siduri-x-behavior-${getPkgVer('packages/organs/behavior')}.tgz`, isOrgan: true },
|
|
22
|
+
{ filter: '@siduri-x/ear', tarName: `siduri-x-ear-${getPkgVer('packages/organs/ear')}.tgz`, isOrgan: true },
|
|
23
|
+
{ filter: '@siduri-x/vision', tarName: `siduri-x-vision-${getPkgVer('packages/organs/vision')}.tgz`, isOrgan: true },
|
|
24
|
+
{ filter: '@siduri-x/hands', tarName: `siduri-x-hands-${getPkgVer('packages/organs/hands')}.tgz`, isOrgan: true },
|
|
25
|
+
{ filter: '@siduri-x/body', tarName: `siduri-x-body-${getPkgVer('packages/organs/body')}.tgz`, isOrgan: true },
|
|
26
|
+
{ filter: '@siduri-x/voice', tarName: `siduri-x-voice-${getPkgVer('packages/organs/voice')}.tgz`, isOrgan: true },
|
|
27
|
+
{ filter: '@siduri-x/observation', tarName: `siduri-x-observation-${getPkgVer('packages/organs/observation')}.tgz`, isOrgan: true },
|
|
28
|
+
{ filter: '@siduri-x/mouth', tarName: `siduri-x-mouth-${getPkgVer('packages/organs/mouth')}.tgz`, isOrgan: true },
|
|
29
|
+
{ filter: '@vxnus/siduri', tarName: `vxnus-siduri-${getPkgVer('cli')}.tgz`, isOrgan: false },
|
|
28
30
|
];
|
|
31
|
+
const getTarPath = (pkgName) => {
|
|
32
|
+
const pkg = ALL_CANONICAL_PACKAGES.find(p => p.filter === pkgName);
|
|
33
|
+
return node_path_1.default.join(tempPackDir, pkg.tarName);
|
|
34
|
+
};
|
|
29
35
|
beforeAll(() => {
|
|
30
36
|
// 1. Prepare clean directories
|
|
31
37
|
if (node_fs_1.default.existsSync(tempPackDir))
|
|
@@ -35,7 +41,7 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
35
41
|
node_fs_1.default.mkdirSync(tempPackDir, { recursive: true });
|
|
36
42
|
node_fs_1.default.mkdirSync(cleanMachineRoot, { recursive: true });
|
|
37
43
|
// 2. Build all packages in repo
|
|
38
|
-
(0, node_child_process_1.execSync)(
|
|
44
|
+
(0, node_child_process_1.execSync)("pnpm turbo run build --filter='!web'", { cwd: repoRoot, stdio: 'pipe' });
|
|
39
45
|
// 3. Pack each canonical package into tempPackDir
|
|
40
46
|
for (const pkg of ALL_CANONICAL_PACKAGES) {
|
|
41
47
|
(0, node_child_process_1.execSync)(`pnpm --filter ${pkg.filter} pack --pack-destination ${tempPackDir}`, {
|
|
@@ -51,7 +57,7 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
51
57
|
node_fs_1.default.rmSync(cleanMachineRoot, { recursive: true, force: true });
|
|
52
58
|
});
|
|
53
59
|
describe('Phase 5A: Package Artifact Verification', () => {
|
|
54
|
-
test('all
|
|
60
|
+
test('all 13 packages produce valid tarballs', () => {
|
|
55
61
|
for (const pkg of ALL_CANONICAL_PACKAGES) {
|
|
56
62
|
const tarPath = node_path_1.default.join(tempPackDir, pkg.tarName);
|
|
57
63
|
expect(node_fs_1.default.existsSync(tarPath)).toBe(true);
|
|
@@ -86,7 +92,7 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
86
92
|
}
|
|
87
93
|
});
|
|
88
94
|
test('memory organ tarball packages migrations/001_initial_schema.sql', () => {
|
|
89
|
-
const memoryTarPath = node_path_1.default.join(tempPackDir, 'siduri-x-memory-1.0.
|
|
95
|
+
const memoryTarPath = node_path_1.default.join(tempPackDir, 'siduri-x-memory-1.0.4.tgz');
|
|
90
96
|
const listing = (0, node_child_process_1.execSync)(`tar -tzf ${memoryTarPath}`, { encoding: 'utf8' });
|
|
91
97
|
expect(listing).toContain('package/migrations/001_initial_schema.sql');
|
|
92
98
|
});
|
|
@@ -106,8 +112,8 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
106
112
|
// Write instance files referencing packed tarballs directly for true clean machine install
|
|
107
113
|
const pkgObj = JSON.parse(files['package.json']);
|
|
108
114
|
pkgObj.dependencies = {
|
|
109
|
-
'@siduri-x/core': `file:${
|
|
110
|
-
'@siduri-x/brain': `file:${
|
|
115
|
+
'@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
|
|
116
|
+
'@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
|
|
111
117
|
};
|
|
112
118
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
|
|
113
119
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
|
|
@@ -154,9 +160,9 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
154
160
|
});
|
|
155
161
|
const pkgObj = JSON.parse(files['package.json']);
|
|
156
162
|
pkgObj.dependencies = {
|
|
157
|
-
'@siduri-x/core': `file:${
|
|
158
|
-
'@siduri-x/brain': `file:${
|
|
159
|
-
'@siduri-x/hands': `file:${
|
|
163
|
+
'@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
|
|
164
|
+
'@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
|
|
165
|
+
'@siduri-x/hands': `file:${getTarPath('@siduri-x/hands')}`,
|
|
160
166
|
};
|
|
161
167
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
|
|
162
168
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
|
|
@@ -193,9 +199,9 @@ describe('Phase 5: Clean-Machine Distribution & E2E Integration Suite', () => {
|
|
|
193
199
|
});
|
|
194
200
|
const pkgObj = JSON.parse(files['package.json']);
|
|
195
201
|
pkgObj.dependencies = {
|
|
196
|
-
'@siduri-x/core': `file:${
|
|
197
|
-
'@siduri-x/brain': `file:${
|
|
198
|
-
'@siduri-x/memory': `file:${
|
|
202
|
+
'@siduri-x/core': `file:${getTarPath('@siduri-x/core')}`,
|
|
203
|
+
'@siduri-x/brain': `file:${getTarPath('@siduri-x/brain')}`,
|
|
204
|
+
'@siduri-x/memory': `file:${getTarPath('@siduri-x/memory')}`,
|
|
199
205
|
};
|
|
200
206
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'package.json'), JSON.stringify(pkgObj, null, 2) + '\n');
|
|
201
207
|
node_fs_1.default.writeFileSync(node_path_1.default.join(instanceDir, 'siduri.config.json'), files['siduri.config.json']);
|
|
@@ -13,6 +13,7 @@ export * from './behavior';
|
|
|
13
13
|
export * from './vision';
|
|
14
14
|
export * from './ear';
|
|
15
15
|
export * from './observation';
|
|
16
|
+
export * from './mouth';
|
|
16
17
|
export interface ConfigureOrganOptions {
|
|
17
18
|
brainOptions?: BrainConfiguratorOptions;
|
|
18
19
|
knowledgeOptions?: KnowledgeConfiguratorOptions;
|
|
@@ -25,6 +25,7 @@ const behavior_1 = require("./behavior");
|
|
|
25
25
|
const vision_1 = require("./vision");
|
|
26
26
|
const ear_1 = require("./ear");
|
|
27
27
|
const observation_1 = require("./observation");
|
|
28
|
+
const mouth_1 = require("./mouth");
|
|
28
29
|
__exportStar(require("./types"), exports);
|
|
29
30
|
__exportStar(require("./brain"), exports);
|
|
30
31
|
__exportStar(require("./knowledge"), exports);
|
|
@@ -36,6 +37,7 @@ __exportStar(require("./behavior"), exports);
|
|
|
36
37
|
__exportStar(require("./vision"), exports);
|
|
37
38
|
__exportStar(require("./ear"), exports);
|
|
38
39
|
__exportStar(require("./observation"), exports);
|
|
40
|
+
__exportStar(require("./mouth"), exports);
|
|
39
41
|
async function configureOrgan(manifest, context, options = {}) {
|
|
40
42
|
const ctx = {
|
|
41
43
|
companionName: context.companionName,
|
|
@@ -63,6 +65,8 @@ async function configureOrgan(manifest, context, options = {}) {
|
|
|
63
65
|
return (0, ear_1.configureEar)(ctx);
|
|
64
66
|
case 'observation':
|
|
65
67
|
return (0, observation_1.configureObservation)(ctx);
|
|
68
|
+
case 'mouth':
|
|
69
|
+
return (0, mouth_1.configureMouth)(ctx);
|
|
66
70
|
default:
|
|
67
71
|
return {
|
|
68
72
|
config: ctx.existingConfig || {},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureMouth = configureMouth;
|
|
4
|
+
async function configureMouth(_context) {
|
|
5
|
+
return {
|
|
6
|
+
config: {
|
|
7
|
+
defaultMedium: 'web',
|
|
8
|
+
maxTextLength: 8000,
|
|
9
|
+
},
|
|
10
|
+
summary: {
|
|
11
|
+
'Default Medium': 'Web',
|
|
12
|
+
'Max Text Length': '8000 chars',
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -13,13 +13,25 @@ async function configureVoice(_context) {
|
|
|
13
13
|
message: 'Voice provider?',
|
|
14
14
|
choices: [
|
|
15
15
|
{
|
|
16
|
-
name: '
|
|
17
|
-
value: '
|
|
16
|
+
name: 'Edge-TTS (Zero-setup cloud TTS, no downloads/no Python required)',
|
|
17
|
+
value: 'edge-tts',
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
name: 'VOICEVOX (Standard VOICEVOX stock character voice banks)',
|
|
21
21
|
value: 'voicevox',
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Kokoro TTS (Fast lightweight neural TTS via HTTP/CLI)',
|
|
25
|
+
value: 'kokoro',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'Piper TTS (Fast local neural TTS via HTTP/CLI)',
|
|
29
|
+
value: 'piper',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'RVC (Custom user-owned voice model via .pth / .index weights)',
|
|
33
|
+
value: 'rvc',
|
|
34
|
+
},
|
|
23
35
|
{
|
|
24
36
|
name: 'None (Disable voice synthesis)',
|
|
25
37
|
value: 'none',
|
|
@@ -32,6 +44,108 @@ async function configureVoice(_context) {
|
|
|
32
44
|
summary: { Provider: 'None (Voice disabled)' },
|
|
33
45
|
};
|
|
34
46
|
}
|
|
47
|
+
if (provider === 'edge-tts') {
|
|
48
|
+
const edgeAnswers = await inquirer_1.default.prompt([
|
|
49
|
+
{
|
|
50
|
+
type: 'input',
|
|
51
|
+
name: 'voice',
|
|
52
|
+
message: 'Edge-TTS Voice Identifier (e.g. ja-JP-NanamiNeural, en-US-AriaNeural):',
|
|
53
|
+
default: 'ja-JP-NanamiNeural',
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
const voice = edgeAnswers.voice.trim() || 'ja-JP-NanamiNeural';
|
|
57
|
+
return {
|
|
58
|
+
config: {
|
|
59
|
+
provider: 'edge-tts',
|
|
60
|
+
voice,
|
|
61
|
+
maxQueueDepth: 50,
|
|
62
|
+
},
|
|
63
|
+
summary: {
|
|
64
|
+
Provider: 'Edge-TTS (Cloud Neural)',
|
|
65
|
+
Voice: voice,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (provider === 'kokoro') {
|
|
70
|
+
const kokoroAnswers = await inquirer_1.default.prompt([
|
|
71
|
+
{
|
|
72
|
+
type: 'input',
|
|
73
|
+
name: 'baseUrl',
|
|
74
|
+
message: 'Kokoro HTTP Base URL (leave empty if using local kokoro-tts CLI):',
|
|
75
|
+
default: 'http://localhost:8880',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'input',
|
|
79
|
+
name: 'voice',
|
|
80
|
+
message: 'Kokoro Voice Name (e.g. af_bella, af_heart):',
|
|
81
|
+
default: 'af_bella',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
type: 'input',
|
|
85
|
+
name: 'speed',
|
|
86
|
+
message: 'Speech Speed multiplier (e.g. 1.0):',
|
|
87
|
+
default: '1.0',
|
|
88
|
+
},
|
|
89
|
+
]);
|
|
90
|
+
const baseUrl = kokoroAnswers.baseUrl.trim() || undefined;
|
|
91
|
+
const voice = kokoroAnswers.voice.trim() || 'af_bella';
|
|
92
|
+
const speed = parseFloat(kokoroAnswers.speed) || 1.0;
|
|
93
|
+
return {
|
|
94
|
+
config: {
|
|
95
|
+
provider: 'kokoro',
|
|
96
|
+
baseUrl,
|
|
97
|
+
voice,
|
|
98
|
+
speed,
|
|
99
|
+
maxQueueDepth: 50,
|
|
100
|
+
},
|
|
101
|
+
summary: {
|
|
102
|
+
Provider: 'Kokoro TTS (Local / Server)',
|
|
103
|
+
Mode: baseUrl ? `HTTP (${baseUrl})` : 'CLI (kokoro-tts)',
|
|
104
|
+
Voice: voice,
|
|
105
|
+
Speed: speed,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (provider === 'piper') {
|
|
110
|
+
const piperAnswers = await inquirer_1.default.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'input',
|
|
113
|
+
name: 'baseUrl',
|
|
114
|
+
message: 'Piper HTTP Base URL (leave empty if using local piper CLI):',
|
|
115
|
+
default: 'http://localhost:5000',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: 'input',
|
|
119
|
+
name: 'model',
|
|
120
|
+
message: 'Piper Model Path or Name (.onnx, optional):',
|
|
121
|
+
default: '',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: 'input',
|
|
125
|
+
name: 'speakerId',
|
|
126
|
+
message: 'Piper Speaker ID (optional):',
|
|
127
|
+
default: '',
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
const baseUrl = piperAnswers.baseUrl.trim() || undefined;
|
|
131
|
+
const model = piperAnswers.model.trim() || undefined;
|
|
132
|
+
const speakerId = piperAnswers.speakerId.trim() ? parseInt(piperAnswers.speakerId.trim(), 10) : undefined;
|
|
133
|
+
return {
|
|
134
|
+
config: {
|
|
135
|
+
provider: 'piper',
|
|
136
|
+
baseUrl,
|
|
137
|
+
model,
|
|
138
|
+
speakerId,
|
|
139
|
+
maxQueueDepth: 50,
|
|
140
|
+
},
|
|
141
|
+
summary: {
|
|
142
|
+
Provider: 'Piper TTS (Local / Server)',
|
|
143
|
+
Mode: baseUrl ? `HTTP (${baseUrl})` : 'CLI (piper)',
|
|
144
|
+
Model: model || 'default',
|
|
145
|
+
'Speaker ID': speakerId !== undefined ? speakerId : 'default',
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
35
149
|
if (provider === 'rvc') {
|
|
36
150
|
const rvcAnswers = await inquirer_1.default.prompt([
|
|
37
151
|
{
|
|
@@ -215,6 +215,38 @@ describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
|
215
215
|
expect(result.config.rvc.pitchShift).toBe(12);
|
|
216
216
|
expect(result.summary?.['Base TTS']).toBe('edge-tts');
|
|
217
217
|
});
|
|
218
|
+
test('Voice configurator configures standalone Edge-TTS', async () => {
|
|
219
|
+
inquirer_1.default.prompt
|
|
220
|
+
.mockResolvedValueOnce({ provider: 'edge-tts' })
|
|
221
|
+
.mockResolvedValueOnce({ voice: 'en-US-AriaNeural' });
|
|
222
|
+
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
223
|
+
expect(result.config.provider).toBe('edge-tts');
|
|
224
|
+
expect(result.config.voice).toBe('en-US-AriaNeural');
|
|
225
|
+
expect(result.summary?.Provider).toBe('Edge-TTS (Cloud Neural)');
|
|
226
|
+
expect(result.summary?.Voice).toBe('en-US-AriaNeural');
|
|
227
|
+
});
|
|
228
|
+
test('Voice configurator configures standalone Kokoro TTS', async () => {
|
|
229
|
+
inquirer_1.default.prompt
|
|
230
|
+
.mockResolvedValueOnce({ provider: 'kokoro' })
|
|
231
|
+
.mockResolvedValueOnce({ baseUrl: 'http://localhost:8880', voice: 'af_heart', speed: '1.2' });
|
|
232
|
+
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
233
|
+
expect(result.config.provider).toBe('kokoro');
|
|
234
|
+
expect(result.config.baseUrl).toBe('http://localhost:8880');
|
|
235
|
+
expect(result.config.voice).toBe('af_heart');
|
|
236
|
+
expect(result.config.speed).toBe(1.2);
|
|
237
|
+
expect(result.summary?.Provider).toBe('Kokoro TTS (Local / Server)');
|
|
238
|
+
});
|
|
239
|
+
test('Voice configurator configures standalone Piper TTS', async () => {
|
|
240
|
+
inquirer_1.default.prompt
|
|
241
|
+
.mockResolvedValueOnce({ provider: 'piper' })
|
|
242
|
+
.mockResolvedValueOnce({ baseUrl: 'http://localhost:5000', model: 'en_US-lessac', speakerId: '2' });
|
|
243
|
+
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
244
|
+
expect(result.config.provider).toBe('piper');
|
|
245
|
+
expect(result.config.baseUrl).toBe('http://localhost:5000');
|
|
246
|
+
expect(result.config.model).toBe('en_US-lessac');
|
|
247
|
+
expect(result.config.speakerId).toBe(2);
|
|
248
|
+
expect(result.summary?.Provider).toBe('Piper TTS (Local / Server)');
|
|
249
|
+
});
|
|
218
250
|
test('Body configurator configures Live2D, custom model path, and expression', async () => {
|
|
219
251
|
inquirer_1.default.prompt
|
|
220
252
|
.mockResolvedValueOnce({ provider: 'live2d' })
|
package/dist/discovery.test.js
CHANGED
|
@@ -8,10 +8,10 @@ const discovery_1 = require("./discovery");
|
|
|
8
8
|
const generator_1 = require("./generator");
|
|
9
9
|
describe('Discovery & Dynamic Composition System Tests (Phase 3)', () => {
|
|
10
10
|
const rootOrgansDir = node_path_1.default.resolve(__dirname, '../../packages/organs');
|
|
11
|
-
test('Registry successfully discovers all
|
|
11
|
+
test('Registry successfully discovers all 11 organ packages from workspace', () => {
|
|
12
12
|
const registry = discovery_1.OrganRegistry.discover([rootOrgansDir]);
|
|
13
13
|
const manifests = registry.getAll();
|
|
14
|
-
expect(manifests.length).toBe(
|
|
14
|
+
expect(manifests.length).toBe(11);
|
|
15
15
|
const organTypes = registry.getAvailableOrganTypes().sort();
|
|
16
16
|
expect(organTypes).toEqual([
|
|
17
17
|
'behavior',
|
|
@@ -21,6 +21,7 @@ describe('Discovery & Dynamic Composition System Tests (Phase 3)', () => {
|
|
|
21
21
|
'hands',
|
|
22
22
|
'knowledge',
|
|
23
23
|
'memory',
|
|
24
|
+
'mouth',
|
|
24
25
|
'observation',
|
|
25
26
|
'vision',
|
|
26
27
|
'voice',
|
|
@@ -60,8 +61,9 @@ describe('Discovery & Dynamic Composition System Tests (Phase 3)', () => {
|
|
|
60
61
|
test('Fallback to builtin organ manifests when scanning non-existent search roots', () => {
|
|
61
62
|
const registry = discovery_1.OrganRegistry.discover(['/non-existent-directory/empty']);
|
|
62
63
|
const manifests = registry.getAll();
|
|
63
|
-
expect(manifests.length).toBe(
|
|
64
|
+
expect(manifests.length).toBe(11);
|
|
64
65
|
expect(registry.get('brain')).toBeDefined();
|
|
65
66
|
expect(registry.get('memory')).toBeDefined();
|
|
67
|
+
expect(registry.get('mouth')).toBeDefined();
|
|
66
68
|
});
|
|
67
69
|
});
|
package/dist/generator.js
CHANGED
|
@@ -63,16 +63,21 @@ function getDefaultConfigForManifest(manifest) {
|
|
|
63
63
|
config.provider = config.provider || 'openrouter';
|
|
64
64
|
config.model = config.model || 'gpt-4-vision';
|
|
65
65
|
}
|
|
66
|
+
else if (manifest.organType === 'mouth') {
|
|
67
|
+
config.defaultMedium = 'web';
|
|
68
|
+
config.maxTextLength = config.maxTextLength || 8000;
|
|
69
|
+
}
|
|
66
70
|
return config;
|
|
67
71
|
}
|
|
68
72
|
function generateInstanceFiles(options) {
|
|
69
73
|
const instanceName = options.name || 'my-siduri';
|
|
70
74
|
const instanceId = options.id || 'default';
|
|
71
|
-
const coreVersion = options.coreVersion || '^1.0.
|
|
75
|
+
const coreVersion = options.coreVersion || '^1.0.8';
|
|
72
76
|
const manifests = options.selectedManifests;
|
|
73
77
|
const hasMemory = manifests.some((m) => m.organType === 'memory');
|
|
74
78
|
const hasVoice = manifests.some((m) => m.organType === 'voice');
|
|
75
79
|
const hasBody = manifests.some((m) => m.organType === 'body');
|
|
80
|
+
const hasMouth = manifests.some((m) => m.organType === 'mouth');
|
|
76
81
|
const voiceConfig = options.organConfigs?.voice || options.organConfigs?.['@siduri-x/voice'];
|
|
77
82
|
const isVoicevox = hasVoice && (!voiceConfig || voiceConfig.provider === 'voicevox');
|
|
78
83
|
const memoryConfig = options.organConfigs?.memory || options.organConfigs?.['@siduri-x/memory'];
|
|
@@ -222,6 +227,9 @@ function generateInstanceFiles(options) {
|
|
|
222
227
|
instantiationLines.push(`const ${varName} = new ${m.factory}(config.organs.${m.configKey});`);
|
|
223
228
|
organMapEntries.push(` ${varName},`);
|
|
224
229
|
}
|
|
230
|
+
if (hasMouth && hasVoice) {
|
|
231
|
+
instantiationLines.push(`if (typeof mouth?.setVoiceOrgan === 'function') mouth.setVoiceOrgan(voice);`);
|
|
232
|
+
}
|
|
225
233
|
const selectedDisplayNames = manifests.map((m) => m.displayName.split(' ')[0] || m.organType).join(', ');
|
|
226
234
|
const srcIndexJs = [
|
|
227
235
|
...importLines,
|
|
@@ -363,7 +371,7 @@ function generateInstanceFiles(options) {
|
|
|
363
371
|
` id: config.id,`,
|
|
364
372
|
` companionId: config.id,`,
|
|
365
373
|
` message: payload.message || payload.text || '',`,
|
|
366
|
-
`
|
|
374
|
+
` context: payload.context,`,
|
|
367
375
|
` history: Array.isArray(payload.history) ? payload.history : [],`,
|
|
368
376
|
` });`,
|
|
369
377
|
'',
|
|
@@ -377,6 +385,122 @@ function generateInstanceFiles(options) {
|
|
|
377
385
|
` return;`,
|
|
378
386
|
` }`,
|
|
379
387
|
'',
|
|
388
|
+
` // API: Real-time SSE streaming (Mouth transport)`,
|
|
389
|
+
` if ((pathname === '/chat/stream' || pathname === '/api/chat/stream') && req.method === 'POST') {`,
|
|
390
|
+
` let body = '';`,
|
|
391
|
+
` req.on('data', (chunk) => { body += chunk; });`,
|
|
392
|
+
` req.on('end', async () => {`,
|
|
393
|
+
` res.writeHead(200, {`,
|
|
394
|
+
` 'Content-Type': 'text/event-stream',`,
|
|
395
|
+
` 'Cache-Control': 'no-cache, no-transform',`,
|
|
396
|
+
` 'Connection': 'keep-alive',`,
|
|
397
|
+
` });`,
|
|
398
|
+
` const abortController = new AbortController();`,
|
|
399
|
+
` const onClose = () => {`,
|
|
400
|
+
` abortController.abort('client_disconnect');`,
|
|
401
|
+
` if (typeof runtime.interruptMouth === 'function') {`,
|
|
402
|
+
` runtime.interruptMouth('client_disconnect');`,
|
|
403
|
+
` }`,
|
|
404
|
+
` };`,
|
|
405
|
+
` req.on('close', onClose);`,
|
|
406
|
+
'',
|
|
407
|
+
` try {`,
|
|
408
|
+
` const payload = JSON.parse(body || '{}');`,
|
|
409
|
+
` const response = await dispatchCompanionChat(runtime, {`,
|
|
410
|
+
` id: config.id,`,
|
|
411
|
+
` companionId: config.id,`,
|
|
412
|
+
` message: payload.message || payload.text || '',`,
|
|
413
|
+
` context: payload.context,`,
|
|
414
|
+
` history: Array.isArray(payload.history) ? payload.history : [],`,
|
|
415
|
+
` medium: 'web',`,
|
|
416
|
+
` signal: abortController.signal,`,
|
|
417
|
+
` });`,
|
|
418
|
+
'',
|
|
419
|
+
` res.write(\`event: staged\\ndata: \${JSON.stringify({ response_id: response.response_id, correlation_id: response.correlation_id, status: response.status })}\\n\\n\`);`,
|
|
420
|
+
'',
|
|
421
|
+
` const avatarEvent = response.metadata?.events?.find(`,
|
|
422
|
+
` (e) => (e.kind === 'avatar' || e.kind === 'body') && (e.approval === 'APPROVED' || !e.approval)`,
|
|
423
|
+
` );`,
|
|
424
|
+
` if (avatarEvent) {`,
|
|
425
|
+
` res.write(\`event: avatar\\ndata: \${JSON.stringify(avatarEvent)}\\n\\n\`);`,
|
|
426
|
+
` }`,
|
|
427
|
+
'',
|
|
428
|
+
` const speechText = response.delivery?.text || response.response?.subtitle_en || response.response?.spoken_ja || '';`,
|
|
429
|
+
` const utterance = {`,
|
|
430
|
+
` utteranceId: response.response_id || 'utt-stream',`,
|
|
431
|
+
` companionId: config.id,`,
|
|
432
|
+
` responseId: response.response_id,`,
|
|
433
|
+
` correlationId: response.correlation_id,`,
|
|
434
|
+
` text: speechText,`,
|
|
435
|
+
` medium: 'web',`,
|
|
436
|
+
` expression: avatarEvent?.expression,`,
|
|
437
|
+
` action: avatarEvent?.action,`,
|
|
438
|
+
` signal: abortController.signal,`,
|
|
439
|
+
` };`,
|
|
440
|
+
'',
|
|
441
|
+
` if (runtime.mouth && typeof runtime.mouth.stream === 'function') {`,
|
|
442
|
+
` for await (const chunk of runtime.mouth.stream(utterance)) {`,
|
|
443
|
+
` if (abortController.signal.aborted) {`,
|
|
444
|
+
` res.write(\`event: chunk\\ndata: \${JSON.stringify({ ...chunk, interrupted: true })}\\n\\n\`);`,
|
|
445
|
+
` break;`,
|
|
446
|
+
` }`,
|
|
447
|
+
` res.write(\`event: chunk\\ndata: \${JSON.stringify(chunk)}\\n\\n\`);`,
|
|
448
|
+
` }`,
|
|
449
|
+
` } else {`,
|
|
450
|
+
` res.write(\`event: chunk\\ndata: \${JSON.stringify({ utteranceId: utterance.utteranceId, index: 1, deltaText: speechText, isComplete: true, medium: 'web' })}\\n\\n\`);`,
|
|
451
|
+
` }`,
|
|
452
|
+
'',
|
|
453
|
+
` res.write(\`event: done\\ndata: \${JSON.stringify(response)}\\n\\n\`);`,
|
|
454
|
+
` res.end();`,
|
|
455
|
+
` } catch (err) {`,
|
|
456
|
+
` if (abortController.signal.aborted) {`,
|
|
457
|
+
` res.write(\`event: interrupted\\ndata: \${JSON.stringify({ reason: abortController.signal.reason })}\\n\\n\`);`,
|
|
458
|
+
` } else {`,
|
|
459
|
+
` res.write(\`event: error\\ndata: \${JSON.stringify({ error: err.message })}\\n\\n\`);`,
|
|
460
|
+
` }`,
|
|
461
|
+
` res.end();`,
|
|
462
|
+
` } finally {`,
|
|
463
|
+
` req.removeListener('close', onClose);`,
|
|
464
|
+
` }`,
|
|
465
|
+
` });`,
|
|
466
|
+
` return;`,
|
|
467
|
+
` }`,
|
|
468
|
+
'',
|
|
469
|
+
` // API: Barge-in interruption`,
|
|
470
|
+
` if ((pathname === '/chat/interrupt' || pathname === '/mouth/interrupt' || pathname === '/api/chat/interrupt') && req.method === 'POST') {`,
|
|
471
|
+
` let body = '';`,
|
|
472
|
+
` req.on('data', (chunk) => { body += chunk; });`,
|
|
473
|
+
` req.on('end', () => {`,
|
|
474
|
+
` try {`,
|
|
475
|
+
` const payload = JSON.parse(body || '{}');`,
|
|
476
|
+
` const reason = payload.reason || 'user_barge_in';`,
|
|
477
|
+
` if (typeof runtime.interruptMouth === 'function') {`,
|
|
478
|
+
` runtime.interruptMouth(reason);`,
|
|
479
|
+
` }`,
|
|
480
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
481
|
+
` res.end(JSON.stringify({ success: true, interrupted: true, reason }));`,
|
|
482
|
+
` } catch (e) {`,
|
|
483
|
+
` res.writeHead(500, { 'Content-Type': 'application/json' });`,
|
|
484
|
+
` res.end(JSON.stringify({ error: e.message }));`,
|
|
485
|
+
` }`,
|
|
486
|
+
` });`,
|
|
487
|
+
` return;`,
|
|
488
|
+
` }`,
|
|
489
|
+
'',
|
|
490
|
+
` // API: Mouth channels & health`,
|
|
491
|
+
` if ((pathname === '/mouth/health' || pathname === '/api/mouth/health') && req.method === 'GET') {`,
|
|
492
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
493
|
+
` res.end(JSON.stringify({ provider: 'siduri-mouth', configured: Boolean(runtime.mouth) }));`,
|
|
494
|
+
` return;`,
|
|
495
|
+
` }`,
|
|
496
|
+
'',
|
|
497
|
+
` if ((pathname === '/mouth/channels' || pathname === '/api/mouth/channels') && req.method === 'GET') {`,
|
|
498
|
+
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
|
499
|
+
` const channels = typeof runtime.mouth?.getRegisteredChannels === 'function' ? runtime.mouth.getRegisteredChannels() : [];`,
|
|
500
|
+
` res.end(JSON.stringify({ channels }));`,
|
|
501
|
+
` return;`,
|
|
502
|
+
` }`,
|
|
503
|
+
'',
|
|
380
504
|
` // API: Model Catalog Discovery (Body & Voice)`,
|
|
381
505
|
` if (pathname === '/api/models/body' && req.method === 'GET') {`,
|
|
382
506
|
` res.writeHead(200, { 'Content-Type': 'application/json' });`,
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ const doctor_1 = require("./doctor");
|
|
|
26
26
|
const db_1 = require("./db");
|
|
27
27
|
const configurators_1 = require("./configurators");
|
|
28
28
|
const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
29
|
-
exports.CLI_VERSION = '0.1.
|
|
29
|
+
exports.CLI_VERSION = '0.1.10';
|
|
30
30
|
exports.colors = {
|
|
31
31
|
cyan: '\u001b[36m',
|
|
32
32
|
dim: '\u001b[2m',
|