genlayer 0.0.31 → 0.0.32-beta.1
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/.github/workflows/publish-beta.yml +41 -0
- package/CHANGELOG.md +4 -0
- package/README.md +28 -0
- package/dist/index.js +35466 -38949
- package/jest.config.js +1 -5
- package/package.json +6 -5
- package/src/commands/general/index.ts +9 -6
- package/src/commands/general/init.ts +38 -54
- package/src/commands/general/start.ts +18 -49
- package/src/lib/clients/system.ts +1 -1
- package/src/lib/interfaces/ISimulatorService.ts +36 -0
- package/src/lib/services/simulator.ts +204 -202
- package/src/types/node-fetch.d.ts +1 -0
- package/tests/actions/init.test.ts +508 -0
- package/tests/commands/init.test.ts +28 -11
- package/tests/utils.ts +2 -2
- package/tsconfig.json +8 -4
|
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as dotenv from "dotenv";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
|
|
5
|
-
import {rpcClient} from "
|
|
5
|
+
import {rpcClient} from "../clients/jsonRpcClient";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_REPO_GH_URL,
|
|
8
8
|
DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
STARTING_TIMEOUT_ATTEMPTS,
|
|
14
14
|
AI_PROVIDERS_CONFIG,
|
|
15
15
|
AiProviders,
|
|
16
|
-
} from "
|
|
16
|
+
} from "../config/simulator";
|
|
17
17
|
import {
|
|
18
18
|
checkCommand,
|
|
19
19
|
getHomeDirectory,
|
|
@@ -24,243 +24,245 @@ import {
|
|
|
24
24
|
removeDockerContainer,
|
|
25
25
|
listDockerImages,
|
|
26
26
|
removeDockerImage,
|
|
27
|
-
} from "
|
|
27
|
+
} from "../clients/system";
|
|
28
28
|
import {MissingRequirementError} from "../errors/missingRequirement";
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const simulatorLocation = getSimulatorLocation();
|
|
37
|
-
const envFilePath = path.join(simulatorLocation, ".env");
|
|
38
|
-
// Transform the config string to object
|
|
39
|
-
const envConfig = dotenv.parse(fs.readFileSync(envFilePath, "utf8"));
|
|
40
|
-
return envConfig[key];
|
|
41
|
-
}
|
|
30
|
+
import {
|
|
31
|
+
ISimulatorService,
|
|
32
|
+
DownloadSimulatorResultType,
|
|
33
|
+
WaitForSimulatorToBeReadyResultType,
|
|
34
|
+
InitializeDatabaseResultType,
|
|
35
|
+
} from "../interfaces/ISimulatorService";
|
|
42
36
|
|
|
43
37
|
function sleep(millliseconds: number): Promise<void> {
|
|
44
38
|
return new Promise(resolve => setTimeout(resolve, millliseconds));
|
|
45
39
|
}
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
export class SimulatorService implements ISimulatorService {
|
|
42
|
+
public getSimulatorLocation(): string {
|
|
43
|
+
return path.join(getHomeDirectory(), "genlayer-simulator");
|
|
44
|
+
}
|
|
50
45
|
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
public readEnvConfigValue(key: string): string {
|
|
47
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
48
|
+
const envFilePath = path.join(simulatorLocation, ".env");
|
|
49
|
+
// Transform the config string to object
|
|
50
|
+
const envConfig = dotenv.parse(fs.readFileSync(envFilePath, "utf8"));
|
|
51
|
+
return envConfig[key];
|
|
52
|
+
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
envConfig[key] = newConfig[key];
|
|
58
|
-
});
|
|
54
|
+
public addConfigToEnvFile(newConfig: Record<string, string>): void {
|
|
55
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
56
|
+
const envFilePath = path.join(simulatorLocation, ".env");
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.map(key => {
|
|
63
|
-
return `${key}=${envConfig[key]}`;
|
|
64
|
-
})
|
|
65
|
-
.join("\n");
|
|
58
|
+
// Create a backup of the original .env file
|
|
59
|
+
fs.writeFileSync(`${envFilePath}.bak`, fs.readFileSync(envFilePath));
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
// Transform the config string to object
|
|
62
|
+
const envConfig = dotenv.parse(fs.readFileSync(envFilePath, "utf8"));
|
|
63
|
+
Object.keys(newConfig).forEach(key => {
|
|
64
|
+
envConfig[key] = newConfig[key];
|
|
65
|
+
});
|
|
70
66
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
requirementsInstalled.git = true;
|
|
81
|
-
} catch (error) {
|
|
82
|
-
if (!(error instanceof MissingRequirementError)) {
|
|
83
|
-
throw error;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
try {
|
|
87
|
-
await checkCommand("docker --version", "docker");
|
|
88
|
-
requirementsInstalled.docker = true;
|
|
89
|
-
} catch (error: any) {
|
|
90
|
-
if (!(error instanceof MissingRequirementError)) {
|
|
91
|
-
throw error;
|
|
92
|
-
}
|
|
67
|
+
// Transform the updated config object back into a string
|
|
68
|
+
const updatedConfig = Object.keys(envConfig)
|
|
69
|
+
.map(key => {
|
|
70
|
+
return `${key}=${envConfig[key]}`;
|
|
71
|
+
})
|
|
72
|
+
.join("\n");
|
|
73
|
+
|
|
74
|
+
// Write the new .env file
|
|
75
|
+
fs.writeFileSync(envFilePath, updatedConfig);
|
|
93
76
|
}
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
public async checkRequirements(): Promise<Record<string, boolean>> {
|
|
79
|
+
const requirementsInstalled = {
|
|
80
|
+
git: false,
|
|
81
|
+
docker: false,
|
|
82
|
+
};
|
|
83
|
+
|
|
96
84
|
try {
|
|
97
|
-
await checkCommand("
|
|
85
|
+
await checkCommand("git --version", "git");
|
|
86
|
+
requirementsInstalled.git = true;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (!(error instanceof MissingRequirementError)) {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await checkCommand("docker --version", "docker");
|
|
94
|
+
requirementsInstalled.docker = true;
|
|
98
95
|
} catch (error: any) {
|
|
99
|
-
|
|
96
|
+
if (!(error instanceof MissingRequirementError)) {
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (requirementsInstalled.docker) {
|
|
102
|
+
try {
|
|
103
|
+
await checkCommand("docker ps", "docker");
|
|
104
|
+
} catch (error: any) {
|
|
105
|
+
await executeCommand(DEFAULT_RUN_DOCKER_COMMAND);
|
|
106
|
+
}
|
|
100
107
|
}
|
|
108
|
+
|
|
109
|
+
return requirementsInstalled;
|
|
101
110
|
}
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
public async downloadSimulator(branch: string = "main"): Promise<DownloadSimulatorResultType> {
|
|
113
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
await executeCommand(cmdsByPlatform, "git");
|
|
117
|
-
} catch (error: any) {
|
|
118
|
-
const simulatorLocationExists = fs.existsSync(simulatorLocation);
|
|
119
|
-
if (simulatorLocationExists) {
|
|
120
|
-
return {wasInstalled: true};
|
|
115
|
+
try {
|
|
116
|
+
const gitCommand = `git clone -b ${branch} ${DEFAULT_REPO_GH_URL} ${simulatorLocation}`;
|
|
117
|
+
const cmdsByPlatform = {darwin: gitCommand, win32: gitCommand, linux: gitCommand};
|
|
118
|
+
await executeCommand(cmdsByPlatform, "git");
|
|
119
|
+
} catch (error: any) {
|
|
120
|
+
const simulatorLocationExists = fs.existsSync(simulatorLocation);
|
|
121
|
+
if (simulatorLocationExists) {
|
|
122
|
+
return {wasInstalled: true};
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
121
125
|
}
|
|
122
|
-
|
|
126
|
+
return {wasInstalled: false};
|
|
123
127
|
}
|
|
124
|
-
return {wasInstalled: false};
|
|
125
|
-
}
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
129
|
+
public async updateSimulator(branch: string = "main"): Promise<boolean> {
|
|
130
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
131
|
+
const gitCleanCommand = `git -C "${simulatorLocation}" clean -f`;
|
|
132
|
+
const cleanCmdsByPlatform = {darwin: gitCleanCommand, win32: gitCleanCommand, linux: gitCleanCommand};
|
|
133
|
+
await executeCommand(cleanCmdsByPlatform, "git");
|
|
134
|
+
|
|
135
|
+
const gitFetchCommand = `git -C "${simulatorLocation}" fetch`;
|
|
136
|
+
const fetchCmdsByPlatform = {darwin: gitFetchCommand, win32: gitFetchCommand, linux: gitFetchCommand};
|
|
137
|
+
await executeCommand(fetchCmdsByPlatform, "git");
|
|
138
|
+
|
|
139
|
+
const gitCheckoutCommand = `git -C "${simulatorLocation}" checkout ${branch}`;
|
|
140
|
+
const checkoutCmdsByPlatform = {
|
|
141
|
+
darwin: gitCheckoutCommand,
|
|
142
|
+
win32: gitCheckoutCommand,
|
|
143
|
+
linux: gitCheckoutCommand,
|
|
144
|
+
};
|
|
145
|
+
await executeCommand(checkoutCmdsByPlatform, "git");
|
|
134
146
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
147
|
+
const gitPullCommand = `git -C "${simulatorLocation}" pull`;
|
|
148
|
+
const pullCmdsByPlatform = {darwin: gitPullCommand, win32: gitPullCommand, linux: gitPullCommand};
|
|
149
|
+
await executeCommand(pullCmdsByPlatform, "git");
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
141
152
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
153
|
+
public async pullOllamaModel(): Promise<boolean> {
|
|
154
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
155
|
+
const cmdsByPlatform = DEFAULT_PULL_OLLAMA_COMMAND(simulatorLocation);
|
|
156
|
+
await executeCommand(cmdsByPlatform);
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
public async configSimulator(newConfig: Record<string, string>): Promise<boolean> {
|
|
161
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
162
|
+
const envExample = path.join(simulatorLocation, ".env.example");
|
|
163
|
+
const envFilePath = path.join(simulatorLocation, ".env");
|
|
164
|
+
fs.copyFileSync(envExample, envFilePath);
|
|
165
|
+
this.addConfigToEnvFile(newConfig);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export async function waitForSimulatorToBeReady(
|
|
164
|
-
retries: number = STARTING_TIMEOUT_ATTEMPTS,
|
|
165
|
-
): Promise<WaitForSimulatorToBeReadyResultType> {
|
|
166
|
-
console.log("Waiting for the simulator to start up...");
|
|
167
|
-
try {
|
|
168
|
-
const response = await rpcClient.request({method: "ping", params: []});
|
|
169
|
-
if (response && response.result.status === "OK") {
|
|
170
|
-
return {initialized: true};
|
|
171
|
-
}
|
|
172
|
-
if (retries > 0) {
|
|
173
|
-
await sleep(STARTING_TIMEOUT_WAIT_CYLCE);
|
|
174
|
-
return waitForSimulatorToBeReady(retries - 1);
|
|
175
|
-
}
|
|
176
|
-
} catch (error: any) {
|
|
177
|
-
if (
|
|
178
|
-
(error.name === "FetchError" ||
|
|
179
|
-
error.message.includes("Fetch Error") ||
|
|
180
|
-
error.message.includes("ECONNRESET") ||
|
|
181
|
-
error.message.includes("ECONNREFUSED") ||
|
|
182
|
-
error.message.includes("socket hang up")) &&
|
|
183
|
-
retries > 0
|
|
184
|
-
) {
|
|
185
|
-
await sleep(STARTING_TIMEOUT_WAIT_CYLCE * 2);
|
|
186
|
-
return waitForSimulatorToBeReady(retries - 1);
|
|
187
|
-
}
|
|
188
|
-
return {initialized: false, errorCode: "ERROR", errorMessage: error.message};
|
|
169
|
+
public runSimulator(): Promise<{stdout: string; stderr: string}> {
|
|
170
|
+
const simulatorLocation = this.getSimulatorLocation();
|
|
171
|
+
const commandsByPlatform = DEFAULT_RUN_SIMULATOR_COMMAND(simulatorLocation);
|
|
172
|
+
return executeCommand(commandsByPlatform);
|
|
189
173
|
}
|
|
190
174
|
|
|
191
|
-
|
|
192
|
-
|
|
175
|
+
public async waitForSimulatorToBeReady(
|
|
176
|
+
retries: number = STARTING_TIMEOUT_ATTEMPTS,
|
|
177
|
+
): Promise<WaitForSimulatorToBeReadyResultType> {
|
|
178
|
+
console.log("Waiting for the simulator to start up...");
|
|
179
|
+
try {
|
|
180
|
+
const response = await rpcClient.request({method: "ping", params: []});
|
|
181
|
+
|
|
182
|
+
//Compatibility with current simulator version
|
|
183
|
+
if (response && (response.result.status === "OK" || response.result.data.status === "OK")) {
|
|
184
|
+
return {initialized: true};
|
|
185
|
+
}
|
|
186
|
+
if (retries > 0) {
|
|
187
|
+
await sleep(STARTING_TIMEOUT_WAIT_CYLCE);
|
|
188
|
+
return this.waitForSimulatorToBeReady(retries - 1);
|
|
189
|
+
}
|
|
190
|
+
} catch (error: any) {
|
|
191
|
+
if (
|
|
192
|
+
(error.name === "FetchError" ||
|
|
193
|
+
error.message.includes("Fetch Error") ||
|
|
194
|
+
error.message.includes("ECONNRESET") ||
|
|
195
|
+
error.message.includes("ECONNREFUSED") ||
|
|
196
|
+
error.message.includes("socket hang up")) &&
|
|
197
|
+
retries > 0
|
|
198
|
+
) {
|
|
199
|
+
await sleep(STARTING_TIMEOUT_WAIT_CYLCE * 2);
|
|
200
|
+
return this.waitForSimulatorToBeReady(retries - 1);
|
|
201
|
+
}
|
|
202
|
+
return {initialized: false, errorCode: "ERROR", errorMessage: error.message};
|
|
203
|
+
}
|
|
193
204
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
205
|
+
return {initialized: false, errorCode: "TIMEOUT"};
|
|
206
|
+
}
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
public createRandomValidators(numValidators: number, llmProviders: AiProviders[]): Promise<any> {
|
|
209
|
+
return rpcClient.request({
|
|
210
|
+
method: "create_random_validators",
|
|
211
|
+
params: [numValidators, 1, 10, llmProviders],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
202
214
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return {createResponse, tablesResponse};
|
|
207
|
-
}
|
|
215
|
+
public deleteAllValidators(): Promise<any> {
|
|
216
|
+
return rpcClient.request({method: "delete_all_validators", params: []});
|
|
217
|
+
}
|
|
208
218
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
219
|
+
public getAiProvidersOptions(withHint: boolean = true): Array<{name: string; value: string}> {
|
|
220
|
+
return Object.values(AI_PROVIDERS_CONFIG).map(providerConfig => {
|
|
221
|
+
return {
|
|
222
|
+
name: `${providerConfig.name}${withHint ? ` ${providerConfig.hint}` : ""}`,
|
|
223
|
+
value: providerConfig.cliOptionValue,
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}
|
|
215
227
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
228
|
+
public getFrontendUrl(): string {
|
|
229
|
+
const frontendPort = this.readEnvConfigValue("FRONTEND_PORT");
|
|
230
|
+
return `http://localhost:${frontendPort}`;
|
|
231
|
+
}
|
|
219
232
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return
|
|
223
|
-
|
|
224
|
-
value: providerConfig.cliOptionValue,
|
|
225
|
-
};
|
|
226
|
-
});
|
|
227
|
-
}
|
|
233
|
+
public async openFrontend(): Promise<boolean> {
|
|
234
|
+
await openUrl(this.getFrontendUrl());
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
228
237
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
238
|
+
public async resetDockerContainers(): Promise<boolean> {
|
|
239
|
+
const containers = await listDockerContainers();
|
|
240
|
+
const genlayerContainers = containers.filter((container: string) =>
|
|
241
|
+
container.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX),
|
|
242
|
+
);
|
|
243
|
+
const containersStopPromises = genlayerContainers.map((container: string) =>
|
|
244
|
+
stopDockerContainer(container),
|
|
245
|
+
);
|
|
246
|
+
await Promise.all(containersStopPromises);
|
|
247
|
+
|
|
248
|
+
const containersRemovePromises = genlayerContainers.map((container: string) =>
|
|
249
|
+
removeDockerContainer(container),
|
|
250
|
+
);
|
|
251
|
+
await Promise.all(containersRemovePromises);
|
|
252
|
+
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
233
255
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
256
|
+
public async resetDockerImages(): Promise<boolean> {
|
|
257
|
+
const images = await listDockerImages();
|
|
258
|
+
const genlayerImages = images.filter((image: string) =>
|
|
259
|
+
image.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX),
|
|
260
|
+
);
|
|
261
|
+
const imagesRemovePromises = genlayerImages.map((image: string) => removeDockerImage(image));
|
|
262
|
+
await Promise.all(imagesRemovePromises);
|
|
238
263
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const genlayerContainers = containers.filter((container: string) =>
|
|
242
|
-
container.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX),
|
|
243
|
-
);
|
|
244
|
-
const containersStopPromises = genlayerContainers.map((container: string) =>
|
|
245
|
-
stopDockerContainer(container),
|
|
246
|
-
);
|
|
247
|
-
await Promise.all(containersStopPromises);
|
|
248
|
-
|
|
249
|
-
const containersRemovePromises = genlayerContainers.map((container: string) =>
|
|
250
|
-
removeDockerContainer(container),
|
|
251
|
-
);
|
|
252
|
-
await Promise.all(containersRemovePromises);
|
|
253
|
-
|
|
254
|
-
return true;
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
255
266
|
}
|
|
256
267
|
|
|
257
|
-
export
|
|
258
|
-
const images = await listDockerImages();
|
|
259
|
-
const genlayerImages = images.filter((image: string) =>
|
|
260
|
-
image.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX),
|
|
261
|
-
);
|
|
262
|
-
const imagesRemovePromises = genlayerImages.map((image: string) => removeDockerImage(image));
|
|
263
|
-
await Promise.all(imagesRemovePromises);
|
|
264
|
-
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
268
|
+
export default new SimulatorService();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "node-fetch";
|