@vxnus/siduri 0.0.7 → 0.0.9
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/README.md +11 -1
- package/dist/builtin-manifests.js +12 -12
- package/dist/clean-machine-e2e.test.js +12 -12
- package/dist/configurators/behavior.d.ts +2 -0
- package/dist/configurators/behavior.js +36 -0
- package/dist/configurators/body.d.ts +2 -0
- package/dist/configurators/body.js +44 -0
- package/dist/configurators/brain.d.ts +6 -0
- package/dist/configurators/brain.js +80 -0
- package/dist/configurators/ear.d.ts +2 -0
- package/dist/configurators/ear.js +28 -0
- package/dist/configurators/hands.d.ts +2 -0
- package/dist/configurators/hands.js +27 -0
- package/dist/configurators/index.d.ts +23 -0
- package/dist/configurators/index.js +74 -0
- package/dist/configurators/knowledge.d.ts +6 -0
- package/dist/configurators/knowledge.js +100 -0
- package/dist/configurators/memory.d.ts +2 -0
- package/dist/configurators/memory.js +44 -0
- package/dist/configurators/observation.d.ts +2 -0
- package/dist/configurators/observation.js +12 -0
- package/dist/configurators/types.d.ts +12 -0
- package/dist/configurators/types.js +2 -0
- package/dist/configurators/vision.d.ts +2 -0
- package/dist/configurators/vision.js +39 -0
- package/dist/configurators/voice.d.ts +2 -0
- package/dist/configurators/voice.js +53 -0
- package/dist/configurators.test.d.ts +1 -0
- package/dist/configurators.test.js +275 -0
- package/dist/doctor-db.test.js +9 -3
- package/dist/generator.d.ts +2 -0
- package/dist/generator.js +289 -33
- package/dist/generator.test.js +20 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +165 -54
- package/dist/providers/knowledge-hub.d.ts +37 -0
- package/dist/providers/knowledge-hub.js +141 -0
- package/dist/providers/openrouter.d.ts +32 -0
- package/dist/providers/openrouter.js +201 -0
- package/dist/release-check.js +12 -12
- package/dist/web-dist/404/index.html +1 -0
- package/dist/web-dist/404.html +1 -0
- package/dist/web-dist/__next.__PAGE__.txt +34 -0
- package/dist/web-dist/__next._full.txt +27 -0
- package/dist/web-dist/__next._tree.txt +3 -0
- package/dist/web-dist/_next/static/_zOqKpMPc6RDqk04fUScI/_buildManifest.js +11 -0
- package/dist/web-dist/_next/static/_zOqKpMPc6RDqk04fUScI/_clientMiddlewareManifest.js +1 -0
- package/dist/web-dist/_next/static/_zOqKpMPc6RDqk04fUScI/_ssgManifest.js +1 -0
- package/dist/web-dist/_next/static/chunks/0cz1d0mv5g_q7.js +1 -0
- package/dist/web-dist/_next/static/chunks/0uwih7sydv413.js +1 -0
- package/dist/web-dist/_next/static/chunks/1_yae15ffa5f6.js +1 -0
- package/dist/web-dist/_next/static/chunks/1hz3jco387c-k.js +1 -0
- package/dist/web-dist/_next/static/chunks/2bu5_paf4sm3x.css +1 -0
- package/dist/web-dist/_next/static/chunks/2kcqevsmv6kh2.js +31 -0
- package/dist/web-dist/_next/static/chunks/2s3d1bfr0l4b0.js +1 -0
- package/dist/web-dist/_next/static/chunks/32z87id9k6i2z.js +22 -0
- package/dist/web-dist/_next/static/chunks/39nefv-hczfy7.js +30 -0
- package/dist/web-dist/_next/static/chunks/3bx2gs3idjmo1.js +1 -0
- package/dist/web-dist/_next/static/chunks/turbopack-3eipe4c-imn5l.js +1 -0
- package/dist/web-dist/_next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- package/dist/web-dist/_not-found/__next._full.txt +17 -0
- package/dist/web-dist/_not-found/__next._not-found.__PAGE__.txt +23 -0
- package/dist/web-dist/_not-found/__next._tree.txt +3 -0
- package/dist/web-dist/_not-found/index.html +1 -0
- package/dist/web-dist/_not-found/index.txt +17 -0
- package/dist/web-dist/chat/__next._full.txt +18 -0
- package/dist/web-dist/chat/__next._tree.txt +3 -0
- package/dist/web-dist/chat/__next.chat.__PAGE__.txt +24 -0
- package/dist/web-dist/chat/index.html +1 -0
- package/dist/web-dist/chat/index.txt +18 -0
- package/dist/web-dist/favicon.ico +0 -0
- package/dist/web-dist/index.html +1 -0
- package/dist/web-dist/index.txt +27 -0
- package/dist/web-dist/live2d/akaituno/akaituno.8192/texture_00.png +0 -0
- package/dist/web-dist/live2d/akaituno/akaituno.cdi3.json +296 -0
- package/dist/web-dist/live2d/akaituno/akaituno.moc3 +0 -0
- package/dist/web-dist/live2d/akaituno/akaituno.model3.json +42 -0
- package/dist/web-dist/live2d/akaituno/akaituno.physics3.json +839 -0
- package/dist/web-dist/live2d/akaituno/eye_color.exp3.json +12 -0
- package/dist/web-dist/live2d/akaituno/eyes_zetubou.exp3.json +12 -0
- package/dist/web-dist/live2d/akaituno/face_aozame.exp3.json +12 -0
- package/dist/web-dist/live2d/akaituno/hair_open.exp3.json +12 -0
- package/dist/web-dist/live2d/live2dcubismcore.min.js +9 -0
- package/dist/web-dist/operator/__next._full.txt +18 -0
- package/dist/web-dist/operator/__next._tree.txt +3 -0
- package/dist/web-dist/operator/__next.operator.__PAGE__.txt +24 -0
- package/dist/web-dist/operator/index.html +1 -0
- package/dist/web-dist/operator/index.txt +18 -0
- package/dist/web-template.d.ts +2 -0
- package/dist/web-template.js +547 -0
- package/package.json +7 -7
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
exports.configureMemory = configureMemory;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
async function configureMemory(_context) {
|
|
9
|
+
const { database } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'database',
|
|
12
|
+
message: 'Memory database?',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'PostgreSQL (FTS relational claims with ACID durability)', value: 'postgres' },
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
const { deployment } = await inquirer_1.default.prompt({
|
|
18
|
+
type: 'list',
|
|
19
|
+
name: 'deployment',
|
|
20
|
+
message: 'PostgreSQL deployment target?',
|
|
21
|
+
choices: [
|
|
22
|
+
{ name: 'Supabase (Hosted Postgres with connection pooling)', value: 'supabase' },
|
|
23
|
+
{ name: 'Neon (Serverless Postgres with branch-per-companion)', value: 'neon' },
|
|
24
|
+
{ name: 'Local PostgreSQL (Docker or system service)', value: 'local' },
|
|
25
|
+
{ name: 'Other PostgreSQL URL', value: 'other' },
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
const deploymentDisplayNames = {
|
|
29
|
+
supabase: 'Supabase',
|
|
30
|
+
neon: 'Neon',
|
|
31
|
+
local: 'Local PostgreSQL',
|
|
32
|
+
other: 'Other PostgreSQL',
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
config: {
|
|
36
|
+
provider: database,
|
|
37
|
+
deployment,
|
|
38
|
+
},
|
|
39
|
+
summary: {
|
|
40
|
+
Database: 'PostgreSQL',
|
|
41
|
+
Deploy: deploymentDisplayNames[deployment] || deployment,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureObservation = configureObservation;
|
|
4
|
+
async function configureObservation(_context) {
|
|
5
|
+
return {
|
|
6
|
+
config: {},
|
|
7
|
+
summary: {
|
|
8
|
+
Provider: 'Grounded Observation Ingest',
|
|
9
|
+
Deduplication: 'Cryptographic SHA-256 Hashing',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OrganManifest } from '../manifest';
|
|
2
|
+
export interface OrganConfigurationResult {
|
|
3
|
+
config: Record<string, unknown>;
|
|
4
|
+
summary?: Record<string, unknown>;
|
|
5
|
+
metadata?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface OrganConfiguratorContext {
|
|
8
|
+
companionName: string;
|
|
9
|
+
manifest: OrganManifest;
|
|
10
|
+
existingConfig?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export type OrganConfigurator = (context: OrganConfiguratorContext) => Promise<OrganConfigurationResult>;
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
exports.configureVision = configureVision;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
async function configureVision(_context) {
|
|
9
|
+
const { model } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'model',
|
|
12
|
+
message: 'Vision model:',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'GPT-4 Vision / GPT-4o (Multimodal OCR & Object Inspection)', value: 'gpt-4-vision' },
|
|
15
|
+
{ name: 'Claude 3.5 Sonnet Vision', value: 'anthropic/claude-3.5-sonnet' },
|
|
16
|
+
{ name: 'Custom Vision Model', value: 'custom' },
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
let selectedModel = model;
|
|
20
|
+
if (model === 'custom') {
|
|
21
|
+
const { customModel } = await inquirer_1.default.prompt({
|
|
22
|
+
type: 'input',
|
|
23
|
+
name: 'customModel',
|
|
24
|
+
message: 'Vision Model ID:',
|
|
25
|
+
default: 'gpt-4-vision',
|
|
26
|
+
});
|
|
27
|
+
selectedModel = customModel.trim();
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
config: {
|
|
31
|
+
provider: 'openrouter',
|
|
32
|
+
model: selectedModel,
|
|
33
|
+
},
|
|
34
|
+
summary: {
|
|
35
|
+
Provider: 'OpenRouter Vision',
|
|
36
|
+
Model: selectedModel,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
exports.configureVoice = configureVoice;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
async function configureVoice(_context) {
|
|
9
|
+
const { provider } = await inquirer_1.default.prompt({
|
|
10
|
+
type: 'list',
|
|
11
|
+
name: 'provider',
|
|
12
|
+
message: 'Voice provider?',
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: 'VOICEVOX (Local high-fidelity neural speech synthesis engine)', value: 'voicevox' },
|
|
15
|
+
{ name: 'None (Disable voice synthesis)', value: 'none' },
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
if (provider === 'none') {
|
|
19
|
+
return {
|
|
20
|
+
config: { provider: 'none' },
|
|
21
|
+
summary: { Provider: 'None (Voice disabled)' },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const answers = await inquirer_1.default.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'input',
|
|
27
|
+
name: 'baseUrl',
|
|
28
|
+
message: 'VOICEVOX Engine Base URL:',
|
|
29
|
+
default: 'http://localhost:50021',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: 'input',
|
|
33
|
+
name: 'speakerId',
|
|
34
|
+
message: 'Default Speaker ID (e.g. 1 for Zundamon, 2 for Shikoku Metan):',
|
|
35
|
+
default: '1',
|
|
36
|
+
validate: (v) => !isNaN(parseInt(v, 10)) || 'Speaker ID must be an integer.',
|
|
37
|
+
},
|
|
38
|
+
]);
|
|
39
|
+
const speakerId = parseInt(answers.speakerId, 10) || 1;
|
|
40
|
+
return {
|
|
41
|
+
config: {
|
|
42
|
+
provider: 'voicevox',
|
|
43
|
+
baseUrl: answers.baseUrl.trim(),
|
|
44
|
+
speakerId,
|
|
45
|
+
maxQueueDepth: 50,
|
|
46
|
+
},
|
|
47
|
+
summary: {
|
|
48
|
+
Provider: 'VOICEVOX',
|
|
49
|
+
'Speaker ID': speakerId,
|
|
50
|
+
'Base URL': answers.baseUrl.trim(),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,275 @@
|
|
|
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 inquirer_1 = __importDefault(require("inquirer"));
|
|
7
|
+
const discovery_1 = require("./discovery");
|
|
8
|
+
const generator_1 = require("./generator");
|
|
9
|
+
const index_1 = require("./index");
|
|
10
|
+
const openrouter_1 = require("./providers/openrouter");
|
|
11
|
+
const knowledge_hub_1 = require("./providers/knowledge-hub");
|
|
12
|
+
const brain_1 = require("./configurators/brain");
|
|
13
|
+
const knowledge_1 = require("./configurators/knowledge");
|
|
14
|
+
const memory_1 = require("./configurators/memory");
|
|
15
|
+
const voice_1 = require("./configurators/voice");
|
|
16
|
+
const body_1 = require("./configurators/body");
|
|
17
|
+
const hands_1 = require("./configurators/hands");
|
|
18
|
+
const behavior_1 = require("./configurators/behavior");
|
|
19
|
+
const vision_1 = require("./configurators/vision");
|
|
20
|
+
// Mock inquirer.prompt
|
|
21
|
+
jest.mock('inquirer', () => ({
|
|
22
|
+
prompt: jest.fn(),
|
|
23
|
+
Separator: jest.fn((label) => ({ type: 'separator', line: label })),
|
|
24
|
+
}));
|
|
25
|
+
describe('Guided Manifest-Driven Configuration UX Specification Tests', () => {
|
|
26
|
+
const registry = discovery_1.OrganRegistry.discover();
|
|
27
|
+
const brainManifest = registry.get('brain');
|
|
28
|
+
const knowledgeManifest = registry.get('knowledge');
|
|
29
|
+
const memoryManifest = registry.get('memory');
|
|
30
|
+
const voiceManifest = registry.get('voice');
|
|
31
|
+
const bodyManifest = registry.get('body');
|
|
32
|
+
const handsManifest = registry.get('hands');
|
|
33
|
+
const behaviorManifest = registry.get('behavior');
|
|
34
|
+
const visionManifest = registry.get('vision');
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
});
|
|
38
|
+
describe('Discrepancy #1: OpenRouter Model Discovery & Brain Configurator', () => {
|
|
39
|
+
test('OpenRouter model provider parses model catalog correctly', async () => {
|
|
40
|
+
const mockModels = [
|
|
41
|
+
{ id: 'openai/gpt-4o-mini', name: 'OpenAI: GPT-4o Mini', description: 'Fast model', context_length: 128000 },
|
|
42
|
+
{ id: 'anthropic/claude-3.5-sonnet', name: 'Anthropic: Claude 3.5 Sonnet', context_length: 200000 },
|
|
43
|
+
];
|
|
44
|
+
const globalFetch = global.fetch;
|
|
45
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
46
|
+
ok: true,
|
|
47
|
+
json: async () => ({ data: mockModels }),
|
|
48
|
+
});
|
|
49
|
+
const provider = new openrouter_1.OpenRouterModelProvider('https://mock-api.com/models');
|
|
50
|
+
const models = await provider.listModels();
|
|
51
|
+
expect(models.length).toBe(2);
|
|
52
|
+
expect(models[0].id).toBe('openai/gpt-4o-mini');
|
|
53
|
+
expect(models[0].name).toBe('OpenAI: GPT-4o Mini');
|
|
54
|
+
expect(models[1].id).toBe('anthropic/claude-3.5-sonnet');
|
|
55
|
+
global.fetch = globalFetch;
|
|
56
|
+
});
|
|
57
|
+
test('Brain configurator selects OpenRouter model and retains canonical model ID', async () => {
|
|
58
|
+
const mockProvider = {
|
|
59
|
+
listModels: jest.fn().mockResolvedValue([
|
|
60
|
+
{ id: 'openai/gpt-4o-mini', name: 'OpenAI: GPT-4o Mini' },
|
|
61
|
+
{ id: 'anthropic/claude-3.5-sonnet', name: 'Anthropic: Claude 3.5 Sonnet' },
|
|
62
|
+
]),
|
|
63
|
+
};
|
|
64
|
+
inquirer_1.default.prompt
|
|
65
|
+
.mockResolvedValueOnce({ provider: 'openrouter' }) // Brain provider
|
|
66
|
+
.mockResolvedValueOnce({ selectedValue: 'openai/gpt-4o-mini' }); // Select model
|
|
67
|
+
const result = await (0, brain_1.configureBrain)({ companionName: 'Sparkle', manifest: brainManifest }, { modelProvider: mockProvider });
|
|
68
|
+
expect(result.config.provider).toBe('openrouter');
|
|
69
|
+
expect(result.config.model).toBe('openai/gpt-4o-mini');
|
|
70
|
+
expect(result.summary?.Model).toBe('openai/gpt-4o-mini');
|
|
71
|
+
expect(result.summary?.Provider).toBe('OpenRouter');
|
|
72
|
+
});
|
|
73
|
+
test('Brain configurator handles discovery failure with curated fallback models', async () => {
|
|
74
|
+
const failingProvider = {
|
|
75
|
+
listModels: jest.fn().mockRejectedValue(new Error('Network request failed')),
|
|
76
|
+
};
|
|
77
|
+
inquirer_1.default.prompt
|
|
78
|
+
.mockResolvedValueOnce({ provider: 'openrouter' }) // Brain provider
|
|
79
|
+
.mockResolvedValueOnce({ failureAction: 'curated' }) // Pick curated fallback
|
|
80
|
+
.mockResolvedValueOnce({ selectedValue: 'anthropic/claude-3.5-sonnet' }); // Select model
|
|
81
|
+
const result = await (0, brain_1.configureBrain)({ companionName: 'Sparkle', manifest: brainManifest }, { modelProvider: failingProvider });
|
|
82
|
+
expect(result.config.provider).toBe('openrouter');
|
|
83
|
+
expect(result.config.model).toBe('anthropic/claude-3.5-sonnet');
|
|
84
|
+
});
|
|
85
|
+
test('Brain configurator handles discovery failure with manual fallback entry', async () => {
|
|
86
|
+
const failingProvider = {
|
|
87
|
+
listModels: jest.fn().mockRejectedValue(new Error('Network request failed')),
|
|
88
|
+
};
|
|
89
|
+
inquirer_1.default.prompt
|
|
90
|
+
.mockResolvedValueOnce({ provider: 'openrouter' })
|
|
91
|
+
.mockResolvedValueOnce({ failureAction: 'manual' })
|
|
92
|
+
.mockResolvedValueOnce({ manualId: 'mistralai/mistral-large' });
|
|
93
|
+
const result = await (0, brain_1.configureBrain)({ companionName: 'Sparkle', manifest: brainManifest }, { modelProvider: failingProvider });
|
|
94
|
+
expect(result.config.provider).toBe('openrouter');
|
|
95
|
+
expect(result.config.model).toBe('mistralai/mistral-large');
|
|
96
|
+
});
|
|
97
|
+
test('Brain configurator supports OpenAI-compatible / Custom endpoint', async () => {
|
|
98
|
+
inquirer_1.default.prompt
|
|
99
|
+
.mockResolvedValueOnce({ provider: 'openai-compatible' })
|
|
100
|
+
.mockResolvedValueOnce({
|
|
101
|
+
baseUrl: 'http://localhost:11434/v1',
|
|
102
|
+
model: 'llama3:latest',
|
|
103
|
+
apiKeyEnv: 'OLLAMA_API_KEY',
|
|
104
|
+
});
|
|
105
|
+
const result = await (0, brain_1.configureBrain)({ companionName: 'Sparkle', manifest: brainManifest });
|
|
106
|
+
expect(result.config.provider).toBe('openai-compatible');
|
|
107
|
+
expect(result.config.model).toBe('llama3:latest');
|
|
108
|
+
expect(result.config.baseUrl).toBe('http://localhost:11434/v1');
|
|
109
|
+
expect(result.config.apiKeyEnv).toBe('OLLAMA_API_KEY');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('Discrepancy #2 & #3: Knowledge Choices & Manifest Metadata Confirmation', () => {
|
|
113
|
+
test('Selecting "Do not use knowledge" sets provider: none and skips discovery', async () => {
|
|
114
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ source: 'none' });
|
|
115
|
+
const result = await (0, knowledge_1.configureKnowledge)({
|
|
116
|
+
companionName: 'Sparkle',
|
|
117
|
+
manifest: knowledgeManifest,
|
|
118
|
+
});
|
|
119
|
+
expect(result.config.provider).toBe('none');
|
|
120
|
+
expect(result.summary?.Source).toBe('Do not use knowledge');
|
|
121
|
+
});
|
|
122
|
+
test('Selecting "E Knowledge Hub" discovers manifest, extracts capabilities, and confirms provider', async () => {
|
|
123
|
+
const mockClient = {
|
|
124
|
+
resolveProvider: jest.fn().mockResolvedValue({
|
|
125
|
+
name: 'e-teyvat',
|
|
126
|
+
displayName: 'E Teyvat',
|
|
127
|
+
package: '@vxnus/e-teyvat',
|
|
128
|
+
version: '1.2.0',
|
|
129
|
+
description: 'Teyvat knowledge provider for Siduri.',
|
|
130
|
+
capabilities: ['Search', 'Retrieval', 'Context injection'],
|
|
131
|
+
source: 'E Knowledge Hub',
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
inquirer_1.default.prompt
|
|
135
|
+
.mockResolvedValueOnce({ source: 'e-hub' }) // Knowledge source
|
|
136
|
+
.mockResolvedValueOnce({ packId: '@vxnus/e-teyvat' }) // Package ID
|
|
137
|
+
.mockResolvedValueOnce({ confirmProvider: 'yes' }); // Confirm provider
|
|
138
|
+
const result = await (0, knowledge_1.configureKnowledge)({ companionName: 'Sparkle', manifest: knowledgeManifest }, { client: mockClient });
|
|
139
|
+
expect(result.config.provider).toBe('e-hub');
|
|
140
|
+
expect(result.config.packId).toBe('@vxnus/e-teyvat');
|
|
141
|
+
expect(result.summary?.Source).toBe('E Knowledge Hub');
|
|
142
|
+
expect(result.summary?.Provider).toBe('E Teyvat');
|
|
143
|
+
expect(result.summary?.Package).toBe('@vxnus/e-teyvat');
|
|
144
|
+
expect(result.summary?.Version).toBe('1.2.0');
|
|
145
|
+
});
|
|
146
|
+
test('Knowledge manifest validation enforces name and version', () => {
|
|
147
|
+
expect(() => (0, knowledge_hub_1.validateKnowledgeManifest)({})).toThrow('Invalid knowledge manifest');
|
|
148
|
+
expect(() => (0, knowledge_hub_1.validateKnowledgeManifest)({ name: 'test' })).toThrow('missing \'version\'');
|
|
149
|
+
const valid = (0, knowledge_hub_1.validateKnowledgeManifest)({
|
|
150
|
+
name: 'e-teyvat',
|
|
151
|
+
displayName: 'E Teyvat',
|
|
152
|
+
version: '1.0.0',
|
|
153
|
+
description: 'Teyvat lore',
|
|
154
|
+
}, '@vxnus/e-teyvat');
|
|
155
|
+
expect(valid.name).toBe('e-teyvat');
|
|
156
|
+
expect(valid.package).toBe('@vxnus/e-teyvat');
|
|
157
|
+
expect(valid.version).toBe('1.0.0');
|
|
158
|
+
});
|
|
159
|
+
test('extractCapabilitiesList formats object and array capabilities correctly', () => {
|
|
160
|
+
const arrayCaps = (0, knowledge_hub_1.extractCapabilitiesList)(['Search', 'Retrieval', 'Custom Tool']);
|
|
161
|
+
expect(arrayCaps).toEqual(['Search', 'Retrieval', 'Custom Tool']);
|
|
162
|
+
const objCaps = (0, knowledge_hub_1.extractCapabilitiesList)({
|
|
163
|
+
search: true,
|
|
164
|
+
retrieval: true,
|
|
165
|
+
contextInjection: true,
|
|
166
|
+
semanticSearch: true,
|
|
167
|
+
});
|
|
168
|
+
expect(objCaps).toContain('Search');
|
|
169
|
+
expect(objCaps).toContain('Retrieval');
|
|
170
|
+
expect(objCaps).toContain('Context injection');
|
|
171
|
+
expect(objCaps).toContain('Semantic search');
|
|
172
|
+
});
|
|
173
|
+
test('Knowledge Hub client fallback returns known pack for @vxnus/e-teyvat', async () => {
|
|
174
|
+
const client = new knowledge_hub_1.KnowledgeHubClient('https://invalid-non-existent-url.local/api');
|
|
175
|
+
const manifest = await client.resolveProvider('@vxnus/e-teyvat');
|
|
176
|
+
expect(manifest.package).toBe('@vxnus/e-teyvat');
|
|
177
|
+
expect(manifest.displayName).toBe('E Teyvat');
|
|
178
|
+
expect(manifest.version).toBe('1.2.0');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('Other Organ Configurators & Generic Router', () => {
|
|
182
|
+
test('Memory configurator configures PostgreSQL with Supabase deployment', async () => {
|
|
183
|
+
inquirer_1.default.prompt
|
|
184
|
+
.mockResolvedValueOnce({ database: 'postgres' })
|
|
185
|
+
.mockResolvedValueOnce({ deployment: 'supabase' });
|
|
186
|
+
const result = await (0, memory_1.configureMemory)({ companionName: 'Sparkle', manifest: memoryManifest });
|
|
187
|
+
expect(result.config.provider).toBe('postgres');
|
|
188
|
+
expect(result.config.deployment).toBe('supabase');
|
|
189
|
+
expect(result.summary?.Deploy).toBe('Supabase');
|
|
190
|
+
});
|
|
191
|
+
test('Voice configurator configures VOICEVOX engine and speaker ID', async () => {
|
|
192
|
+
inquirer_1.default.prompt
|
|
193
|
+
.mockResolvedValueOnce({ provider: 'voicevox' })
|
|
194
|
+
.mockResolvedValueOnce({ baseUrl: 'http://localhost:50021', speakerId: '2' });
|
|
195
|
+
const result = await (0, voice_1.configureVoice)({ companionName: 'Sparkle', manifest: voiceManifest });
|
|
196
|
+
expect(result.config.provider).toBe('voicevox');
|
|
197
|
+
expect(result.config.speakerId).toBe(2);
|
|
198
|
+
expect(result.summary?.['Speaker ID']).toBe(2);
|
|
199
|
+
});
|
|
200
|
+
test('Body configurator configures Live2D and expression', async () => {
|
|
201
|
+
inquirer_1.default.prompt
|
|
202
|
+
.mockResolvedValueOnce({ provider: 'live2d' })
|
|
203
|
+
.mockResolvedValueOnce({ initialExpression: 'happy' });
|
|
204
|
+
const result = await (0, body_1.configureBody)({ companionName: 'Sparkle', manifest: bodyManifest });
|
|
205
|
+
expect(result.config.provider).toBe('live2d');
|
|
206
|
+
expect(result.config.initialExpression).toBe('happy');
|
|
207
|
+
});
|
|
208
|
+
test('Hands configurator configures MCP tool execution timeout', async () => {
|
|
209
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ timeoutSeconds: '15' });
|
|
210
|
+
const result = await (0, hands_1.configureHands)({ companionName: 'Sparkle', manifest: handsManifest });
|
|
211
|
+
expect(result.config.defaultTimeoutMs).toBe(15000);
|
|
212
|
+
});
|
|
213
|
+
test('Behavior configurator configures active self personality preset', async () => {
|
|
214
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ preset: 'cheerful' });
|
|
215
|
+
const result = await (0, behavior_1.configureBehavior)({ companionName: 'Sparkle', manifest: behaviorManifest });
|
|
216
|
+
expect(result.config.provider).toBe('active_self');
|
|
217
|
+
expect(result.config.preset).toBe('cheerful');
|
|
218
|
+
});
|
|
219
|
+
test('Vision configurator configures OpenRouter vision model', async () => {
|
|
220
|
+
inquirer_1.default.prompt.mockResolvedValueOnce({ model: 'gpt-4-vision' });
|
|
221
|
+
const result = await (0, vision_1.configureVision)({ companionName: 'Sparkle', manifest: visionManifest });
|
|
222
|
+
expect(result.config.provider).toBe('openrouter');
|
|
223
|
+
expect(result.config.model).toBe('gpt-4-vision');
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
describe('Review Summary Formatting & Generator Integration', () => {
|
|
227
|
+
test('formatReviewSummary displays actual configuration values and metadata', () => {
|
|
228
|
+
const summaryOutput = (0, index_1.formatReviewSummary)('Sparkle', [brainManifest, memoryManifest, knowledgeManifest, voiceManifest], {
|
|
229
|
+
brain: { Provider: 'OpenRouter', Model: 'openai/gpt-4o-mini' },
|
|
230
|
+
memory: { Database: 'PostgreSQL', Deploy: 'Supabase' },
|
|
231
|
+
knowledge: { Source: 'E Knowledge Hub', Provider: 'E Teyvat', Package: '@vxnus/e-teyvat', Version: '1.2.0' },
|
|
232
|
+
voice: { Provider: 'VOICEVOX', 'Speaker ID': 1 },
|
|
233
|
+
});
|
|
234
|
+
expect(summaryOutput).toContain('Sparkle');
|
|
235
|
+
expect(summaryOutput).toContain('Brain');
|
|
236
|
+
expect(summaryOutput).toContain('OpenRouter');
|
|
237
|
+
expect(summaryOutput).toContain('openai/gpt-4o-mini');
|
|
238
|
+
expect(summaryOutput).toContain('Memory');
|
|
239
|
+
expect(summaryOutput).toContain('PostgreSQL');
|
|
240
|
+
expect(summaryOutput).toContain('Supabase');
|
|
241
|
+
expect(summaryOutput).toContain('Knowledge');
|
|
242
|
+
expect(summaryOutput).toContain('E Knowledge Hub');
|
|
243
|
+
expect(summaryOutput).toContain('E Teyvat');
|
|
244
|
+
expect(summaryOutput).toContain('@vxnus/e-teyvat');
|
|
245
|
+
expect(summaryOutput).toContain('Voice');
|
|
246
|
+
expect(summaryOutput).toContain('VOICEVOX');
|
|
247
|
+
});
|
|
248
|
+
test('generateInstanceFiles accurately embeds configured organ values in siduri.config.json', () => {
|
|
249
|
+
const organConfigs = {
|
|
250
|
+
brain: { provider: 'openrouter', model: 'openai/gpt-4o-mini', apiKeyEnv: 'OPENROUTER_API_KEY' },
|
|
251
|
+
memory: { provider: 'postgres', deployment: 'supabase' },
|
|
252
|
+
knowledge: { provider: 'e-hub', registryUrl: 'https://e.vxnus.xyz/api/v1/knowledge', packId: '@vxnus/e-teyvat' },
|
|
253
|
+
voice: { provider: 'voicevox', speakerId: 2, baseUrl: 'http://localhost:50021' },
|
|
254
|
+
};
|
|
255
|
+
const files = (0, generator_1.generateInstanceFiles)({
|
|
256
|
+
name: 'Sparkle',
|
|
257
|
+
selectedManifests: [brainManifest, memoryManifest, knowledgeManifest, voiceManifest],
|
|
258
|
+
organConfigs,
|
|
259
|
+
});
|
|
260
|
+
const config = JSON.parse(files['siduri.config.json']);
|
|
261
|
+
expect(config.name).toBe('Sparkle');
|
|
262
|
+
expect(config.organs.brain.provider).toBe('openrouter');
|
|
263
|
+
expect(config.organs.brain.model).toBe('openai/gpt-4o-mini');
|
|
264
|
+
expect(config.organs.memory.deployment).toBe('supabase');
|
|
265
|
+
expect(config.organs.knowledge.provider).toBe('e-hub');
|
|
266
|
+
expect(config.organs.knowledge.packId).toBe('@vxnus/e-teyvat');
|
|
267
|
+
expect(config.organs.voice.speakerId).toBe(2);
|
|
268
|
+
// Verify explicit imports in src/index.js
|
|
269
|
+
expect(files['src/index.js']).toContain("import { OpenRouterBrain } from '@siduri-x/brain'");
|
|
270
|
+
expect(files['src/index.js']).toContain("import { PostgresMemoryOrgan } from '@siduri-x/memory'");
|
|
271
|
+
expect(files['src/index.js']).toContain("import { EKnowledgeAdapter } from '@siduri-x/knowledge'");
|
|
272
|
+
expect(files['src/index.js']).toContain("import { VoicevoxAdapter } from '@siduri-x/voice'");
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
package/dist/doctor-db.test.js
CHANGED
|
@@ -44,7 +44,9 @@ describe('Phase 4: Diagnostics and Database Provisioning Tests', () => {
|
|
|
44
44
|
});
|
|
45
45
|
for (const [name, content] of Object.entries(files)) {
|
|
46
46
|
if (typeof content === 'string') {
|
|
47
|
-
|
|
47
|
+
const fullPath = node_path_1.default.join(instanceDir, name);
|
|
48
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(fullPath), { recursive: true });
|
|
49
|
+
node_fs_1.default.writeFileSync(fullPath, content);
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
// 1. Doctor without OPENROUTER_API_KEY -> FAIL (Brain Health Probe fails)
|
|
@@ -73,7 +75,9 @@ describe('Phase 4: Diagnostics and Database Provisioning Tests', () => {
|
|
|
73
75
|
});
|
|
74
76
|
for (const [name, content] of Object.entries(files)) {
|
|
75
77
|
if (typeof content === 'string') {
|
|
76
|
-
|
|
78
|
+
const fullPath = node_path_1.default.join(instanceDir, name);
|
|
79
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(fullPath), { recursive: true });
|
|
80
|
+
node_fs_1.default.writeFileSync(fullPath, content);
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
// Doctor checks both keys
|
|
@@ -102,7 +106,9 @@ describe('Phase 4: Diagnostics and Database Provisioning Tests', () => {
|
|
|
102
106
|
});
|
|
103
107
|
for (const [name, content] of Object.entries(files)) {
|
|
104
108
|
if (typeof content === 'string') {
|
|
105
|
-
|
|
109
|
+
const fullPath = node_path_1.default.join(instanceDir, name);
|
|
110
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(fullPath), { recursive: true });
|
|
111
|
+
node_fs_1.default.writeFileSync(fullPath, content);
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
// 1. Doctor fails without DATABASE_URL
|
package/dist/generator.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface GeneratedInstanceFiles {
|
|
|
6
6
|
'.env.example': string;
|
|
7
7
|
'README.md': string;
|
|
8
8
|
'src/index.js': string;
|
|
9
|
+
'public/index.html': string;
|
|
10
|
+
'docker-compose.yml'?: string;
|
|
9
11
|
createAssetsBodyDir?: boolean;
|
|
10
12
|
}
|
|
11
13
|
export interface InstanceGeneratorOptions {
|