symmetry-cli 1.0.6 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- package/__test__/cli.test.ts +1 -1
- package/dist/constants.js +2 -1
- package/dist/provider.js +57 -44
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/package.json +1 -1
- package/readme.md +2 -2
- package/src/constants.ts +2 -0
- package/src/provider.ts +73 -53
package/__test__/cli.test.ts
CHANGED
package/dist/constants.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.apiProviders = exports.serverMessageKeys = exports.NORMALIZE_REGEX = void 0;
|
3
|
+
exports.apiProviders = exports.serverMessageKeys = exports.PROVIDER_HELLO_TIMEOUT = exports.NORMALIZE_REGEX = void 0;
|
4
4
|
exports.NORMALIZE_REGEX = /\s*\r?\n|\r/g;
|
5
|
+
exports.PROVIDER_HELLO_TIMEOUT = 15000;
|
5
6
|
exports.serverMessageKeys = {
|
6
7
|
challenge: "challenge",
|
7
8
|
conectionSize: "conectionSize",
|
package/dist/provider.js
CHANGED
@@ -22,6 +22,7 @@ class SymmetryProvider {
|
|
22
22
|
this._isPublic = false;
|
23
23
|
this._providerConnections = 0;
|
24
24
|
this._providerSwarm = null;
|
25
|
+
this._serverSwarm = null;
|
25
26
|
this._serverPeer = null;
|
26
27
|
logger_1.logger.info(`🔗 Initializing client using config file: ${configPath}`);
|
27
28
|
this._config = new config_1.ConfigManager(configPath);
|
@@ -50,7 +51,7 @@ class SymmetryProvider {
|
|
50
51
|
if (this._isPublic) {
|
51
52
|
logger_1.logger.info(chalk_1.default.white(`🔑 Server key: ${this._config.get("serverKey")}`));
|
52
53
|
logger_1.logger.info(chalk_1.default.white("🔗 Joining server, please wait."));
|
53
|
-
this.
|
54
|
+
this.joinServer();
|
54
55
|
}
|
55
56
|
process.on("SIGINT", async () => {
|
56
57
|
var _a;
|
@@ -63,62 +64,74 @@ class SymmetryProvider {
|
|
63
64
|
}
|
64
65
|
});
|
65
66
|
}
|
67
|
+
async destroySwarms() {
|
68
|
+
var _a, _b;
|
69
|
+
await ((_a = this._providerSwarm) === null || _a === void 0 ? void 0 : _a.destroy());
|
70
|
+
await ((_b = this._serverSwarm) === null || _b === void 0 ? void 0 : _b.destroy());
|
71
|
+
}
|
66
72
|
async testProviderCall() {
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
const { requestOptions, requestBody } = req;
|
77
|
-
const { protocol, hostname, port, path, method, headers } = requestOptions;
|
78
|
-
const url = `${protocol}://${hostname}:${port}${path}`;
|
79
|
-
logger_1.logger.info(chalk_1.default.white(`🚀 Sending test request to ${url}`));
|
80
|
-
try {
|
81
|
-
const response = await fetch(url, {
|
82
|
-
method,
|
83
|
-
headers,
|
84
|
-
body: JSON.stringify(requestBody),
|
85
|
-
});
|
86
|
-
if (!response.ok) {
|
87
|
-
logger_1.logger.error(chalk_1.default.red(`❌ Server responded with status code: ${response.status}`));
|
88
|
-
throw new Error(`Server responded with status code: ${response.status}`);
|
73
|
+
const testCall = async () => {
|
74
|
+
logger_1.logger.info(chalk_1.default.white(`👋 Saying hello to your provider...`));
|
75
|
+
const testMessages = [
|
76
|
+
{ role: "user", content: "Hello, this is a test message." },
|
77
|
+
];
|
78
|
+
const req = this.buildStreamRequest(testMessages);
|
79
|
+
if (!req) {
|
80
|
+
logger_1.logger.error(chalk_1.default.red("❌ Failed to build test request"));
|
81
|
+
throw new Error("Failed to build test request");
|
89
82
|
}
|
90
|
-
|
91
|
-
|
92
|
-
|
83
|
+
const { requestOptions, requestBody } = req;
|
84
|
+
const { protocol, hostname, port, path, method, headers } = requestOptions;
|
85
|
+
const url = `${protocol}://${hostname}:${port}${path}`;
|
86
|
+
logger_1.logger.info(chalk_1.default.white(`🚀 Sending test request to ${url}`));
|
87
|
+
try {
|
88
|
+
const response = await fetch(url, {
|
89
|
+
method,
|
90
|
+
headers,
|
91
|
+
body: JSON.stringify(requestBody),
|
92
|
+
});
|
93
|
+
if (!response.ok) {
|
94
|
+
logger_1.logger.error(chalk_1.default.red(`❌ Server responded with status code: ${response.status}`));
|
95
|
+
this.destroySwarms();
|
96
|
+
throw new Error(`Server responded with status code: ${response.status}`);
|
97
|
+
}
|
98
|
+
if (!response.body) {
|
99
|
+
logger_1.logger.error(chalk_1.default.red("❌ Failed to get a ReadableStream from the response"));
|
100
|
+
this.destroySwarms();
|
101
|
+
throw new Error("Failed to get a ReadableStream from the response");
|
102
|
+
}
|
103
|
+
logger_1.logger.info(chalk_1.default.white(`📡 Got response, checking stream...`));
|
104
|
+
const reader = response.body.getReader();
|
105
|
+
const { done } = await reader.read();
|
106
|
+
if (done) {
|
107
|
+
logger_1.logger.error(chalk_1.default.red("❌ Stream ended without data"));
|
108
|
+
this.destroySwarms();
|
109
|
+
throw new Error("Stream ended without data");
|
110
|
+
}
|
111
|
+
logger_1.logger.info(chalk_1.default.green(`✅ Test inference call successful!`));
|
93
112
|
}
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
logger_1.logger.error(chalk_1.default.red("❌ Stream ended without data"));
|
99
|
-
throw new Error("Stream ended without data");
|
113
|
+
catch (error) {
|
114
|
+
this.destroySwarms();
|
115
|
+
logger_1.logger.error(chalk_1.default.red(`❌ Error during test inference call: ${error}`));
|
116
|
+
throw error;
|
100
117
|
}
|
101
|
-
logger_1.logger.info(chalk_1.default.
|
102
|
-
}
|
103
|
-
|
104
|
-
logger_1.logger.error(chalk_1.default.red(`❌ Error during test inference call: ${error}`));
|
105
|
-
throw error;
|
106
|
-
}
|
107
|
-
logger_1.logger.info(chalk_1.default.white(`🔗 Proceeding to join server...`));
|
108
|
-
await this.joinServer();
|
118
|
+
logger_1.logger.info(chalk_1.default.white(`🔗 Test call successful!`));
|
119
|
+
};
|
120
|
+
setTimeout(() => testCall(), constants_1.PROVIDER_HELLO_TIMEOUT);
|
109
121
|
}
|
110
122
|
async joinServer() {
|
111
|
-
|
123
|
+
this._serverSwarm = new hyperswarm_1.default();
|
112
124
|
const serverKey = Buffer.from(this._config.get("serverKey"));
|
113
|
-
|
125
|
+
this._serverSwarm.join(hypercore_crypto_1.default.discoveryKey(serverKey), {
|
114
126
|
client: true,
|
115
127
|
server: false,
|
116
128
|
});
|
117
|
-
|
118
|
-
|
129
|
+
this._serverSwarm.flush();
|
130
|
+
this._serverSwarm.on("connection", (peer) => {
|
119
131
|
var _a;
|
120
132
|
this._serverPeer = peer;
|
121
133
|
logger_1.logger.info(chalk_1.default.green("🔗 Connected to server."));
|
134
|
+
this.testProviderCall();
|
122
135
|
this._challenge = hypercore_crypto_1.default.randomBytes(32);
|
123
136
|
this._serverPeer.write((0, utils_1.createMessage)(constants_1.serverMessageKeys.challenge, {
|
124
137
|
challenge: this._challenge,
|
package/install.ps1
CHANGED
@@ -16,7 +16,7 @@ if (!(Get-Command npm -ErrorAction SilentlyContinue)) {
|
|
16
16
|
}
|
17
17
|
|
18
18
|
Print-Color $YELLOW "Installing symmetry-cli globally..."
|
19
|
-
if (npm install -g
|
19
|
+
if (npm install -g symmetry-cli) {
|
20
20
|
Print-Color $GREEN "symmetry-cli installed successfully!"
|
21
21
|
} else {
|
22
22
|
Print-Color $RED "Failed to install symmetry-cli. Please check your npm configuration and try again."
|
@@ -56,4 +56,4 @@ Print-Color $GREEN "Installation complete! You can now run 'symmetry-cli' to sta
|
|
56
56
|
Print-Color $YELLOW "Please edit $provider_yaml to customize your provider settings, especially:"
|
57
57
|
Print-Color $YELLOW " - apiKey: Add your API key if required"
|
58
58
|
Print-Color $YELLOW " - name: Currently set to your system username, change if needed"
|
59
|
-
Print-Color $YELLOW " - public: Set to true by default, change to false if you don't want to be publicly accessible"
|
59
|
+
Print-Color $YELLOW " - public: Set to true by default, change to false if you don't want to be publicly accessible"
|
package/install.sh
CHANGED
@@ -18,7 +18,7 @@ if ! command -v npm >/dev/null 2>&1; then
|
|
18
18
|
fi
|
19
19
|
|
20
20
|
print_color "$YELLOW" "Installing symmetry-cli globally..."
|
21
|
-
if npm install -g
|
21
|
+
if npm install -g symmetry-cli; then
|
22
22
|
print_color "$GREEN" "symmetry-cli installed successfully!"
|
23
23
|
else
|
24
24
|
print_color "$RED" "Failed to install symmetry-cli. Please check your npm configuration and try again."
|
package/package.json
CHANGED
package/readme.md
CHANGED
@@ -18,12 +18,12 @@ To install Symmetry, use the following commands:
|
|
18
18
|
|
19
19
|
For Linux and macOS:
|
20
20
|
```bash
|
21
|
-
curl -fsSL https://
|
21
|
+
curl -fsSL https://www.twinny.dev/symmetry-unix.sh | sh
|
22
22
|
```
|
23
23
|
|
24
24
|
For Windows:
|
25
25
|
```powershell
|
26
|
-
iwr -useb https://
|
26
|
+
iwr -useb https://www.twinny.dev/symmetry-windows.ps1 | iex
|
27
27
|
```
|
28
28
|
|
29
29
|
## Usage
|
package/src/constants.ts
CHANGED
package/src/provider.ts
CHANGED
@@ -14,7 +14,7 @@ import {
|
|
14
14
|
} from "./utils";
|
15
15
|
import { logger } from "./logger";
|
16
16
|
import { Peer, ProviderMessage, InferenceRequest, Message } from "./types";
|
17
|
-
import { serverMessageKeys } from "./constants";
|
17
|
+
import { PROVIDER_HELLO_TIMEOUT, serverMessageKeys } from "./constants";
|
18
18
|
|
19
19
|
export class SymmetryProvider {
|
20
20
|
private _challenge: Buffer | null = null;
|
@@ -24,6 +24,7 @@ export class SymmetryProvider {
|
|
24
24
|
private _isPublic = false;
|
25
25
|
private _providerConnections: number = 0;
|
26
26
|
private _providerSwarm: Hyperswarm | null = null;
|
27
|
+
private _serverSwarm: Hyperswarm | null = null;
|
27
28
|
private _serverPeer: Peer | null = null;
|
28
29
|
|
29
30
|
constructor(configPath: string) {
|
@@ -63,7 +64,7 @@ export class SymmetryProvider {
|
|
63
64
|
chalk.white(`🔑 Server key: ${this._config.get("serverKey")}`)
|
64
65
|
);
|
65
66
|
logger.info(chalk.white("🔗 Joining server, please wait."));
|
66
|
-
this.
|
67
|
+
this.joinServer();
|
67
68
|
}
|
68
69
|
|
69
70
|
process.on("SIGINT", async () => {
|
@@ -78,78 +79,97 @@ export class SymmetryProvider {
|
|
78
79
|
});
|
79
80
|
}
|
80
81
|
|
82
|
+
async destroySwarms() {
|
83
|
+
await this._providerSwarm?.destroy();
|
84
|
+
await this._serverSwarm?.destroy();
|
85
|
+
}
|
86
|
+
|
81
87
|
private async testProviderCall(): Promise<void> {
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
const testCall = async () => {
|
89
|
+
logger.info(chalk.white(`👋 Saying hello to your provider...`));
|
90
|
+
const testMessages: Message[] = [
|
91
|
+
{ role: "user", content: "Hello, this is a test message." },
|
92
|
+
];
|
93
|
+
const req = this.buildStreamRequest(testMessages);
|
94
|
+
|
95
|
+
if (!req) {
|
96
|
+
logger.error(chalk.red("❌ Failed to build test request"));
|
97
|
+
throw new Error("Failed to build test request");
|
98
|
+
}
|
92
99
|
|
93
|
-
|
94
|
-
|
95
|
-
|
100
|
+
const { requestOptions, requestBody } = req;
|
101
|
+
const { protocol, hostname, port, path, method, headers } =
|
102
|
+
requestOptions;
|
103
|
+
const url = `${protocol}://${hostname}:${port}${path}`;
|
104
|
+
|
105
|
+
logger.info(chalk.white(`🚀 Sending test request to ${url}`));
|
106
|
+
|
107
|
+
try {
|
108
|
+
const response = await fetch(url, {
|
109
|
+
method,
|
110
|
+
headers,
|
111
|
+
body: JSON.stringify(requestBody),
|
112
|
+
});
|
113
|
+
|
114
|
+
if (!response.ok) {
|
115
|
+
logger.error(
|
116
|
+
chalk.red(
|
117
|
+
`❌ Server responded with status code: ${response.status}`
|
118
|
+
)
|
119
|
+
);
|
120
|
+
this.destroySwarms();
|
121
|
+
throw new Error(
|
122
|
+
`Server responded with status code: ${response.status}`
|
123
|
+
);
|
124
|
+
}
|
96
125
|
|
97
|
-
|
126
|
+
if (!response.body) {
|
127
|
+
logger.error(
|
128
|
+
chalk.red("❌ Failed to get a ReadableStream from the response")
|
129
|
+
);
|
130
|
+
this.destroySwarms();
|
131
|
+
throw new Error("Failed to get a ReadableStream from the response");
|
132
|
+
}
|
98
133
|
|
99
|
-
|
100
|
-
const response = await fetch(url, {
|
101
|
-
method,
|
102
|
-
headers,
|
103
|
-
body: JSON.stringify(requestBody),
|
104
|
-
});
|
134
|
+
logger.info(chalk.white(`📡 Got response, checking stream...`));
|
105
135
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
}
|
136
|
+
const reader = response.body.getReader();
|
137
|
+
const { done } = await reader.read();
|
138
|
+
if (done) {
|
139
|
+
logger.error(chalk.red("❌ Stream ended without data"));
|
140
|
+
this.destroySwarms();
|
141
|
+
throw new Error("Stream ended without data");
|
142
|
+
}
|
114
143
|
|
115
|
-
|
144
|
+
logger.info(chalk.green(`✅ Test inference call successful!`));
|
145
|
+
} catch (error) {
|
146
|
+
this.destroySwarms();
|
116
147
|
logger.error(
|
117
|
-
chalk.red(
|
148
|
+
chalk.red(`❌ Error during test inference call: ${error}`)
|
118
149
|
);
|
119
|
-
throw
|
150
|
+
throw error;
|
120
151
|
}
|
121
152
|
|
122
|
-
logger.info(chalk.white(
|
123
|
-
|
124
|
-
const reader = response.body.getReader();
|
125
|
-
const { done } = await reader.read();
|
126
|
-
if (done) {
|
127
|
-
logger.error(chalk.red("❌ Stream ended without data"));
|
128
|
-
throw new Error("Stream ended without data");
|
129
|
-
}
|
130
|
-
|
131
|
-
logger.info(chalk.green(`✅ Test inference call successful!`));
|
132
|
-
} catch (error) {
|
133
|
-
logger.error(chalk.red(`❌ Error during test inference call: ${error}`));
|
134
|
-
throw error;
|
135
|
-
}
|
153
|
+
logger.info(chalk.white(`🔗 Test call successful!`));
|
154
|
+
};
|
136
155
|
|
137
|
-
|
138
|
-
await this.joinServer();
|
156
|
+
setTimeout(() => testCall(), PROVIDER_HELLO_TIMEOUT)
|
139
157
|
}
|
140
158
|
|
141
159
|
async joinServer(): Promise<void> {
|
142
|
-
|
160
|
+
this._serverSwarm = new Hyperswarm();
|
143
161
|
const serverKey = Buffer.from(this._config.get("serverKey"));
|
144
|
-
|
162
|
+
this._serverSwarm.join(crypto.discoveryKey(serverKey), {
|
145
163
|
client: true,
|
146
164
|
server: false,
|
147
165
|
});
|
148
|
-
|
149
|
-
|
166
|
+
this._serverSwarm.flush();
|
167
|
+
this._serverSwarm.on("connection", (peer: Peer) => {
|
150
168
|
this._serverPeer = peer;
|
151
169
|
logger.info(chalk.green("🔗 Connected to server."));
|
152
170
|
|
171
|
+
this.testProviderCall();
|
172
|
+
|
153
173
|
this._challenge = crypto.randomBytes(32);
|
154
174
|
|
155
175
|
this._serverPeer.write(
|