apteva 0.1.8 → 0.2.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/package.json +8 -1
- package/src/binary.ts +149 -84
- package/src/providers.ts +35 -53
- package/src/routes/api.ts +2 -2
- package/src/server.ts +14 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apteva",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Run AI agents locally. Multi-provider support for Claude, GPT, Gemini, Llama, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -63,5 +63,12 @@
|
|
|
63
63
|
"@apteva/apteva-kit": "^0.1.102",
|
|
64
64
|
"react": "^18.2.0",
|
|
65
65
|
"react-dom": "^18.2.0"
|
|
66
|
+
},
|
|
67
|
+
"optionalDependencies": {
|
|
68
|
+
"@apteva/agent-darwin-arm64": "^0.2.0",
|
|
69
|
+
"@apteva/agent-darwin-x64": "^0.2.0",
|
|
70
|
+
"@apteva/agent-linux-x64": "^0.2.0",
|
|
71
|
+
"@apteva/agent-linux-arm64": "^0.2.0",
|
|
72
|
+
"@apteva/agent-win32-x64": "^0.2.0"
|
|
66
73
|
}
|
|
67
74
|
}
|
package/src/binary.ts
CHANGED
|
@@ -3,9 +3,10 @@ import { existsSync, mkdirSync, chmodSync } from "fs";
|
|
|
3
3
|
|
|
4
4
|
// Binary configuration
|
|
5
5
|
const BINARY_BASE_URL = "https://github.com/apteva/agent/releases/latest/download";
|
|
6
|
-
const
|
|
6
|
+
const CONNECT_TIMEOUT = 15000; // 15 seconds for initial connection
|
|
7
|
+
const DOWNLOAD_TIMEOUT = 120000; // 120 seconds for full download
|
|
7
8
|
const MAX_RETRIES = 3;
|
|
8
|
-
const RETRY_DELAY =
|
|
9
|
+
const RETRY_DELAY = 1000; // 1 second between retries
|
|
9
10
|
|
|
10
11
|
// ANSI colors for console output
|
|
11
12
|
const c = {
|
|
@@ -16,12 +17,56 @@ const c = {
|
|
|
16
17
|
red: "\x1b[38;5;196m",
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
+
// Map Node.js platform/arch to npm package names
|
|
21
|
+
function getNpmPackageName(): string {
|
|
22
|
+
const platform = process.platform; // darwin, linux, win32
|
|
23
|
+
const arch = process.arch; // x64, arm64
|
|
24
|
+
|
|
25
|
+
// Map to our package naming convention
|
|
26
|
+
const archMap: Record<string, string> = {
|
|
27
|
+
x64: "x64",
|
|
28
|
+
arm64: "arm64",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const mappedArch = archMap[arch] || arch;
|
|
32
|
+
return `@apteva/agent-${platform}-${mappedArch}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Try to find binary from installed npm package
|
|
36
|
+
function findNpmBinary(): string | null {
|
|
37
|
+
const packageName = getNpmPackageName();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Try to require the package - it exports the binary path
|
|
41
|
+
const binaryPath = require(packageName);
|
|
42
|
+
if (existsSync(binaryPath)) {
|
|
43
|
+
return binaryPath;
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// Package not installed, fall through
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Also try direct path resolution in node_modules
|
|
50
|
+
const possiblePaths = [
|
|
51
|
+
join(import.meta.dir, "../../node_modules", packageName, process.platform === "win32" ? "agent.exe" : "agent"),
|
|
52
|
+
join(process.cwd(), "node_modules", packageName, process.platform === "win32" ? "agent.exe" : "agent"),
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
for (const p of possiblePaths) {
|
|
56
|
+
if (existsSync(p)) {
|
|
57
|
+
return p;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Determine platform and architecture for download fallback
|
|
20
65
|
function getPlatformInfo(): { platform: string; arch: string; ext: string } {
|
|
21
66
|
const platform = process.platform === "win32" ? "windows" : process.platform;
|
|
22
67
|
let arch = process.arch;
|
|
23
68
|
|
|
24
|
-
// Normalize architecture names
|
|
69
|
+
// Normalize architecture names for GitHub releases
|
|
25
70
|
if (arch === "x64") arch = "amd64";
|
|
26
71
|
if (arch === "arm64") arch = "arm64";
|
|
27
72
|
|
|
@@ -30,13 +75,13 @@ function getPlatformInfo(): { platform: string; arch: string; ext: string } {
|
|
|
30
75
|
return { platform, arch, ext };
|
|
31
76
|
}
|
|
32
77
|
|
|
33
|
-
// Get binary filename for current platform
|
|
78
|
+
// Get binary filename for current platform (for download)
|
|
34
79
|
export function getBinaryFilename(): string {
|
|
35
80
|
const { platform, arch, ext } = getPlatformInfo();
|
|
36
81
|
return `agent-${platform}-${arch}${ext}`;
|
|
37
82
|
}
|
|
38
83
|
|
|
39
|
-
// Get full binary path
|
|
84
|
+
// Get full binary path in bin directory
|
|
40
85
|
export function getBinaryPath(binDir: string): string {
|
|
41
86
|
return join(binDir, getBinaryFilename());
|
|
42
87
|
}
|
|
@@ -47,31 +92,78 @@ function getDownloadUrl(): string {
|
|
|
47
92
|
return `${BINARY_BASE_URL}/${filename}`;
|
|
48
93
|
}
|
|
49
94
|
|
|
50
|
-
// Check if binary exists
|
|
95
|
+
// Check if binary exists (either from npm or downloaded)
|
|
51
96
|
export function binaryExists(binDir: string): boolean {
|
|
97
|
+
// First check npm package
|
|
98
|
+
const npmBinary = findNpmBinary();
|
|
99
|
+
if (npmBinary) return true;
|
|
100
|
+
|
|
101
|
+
// Then check downloaded binary
|
|
52
102
|
return existsSync(getBinaryPath(binDir));
|
|
53
103
|
}
|
|
54
104
|
|
|
105
|
+
// Get the actual binary path (npm or downloaded)
|
|
106
|
+
export function getActualBinaryPath(binDir: string): string | null {
|
|
107
|
+
// First check npm package
|
|
108
|
+
const npmBinary = findNpmBinary();
|
|
109
|
+
if (npmBinary) return npmBinary;
|
|
110
|
+
|
|
111
|
+
// Then check downloaded binary
|
|
112
|
+
const downloadedPath = getBinaryPath(binDir);
|
|
113
|
+
if (existsSync(downloadedPath)) return downloadedPath;
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
55
118
|
// Helper to delay
|
|
56
119
|
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
57
120
|
|
|
58
|
-
// Download with timeout
|
|
59
|
-
async function
|
|
121
|
+
// Download file with timeout for both connection and body
|
|
122
|
+
async function downloadWithTimeout(url: string): Promise<ArrayBuffer> {
|
|
60
123
|
const controller = new AbortController();
|
|
61
|
-
|
|
124
|
+
|
|
125
|
+
// Timeout for connection
|
|
126
|
+
let timeoutId = setTimeout(() => controller.abort(), CONNECT_TIMEOUT);
|
|
127
|
+
|
|
128
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
129
|
+
clearTimeout(timeoutId);
|
|
130
|
+
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
throw new Error(`HTTP ${response.status}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Timeout for body download
|
|
136
|
+
timeoutId = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT);
|
|
62
137
|
|
|
63
138
|
try {
|
|
64
|
-
const
|
|
139
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
65
140
|
clearTimeout(timeoutId);
|
|
66
|
-
return
|
|
141
|
+
return arrayBuffer;
|
|
67
142
|
} catch (err) {
|
|
68
143
|
clearTimeout(timeoutId);
|
|
69
144
|
throw err;
|
|
70
145
|
}
|
|
71
146
|
}
|
|
72
147
|
|
|
73
|
-
//
|
|
74
|
-
export async function ensureBinary(binDir: string, silent = false): Promise<{
|
|
148
|
+
// Ensure binary exists - check npm first, then download
|
|
149
|
+
export async function ensureBinary(binDir: string, silent = false): Promise<{
|
|
150
|
+
success: boolean;
|
|
151
|
+
path: string;
|
|
152
|
+
error?: string;
|
|
153
|
+
downloaded?: boolean;
|
|
154
|
+
source?: "npm" | "download" | "cached";
|
|
155
|
+
}> {
|
|
156
|
+
// First, check if binary is available from npm package
|
|
157
|
+
const npmBinary = findNpmBinary();
|
|
158
|
+
if (npmBinary) {
|
|
159
|
+
return {
|
|
160
|
+
success: true,
|
|
161
|
+
path: npmBinary,
|
|
162
|
+
downloaded: false,
|
|
163
|
+
source: "npm"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
75
167
|
const binaryPath = getBinaryPath(binDir);
|
|
76
168
|
|
|
77
169
|
// Ensure bin directory exists
|
|
@@ -79,82 +171,26 @@ export async function ensureBinary(binDir: string, silent = false): Promise<{ su
|
|
|
79
171
|
mkdirSync(binDir, { recursive: true });
|
|
80
172
|
}
|
|
81
173
|
|
|
82
|
-
// Check if already
|
|
174
|
+
// Check if already downloaded
|
|
83
175
|
if (existsSync(binaryPath)) {
|
|
84
|
-
return {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// Show downloading message (server.ts already printed "Binary ")
|
|
91
|
-
if (!silent) {
|
|
92
|
-
process.stdout.write(`${c.orange}downloading...${c.reset}`);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
let lastError: string = "";
|
|
96
|
-
|
|
97
|
-
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
98
|
-
try {
|
|
99
|
-
if (!silent && attempt > 1) {
|
|
100
|
-
// Clear line and show retry status
|
|
101
|
-
process.stdout.write(`\r Agent ${c.orange}retry ${attempt}/${MAX_RETRIES}...${c.reset} `);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const response = await fetchWithTimeout(url, DOWNLOAD_TIMEOUT);
|
|
105
|
-
|
|
106
|
-
if (!response.ok) {
|
|
107
|
-
if (response.status === 404) {
|
|
108
|
-
if (!silent) {
|
|
109
|
-
console.log(`\r${c.red}not found${c.reset} `);
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
success: false,
|
|
113
|
-
path: binaryPath,
|
|
114
|
-
error: `Binary not found at ${url}`,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
lastError = `HTTP ${response.status}`;
|
|
118
|
-
if (attempt < MAX_RETRIES) {
|
|
119
|
-
await sleep(RETRY_DELAY);
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
// Download the binary
|
|
124
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
125
|
-
await Bun.write(binaryPath, arrayBuffer);
|
|
126
|
-
|
|
127
|
-
// Make executable on Unix systems
|
|
128
|
-
if (process.platform !== "win32") {
|
|
129
|
-
chmodSync(binaryPath, 0o755);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Show success
|
|
133
|
-
if (!silent) {
|
|
134
|
-
const sizeMB = (arrayBuffer.byteLength / 1024 / 1024).toFixed(1);
|
|
135
|
-
console.log(`\r${c.green}binary ready${c.reset} ${c.gray}(${sizeMB}MB downloaded)${c.reset} `);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return { success: true, path: binaryPath, downloaded: true };
|
|
139
|
-
}
|
|
140
|
-
} catch (err: any) {
|
|
141
|
-
lastError = err.name === "AbortError" ? "timeout" : String(err.message || err);
|
|
142
|
-
if (attempt < MAX_RETRIES) {
|
|
143
|
-
await sleep(RETRY_DELAY);
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
176
|
+
return {
|
|
177
|
+
success: true,
|
|
178
|
+
path: binaryPath,
|
|
179
|
+
downloaded: false,
|
|
180
|
+
source: "cached"
|
|
181
|
+
};
|
|
147
182
|
}
|
|
148
183
|
|
|
149
|
-
//
|
|
184
|
+
// No npm package and no cached binary - show error
|
|
150
185
|
if (!silent) {
|
|
151
|
-
console.log(
|
|
186
|
+
console.log(`${c.red}not found${c.reset}`);
|
|
187
|
+
console.log(`\n Install the agent binary: npm install @apteva/agent-linux-x64`);
|
|
152
188
|
}
|
|
153
189
|
|
|
154
190
|
return {
|
|
155
191
|
success: false,
|
|
156
192
|
path: binaryPath,
|
|
157
|
-
error:
|
|
193
|
+
error: "Binary not found. Install via: npm install @apteva/agent-<platform>",
|
|
158
194
|
};
|
|
159
195
|
}
|
|
160
196
|
|
|
@@ -166,16 +202,45 @@ export function getBinaryStatus(binDir: string): {
|
|
|
166
202
|
downloadUrl: string;
|
|
167
203
|
platform: string;
|
|
168
204
|
arch: string;
|
|
205
|
+
source?: "npm" | "download" | "none";
|
|
169
206
|
} {
|
|
170
207
|
const { platform, arch } = getPlatformInfo();
|
|
171
|
-
|
|
208
|
+
|
|
209
|
+
// Check npm first
|
|
210
|
+
const npmBinary = findNpmBinary();
|
|
211
|
+
if (npmBinary) {
|
|
212
|
+
return {
|
|
213
|
+
exists: true,
|
|
214
|
+
path: npmBinary,
|
|
215
|
+
filename: getBinaryFilename(),
|
|
216
|
+
downloadUrl: getDownloadUrl(),
|
|
217
|
+
platform,
|
|
218
|
+
arch,
|
|
219
|
+
source: "npm",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Check downloaded
|
|
224
|
+
const downloadedPath = getBinaryPath(binDir);
|
|
225
|
+
if (existsSync(downloadedPath)) {
|
|
226
|
+
return {
|
|
227
|
+
exists: true,
|
|
228
|
+
path: downloadedPath,
|
|
229
|
+
filename: getBinaryFilename(),
|
|
230
|
+
downloadUrl: getDownloadUrl(),
|
|
231
|
+
platform,
|
|
232
|
+
arch,
|
|
233
|
+
source: "download",
|
|
234
|
+
};
|
|
235
|
+
}
|
|
172
236
|
|
|
173
237
|
return {
|
|
174
|
-
exists:
|
|
175
|
-
path,
|
|
238
|
+
exists: false,
|
|
239
|
+
path: downloadedPath,
|
|
176
240
|
filename: getBinaryFilename(),
|
|
177
241
|
downloadUrl: getDownloadUrl(),
|
|
178
242
|
platform,
|
|
179
243
|
arch,
|
|
244
|
+
source: "none",
|
|
180
245
|
};
|
|
181
246
|
}
|
package/src/providers.ts
CHANGED
|
@@ -6,91 +6,61 @@ export const PROVIDERS = {
|
|
|
6
6
|
anthropic: {
|
|
7
7
|
id: "anthropic",
|
|
8
8
|
name: "Anthropic",
|
|
9
|
-
displayName: "Anthropic
|
|
9
|
+
displayName: "Anthropic",
|
|
10
10
|
envVar: "ANTHROPIC_API_KEY",
|
|
11
11
|
docsUrl: "https://console.anthropic.com/settings/keys",
|
|
12
12
|
testEndpoint: "https://api.anthropic.com/v1/messages",
|
|
13
13
|
models: [
|
|
14
|
-
{ value: "claude-sonnet-4-
|
|
15
|
-
{ value: "claude-
|
|
16
|
-
{ value: "claude-4-5-sonnet", label: "Claude 4.5 Sonnet" },
|
|
17
|
-
{ value: "claude-4-5-haiku", label: "Claude 4.5 Haiku (Fast)" },
|
|
14
|
+
{ value: "claude-sonnet-4-5", label: "Claude Sonnet 4.5", recommended: true },
|
|
15
|
+
{ value: "claude-haiku-4-5", label: "Claude Haiku 4.5 (Fast)" },
|
|
18
16
|
],
|
|
19
17
|
},
|
|
20
18
|
openai: {
|
|
21
19
|
id: "openai",
|
|
22
20
|
name: "OpenAI",
|
|
23
|
-
displayName: "OpenAI
|
|
21
|
+
displayName: "OpenAI",
|
|
24
22
|
envVar: "OPENAI_API_KEY",
|
|
25
23
|
docsUrl: "https://platform.openai.com/api-keys",
|
|
26
24
|
testEndpoint: "https://api.openai.com/v1/models",
|
|
27
25
|
models: [
|
|
28
26
|
{ value: "gpt-4o", label: "GPT-4o", recommended: true },
|
|
29
27
|
{ value: "gpt-4o-mini", label: "GPT-4o Mini (Fast)" },
|
|
30
|
-
{ value: "gpt-4-turbo", label: "GPT-4 Turbo" },
|
|
31
28
|
],
|
|
32
29
|
},
|
|
33
30
|
groq: {
|
|
34
31
|
id: "groq",
|
|
35
32
|
name: "Groq",
|
|
36
|
-
displayName: "Groq
|
|
33
|
+
displayName: "Groq",
|
|
37
34
|
envVar: "GROQ_API_KEY",
|
|
38
35
|
docsUrl: "https://console.groq.com/keys",
|
|
39
36
|
testEndpoint: "https://api.groq.com/openai/v1/models",
|
|
40
37
|
models: [
|
|
41
38
|
{ value: "llama-3.3-70b-versatile", label: "Llama 3.3 70B", recommended: true },
|
|
42
|
-
{ value: "llama-3.1-8b-instant", label: "Llama 3.1 8B (
|
|
43
|
-
{ value: "mixtral-8x7b-32768", label: "Mixtral 8x7B" },
|
|
39
|
+
{ value: "llama-3.1-8b-instant", label: "Llama 3.1 8B (Fast)" },
|
|
44
40
|
],
|
|
45
41
|
},
|
|
46
42
|
gemini: {
|
|
47
43
|
id: "gemini",
|
|
48
44
|
name: "Google",
|
|
49
|
-
displayName: "Google
|
|
45
|
+
displayName: "Google Gemini",
|
|
50
46
|
envVar: "GEMINI_API_KEY",
|
|
51
47
|
docsUrl: "https://aistudio.google.com/app/apikey",
|
|
52
48
|
testEndpoint: "https://generativelanguage.googleapis.com/v1/models",
|
|
53
49
|
models: [
|
|
54
|
-
{ value: "gemini-
|
|
55
|
-
{ value: "gemini-
|
|
56
|
-
{ value: "gemini-1.5-flash", label: "Gemini 1.5 Flash" },
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
fireworks: {
|
|
60
|
-
id: "fireworks",
|
|
61
|
-
name: "Fireworks",
|
|
62
|
-
displayName: "Fireworks AI",
|
|
63
|
-
envVar: "FIREWORKS_API_KEY",
|
|
64
|
-
docsUrl: "https://fireworks.ai/api-keys",
|
|
65
|
-
testEndpoint: "https://api.fireworks.ai/inference/v1/models",
|
|
66
|
-
models: [
|
|
67
|
-
{ value: "accounts/fireworks/models/llama-v3p3-70b-instruct", label: "Llama 3.3 70B", recommended: true },
|
|
68
|
-
{ value: "accounts/fireworks/models/deepseek-v3", label: "DeepSeek V3" },
|
|
69
|
-
{ value: "accounts/fireworks/models/qwen2p5-72b-instruct", label: "Qwen 2.5 72B" },
|
|
50
|
+
{ value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview (Latest)", recommended: true },
|
|
51
|
+
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview (Fast)" },
|
|
70
52
|
],
|
|
71
53
|
},
|
|
72
54
|
xai: {
|
|
73
55
|
id: "xai",
|
|
74
56
|
name: "xAI",
|
|
75
|
-
displayName: "xAI
|
|
57
|
+
displayName: "xAI Grok",
|
|
76
58
|
envVar: "XAI_API_KEY",
|
|
77
59
|
docsUrl: "https://console.x.ai/",
|
|
78
60
|
testEndpoint: "https://api.x.ai/v1/models",
|
|
79
61
|
models: [
|
|
80
|
-
{ value: "grok-2
|
|
81
|
-
{ value: "grok-
|
|
82
|
-
],
|
|
83
|
-
},
|
|
84
|
-
moonshot: {
|
|
85
|
-
id: "moonshot",
|
|
86
|
-
name: "Moonshot",
|
|
87
|
-
displayName: "Moonshot AI (Kimi)",
|
|
88
|
-
envVar: "MOONSHOT_API_KEY",
|
|
89
|
-
docsUrl: "https://platform.moonshot.cn/console/api-keys",
|
|
90
|
-
testEndpoint: "https://api.moonshot.cn/v1/models",
|
|
91
|
-
models: [
|
|
92
|
-
{ value: "moonshot-v1-128k", label: "Moonshot V1 128K", recommended: true },
|
|
93
|
-
{ value: "moonshot-v1-32k", label: "Moonshot V1 32K" },
|
|
62
|
+
{ value: "grok-2", label: "Grok 2", recommended: true },
|
|
63
|
+
{ value: "grok-2-mini", label: "Grok 2 Mini (Fast)" },
|
|
94
64
|
],
|
|
95
65
|
},
|
|
96
66
|
together: {
|
|
@@ -101,20 +71,32 @@ export const PROVIDERS = {
|
|
|
101
71
|
docsUrl: "https://api.together.xyz/settings/api-keys",
|
|
102
72
|
testEndpoint: "https://api.together.xyz/v1/models",
|
|
103
73
|
models: [
|
|
104
|
-
{ value: "
|
|
105
|
-
{ value: "
|
|
106
|
-
{ value: "deepseek-ai/DeepSeek-V3", label: "DeepSeek V3" },
|
|
74
|
+
{ value: "moonshotai/Kimi-K2.5", label: "Kimi K2.5", recommended: true },
|
|
75
|
+
{ value: "moonshotai/Kimi-K2-Thinking", label: "Kimi K2 Thinking (Reasoning)" },
|
|
107
76
|
],
|
|
108
77
|
},
|
|
109
|
-
|
|
110
|
-
id: "
|
|
111
|
-
name: "
|
|
112
|
-
displayName: "
|
|
113
|
-
envVar: "
|
|
114
|
-
docsUrl: "https://
|
|
115
|
-
testEndpoint: "https://api.
|
|
78
|
+
fireworks: {
|
|
79
|
+
id: "fireworks",
|
|
80
|
+
name: "Fireworks",
|
|
81
|
+
displayName: "Fireworks AI",
|
|
82
|
+
envVar: "FIREWORKS_API_KEY",
|
|
83
|
+
docsUrl: "https://fireworks.ai/api-keys",
|
|
84
|
+
testEndpoint: "https://api.fireworks.ai/inference/v1/models",
|
|
85
|
+
models: [
|
|
86
|
+
{ value: "accounts/fireworks/models/kimi-k2p5", label: "Kimi K2.5", recommended: true },
|
|
87
|
+
{ value: "accounts/fireworks/models/kimi-k2-thinking", label: "Kimi K2 Thinking (Reasoning)" },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
moonshot: {
|
|
91
|
+
id: "moonshot",
|
|
92
|
+
name: "Moonshot",
|
|
93
|
+
displayName: "Moonshot AI",
|
|
94
|
+
envVar: "MOONSHOT_API_KEY",
|
|
95
|
+
docsUrl: "https://platform.moonshot.cn/console/api-keys",
|
|
96
|
+
testEndpoint: "https://api.moonshot.cn/v1/models",
|
|
116
97
|
models: [
|
|
117
|
-
{ value: "
|
|
98
|
+
{ value: "moonshot-v1-128k", label: "Kimi 128K", recommended: true },
|
|
99
|
+
{ value: "moonshot-v1-32k", label: "Kimi 32K (Fast)" },
|
|
118
100
|
],
|
|
119
101
|
},
|
|
120
102
|
} as const;
|
package/src/routes/api.ts
CHANGED
|
@@ -172,8 +172,8 @@ export async function handleApiRequest(req: Request, path: string): Promise<Resp
|
|
|
172
172
|
const proc = spawn({
|
|
173
173
|
cmd: [BINARY_PATH],
|
|
174
174
|
env,
|
|
175
|
-
stdout: "
|
|
176
|
-
stderr: "
|
|
175
|
+
stdout: "ignore",
|
|
176
|
+
stderr: "ignore",
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
agentProcesses.set(agent.id, proc);
|
package/src/server.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { handleApiRequest } from "./routes/api";
|
|
|
3
3
|
import { serveStatic } from "./routes/static";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { initDatabase, AgentDB, ProviderKeysDB } from "./db";
|
|
6
|
-
import { ensureBinary, getBinaryPath, getBinaryStatus } from "./binary";
|
|
6
|
+
import { ensureBinary, getBinaryPath, getBinaryStatus, getActualBinaryPath } from "./binary";
|
|
7
7
|
|
|
8
8
|
const PORT = parseInt(process.env.PORT || "4280");
|
|
9
9
|
const DATA_DIR = process.env.DATA_DIR || join(import.meta.dir, "../data");
|
|
@@ -31,8 +31,18 @@ AgentDB.resetAllStatus();
|
|
|
31
31
|
// In-memory store for running agent processes only
|
|
32
32
|
export const agentProcesses: Map<string, Subprocess> = new Map();
|
|
33
33
|
|
|
34
|
-
// Binary path - can be overridden via environment variable
|
|
35
|
-
export
|
|
34
|
+
// Binary path - can be overridden via environment variable, or found from npm/downloaded
|
|
35
|
+
export function getBinaryPathForAgent(): string {
|
|
36
|
+
// Environment override takes priority
|
|
37
|
+
if (process.env.AGENT_BINARY_PATH) {
|
|
38
|
+
return process.env.AGENT_BINARY_PATH;
|
|
39
|
+
}
|
|
40
|
+
// Otherwise use npm package or downloaded binary
|
|
41
|
+
return getActualBinaryPath(BIN_DIR) || getBinaryPath(BIN_DIR);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Export for legacy compatibility
|
|
45
|
+
export const BINARY_PATH = getBinaryPathForAgent();
|
|
36
46
|
|
|
37
47
|
// Export binary status function for API
|
|
38
48
|
export { getBinaryStatus, BIN_DIR };
|
|
@@ -133,4 +143,4 @@ console.log(`
|
|
|
133
143
|
${c.darkGray}Click link or Cmd/Ctrl+C to copy${c.reset}
|
|
134
144
|
`);
|
|
135
145
|
|
|
136
|
-
export default server
|
|
146
|
+
// Note: Don't use "export default server" - it causes Bun to print "Started server" message
|