langtrain 0.1.6 → 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/cli.d.mts +0 -2
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +297 -125
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +299 -127
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +65 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +63 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
- package/src/agent.ts +54 -0
- package/src/cli.ts +197 -50
- package/src/index.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langtrain",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Unified JavaScript SDK for Langtrain Ecosystem",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@clack/prompts": "^1.0.1",
|
|
40
|
+
"axios": "^1.13.5",
|
|
40
41
|
"commander": "^14.0.3",
|
|
42
|
+
"conf": "^15.1.0",
|
|
43
|
+
"gradient-string": "^3.0.0",
|
|
41
44
|
"kleur": "^4.1.5"
|
|
42
45
|
}
|
|
43
46
|
}
|
package/src/agent.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
|
|
3
|
+
export interface Agent {
|
|
4
|
+
id: string;
|
|
5
|
+
workspace_id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
model_id?: string;
|
|
9
|
+
config: any;
|
|
10
|
+
is_active: boolean;
|
|
11
|
+
created_at: string;
|
|
12
|
+
updated_at: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AgentRun {
|
|
16
|
+
id: string;
|
|
17
|
+
conversation_id: string;
|
|
18
|
+
success: boolean;
|
|
19
|
+
output?: any;
|
|
20
|
+
error?: string;
|
|
21
|
+
latency_ms: number;
|
|
22
|
+
tokens_used: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class AgentClient {
|
|
26
|
+
private client: AxiosInstance;
|
|
27
|
+
|
|
28
|
+
constructor(private config: { apiKey: string, baseUrl?: string }) {
|
|
29
|
+
this.client = axios.create({
|
|
30
|
+
baseURL: config.baseUrl || 'https://api.langtrain.ai/api/v1',
|
|
31
|
+
headers: {
|
|
32
|
+
'X-API-Key': config.apiKey,
|
|
33
|
+
'Content-Type': 'application/json'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async list(workspaceId?: string): Promise<Agent[]> {
|
|
39
|
+
const params: any = {};
|
|
40
|
+
if (workspaceId) params.workspace_id = workspaceId;
|
|
41
|
+
|
|
42
|
+
const response = await this.client.get<{ agents: Agent[] }>('/agents', { params });
|
|
43
|
+
return response.data.agents;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async execute(agentId: string, input: any, messages: any[] = [], conversationId?: string): Promise<AgentRun> {
|
|
47
|
+
const response = await this.client.post<AgentRun>(`/agents/${agentId}/execute`, {
|
|
48
|
+
input,
|
|
49
|
+
messages,
|
|
50
|
+
conversation_id: conversationId
|
|
51
|
+
});
|
|
52
|
+
return response.data;
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,64 +1,205 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { intro, outro, select, text, spinner, isCancel, cancel } from '@clack/prompts';
|
|
3
|
-
import { bgCyan, black, red, green } from 'kleur/colors';
|
|
2
|
+
import { intro, outro, select, text, spinner, isCancel, cancel, password } from '@clack/prompts';
|
|
3
|
+
import { bgCyan, black, red, green, yellow, gray } from 'kleur/colors';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
|
-
import { Langvision, Langtune } from './index';
|
|
5
|
+
import { Langvision, Langtune, AgentClient, Agent } from './index';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import gradient from 'gradient-string';
|
|
6
10
|
|
|
7
|
-
//
|
|
8
|
-
const
|
|
9
|
-
const
|
|
11
|
+
// Configuration
|
|
12
|
+
const CONFIG_DIR = path.join(os.homedir(), '.langtrain');
|
|
13
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
14
|
+
|
|
15
|
+
function getConfig() {
|
|
16
|
+
if (!fs.existsSync(CONFIG_FILE)) return {};
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function saveConfig(config: any) {
|
|
25
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
26
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const packageJson = require(path.join(__dirname, '../package.json'));
|
|
10
32
|
|
|
11
33
|
async function main() {
|
|
12
34
|
const program = new Command();
|
|
35
|
+
const version = packageJson.version;
|
|
13
36
|
|
|
14
37
|
program
|
|
15
38
|
.name('langtrain')
|
|
16
|
-
.description('Langtrain CLI for AI Model Fine-tuning and Generation')
|
|
17
|
-
.version(
|
|
39
|
+
.description(packageJson.description || 'Langtrain CLI for AI Model Fine-tuning and Generation')
|
|
40
|
+
.version(version);
|
|
18
41
|
|
|
19
42
|
program.action(async () => {
|
|
20
43
|
console.clear();
|
|
21
|
-
intro(`${bgCyan(black(' langtrain '))}`);
|
|
22
|
-
|
|
23
|
-
const operation = await select({
|
|
24
|
-
message: 'Select an operation:',
|
|
25
|
-
options: [
|
|
26
|
-
{ value: 'tune-finetune', label: '🧠 Fine-tune Text Model (Langtune)' },
|
|
27
|
-
{ value: 'tune-generate', label: '📝 Generate Text (Langtune)' },
|
|
28
|
-
{ value: 'vision-finetune', label: '👁️ Fine-tune Vision Model (Langvision)' },
|
|
29
|
-
{ value: 'vision-generate', label: '🖼️ Generate Vision Response (Langvision)' },
|
|
30
|
-
{ value: 'exit', label: '🚪 Exit' }
|
|
31
|
-
],
|
|
32
|
-
});
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
// Gradient Banner
|
|
46
|
+
const banner = `
|
|
47
|
+
██╗ █████╗ ███╗ ██╗ ██████╗████████╗██████╗ █████╗ ██╗███╗ ██╗
|
|
48
|
+
██║ ██╔══██╗████╗ ██║██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██║████╗ ██║
|
|
49
|
+
██║ ███████║██╔██╗ ██║██║ ███╗ ██║ ██████╔╝███████║██║██╔██╗ ██║
|
|
50
|
+
██║ ██╔══██║██║╚██╗██║██║ ██║ ██║ ██╔══██╗██╔══██║██║██║╚██╗██║
|
|
51
|
+
███████╗██║ ██║██║ ╚████║╚██████╔╝ ██║ ██║ ██║██║ ██║██║██║ ╚████║
|
|
52
|
+
╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
|
|
53
|
+
`;
|
|
54
|
+
console.log(gradient(['#00DC82', '#36E4DA', '#0047E1'])(banner)); // Custom Langtrain Green-Cyan-Blue gradient
|
|
55
|
+
intro(`${bgCyan(black(` Langtrain SDK v${version} `))}`);
|
|
56
|
+
|
|
57
|
+
// Check auth (only show login if missing)
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
if (!config.apiKey) {
|
|
60
|
+
intro(yellow('Authentication required'));
|
|
61
|
+
await handleLogin();
|
|
37
62
|
}
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
// Operation Handlers Map (O(1) lookup)
|
|
65
|
+
const handlers: Record<string, (clients?: any) => Promise<void>> = {
|
|
66
|
+
'login': handleLogin,
|
|
67
|
+
'tune-finetune': (c) => handleTuneFinetune(c.tune),
|
|
68
|
+
'tune-generate': (c) => handleTuneGenerate(c.tune),
|
|
69
|
+
'vision-finetune': (c) => handleVisionFinetune(c.vision),
|
|
70
|
+
'vision-generate': (c) => handleVisionGenerate(c.vision),
|
|
71
|
+
'agent-list': (c) => handleAgentList(c.agent),
|
|
72
|
+
'exit': async () => { outro('Goodbye!'); process.exit(0); },
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
while (true) {
|
|
76
|
+
const operation = await select({
|
|
77
|
+
message: 'Select an operation:',
|
|
78
|
+
options: [
|
|
79
|
+
{ value: 'group-agents', label: '🤖 Agents (Server)', hint: 'Chat with custom agents' },
|
|
80
|
+
{ value: 'agent-list', label: ' ↳ List & Run Agents' },
|
|
81
|
+
|
|
82
|
+
{ value: 'group-tune', label: '🧠 Langtune (LLM)', hint: 'Fine-tuning & Text Generation' },
|
|
83
|
+
{ value: 'tune-finetune', label: ' ↳ Fine-tune Text Model' },
|
|
84
|
+
{ value: 'tune-generate', label: ' ↳ Generate Text' },
|
|
85
|
+
|
|
86
|
+
{ value: 'group-vision', label: '👁️ Langvision (Vision)', hint: 'Vision Analysis & Tuning' },
|
|
87
|
+
{ value: 'vision-finetune', label: ' ↳ Fine-tune Vision Model' },
|
|
88
|
+
{ value: 'vision-generate', label: ' ↳ Generate Vision Response' },
|
|
89
|
+
|
|
90
|
+
{ value: 'group-settings', label: '⚙️ Settings' },
|
|
91
|
+
{ value: 'login', label: ' ↳ Update API Key' },
|
|
92
|
+
{ value: 'exit', label: ' ↳ Exit' }
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (isCancel(operation)) {
|
|
97
|
+
outro('Goodbye!');
|
|
98
|
+
process.exit(0);
|
|
48
99
|
}
|
|
49
|
-
} catch (error: any) {
|
|
50
|
-
outro(red(`Error: ${error.message}`));
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
100
|
|
|
54
|
-
|
|
101
|
+
if (typeof operation === 'string') {
|
|
102
|
+
if (operation.startsWith('group-')) continue;
|
|
103
|
+
|
|
104
|
+
// Execute handler via map lookup
|
|
105
|
+
const handler = handlers[operation];
|
|
106
|
+
if (handler) {
|
|
107
|
+
try {
|
|
108
|
+
// Re-read config & re-init clients freshly for each operation
|
|
109
|
+
const currentConfig = getConfig();
|
|
110
|
+
const clients = {
|
|
111
|
+
vision: new Langvision({ apiKey: currentConfig.apiKey }),
|
|
112
|
+
tune: new Langtune({ apiKey: currentConfig.apiKey }),
|
|
113
|
+
agent: new AgentClient({ apiKey: currentConfig.apiKey, baseUrl: currentConfig.baseUrl })
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
await handler(clients);
|
|
117
|
+
} catch (error: any) {
|
|
118
|
+
outro(red(`Error: ${error.message}`));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
55
123
|
});
|
|
56
124
|
|
|
57
125
|
program.parse(process.argv);
|
|
58
126
|
}
|
|
59
127
|
|
|
128
|
+
async function handleLogin() {
|
|
129
|
+
const apiKey = await password({
|
|
130
|
+
message: 'Enter your new Langtrain API Key:',
|
|
131
|
+
validate(value) {
|
|
132
|
+
if (!value || value.length === 0) return 'API Key is required';
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (isCancel(apiKey)) cancel('Operation cancelled');
|
|
137
|
+
|
|
138
|
+
const config = getConfig();
|
|
139
|
+
saveConfig({ ...config, apiKey });
|
|
140
|
+
intro(green('API Key updated successfully!'));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function handleAgentList(client: AgentClient) {
|
|
144
|
+
const s = spinner();
|
|
145
|
+
s.start('Fetching agents...');
|
|
146
|
+
const agents = await client.list();
|
|
147
|
+
s.stop(`Found ${agents.length} agents`);
|
|
148
|
+
|
|
149
|
+
if (agents.length === 0) {
|
|
150
|
+
intro(yellow('No agents found in your workspace.'));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const agentId = await select({
|
|
155
|
+
message: 'Select an agent to run:',
|
|
156
|
+
options: agents.map(a => ({ value: a.id, label: a.name, hint: a.description || 'No description' }))
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (isCancel(agentId)) return;
|
|
160
|
+
|
|
161
|
+
await handleAgentRun(client, agentId as string, agents.find(a => a.id === agentId)?.name || 'Agent');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function handleAgentRun(client: AgentClient, agentId: string, agentName: string) {
|
|
165
|
+
intro(bgCyan(black(` Chatting with ${agentName} `)));
|
|
166
|
+
console.log(gray('Type "exit" to quit conversation.'));
|
|
167
|
+
|
|
168
|
+
let conversationId: string | undefined = undefined;
|
|
169
|
+
|
|
170
|
+
while (true) {
|
|
171
|
+
const input = await text({
|
|
172
|
+
message: 'You:',
|
|
173
|
+
placeholder: 'Type a message...',
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (isCancel(input) || input === 'exit') {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const s = spinner();
|
|
181
|
+
s.start('Agent is thinking...');
|
|
182
|
+
try {
|
|
183
|
+
const result = await client.execute(agentId, { prompt: input }, [], conversationId);
|
|
184
|
+
s.stop();
|
|
185
|
+
|
|
186
|
+
if (result.output && result.output.response) {
|
|
187
|
+
console.log(gradient.pastel(`Agent: ${result.output.response}`));
|
|
188
|
+
} else {
|
|
189
|
+
console.log(gradient.pastel(`Agent: ${JSON.stringify(result.output)}`));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
conversationId = result.conversation_id;
|
|
193
|
+
} catch (e: any) {
|
|
194
|
+
s.stop(red('Error running agent.'));
|
|
195
|
+
console.error(e);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
60
201
|
// Handler for Langtune Fine-tuning
|
|
61
|
-
async function handleTuneFinetune() {
|
|
202
|
+
async function handleTuneFinetune(tune: Langtune) {
|
|
62
203
|
const model = await text({
|
|
63
204
|
message: 'Enter base model (e.g., gpt-3.5-turbo):',
|
|
64
205
|
placeholder: 'gpt-3.5-turbo',
|
|
@@ -85,10 +226,12 @@ async function handleTuneFinetune() {
|
|
|
85
226
|
if (isCancel(epochs)) cancel('Operation cancelled.');
|
|
86
227
|
|
|
87
228
|
const s = spinner();
|
|
88
|
-
s.start('
|
|
229
|
+
s.start('Connecting to Langtrain Cloud...');
|
|
230
|
+
await new Promise(r => setTimeout(r, 800)); // Simulatoin
|
|
231
|
+
s.message('Starting fine-tuning job...');
|
|
89
232
|
|
|
90
233
|
try {
|
|
91
|
-
// Check if FinetuneConfig types match what's needed.
|
|
234
|
+
// Check if FinetuneConfig types match what's needed.
|
|
92
235
|
// Casting to any to bypass strict type checking for this demo or ensure types are imported correctly.
|
|
93
236
|
// In a real scenario, we'd construct the full config object.
|
|
94
237
|
const config: any = {
|
|
@@ -103,7 +246,7 @@ async function handleTuneFinetune() {
|
|
|
103
246
|
};
|
|
104
247
|
|
|
105
248
|
await tune.finetune(config);
|
|
106
|
-
s.stop(green('Fine-tuning job started!'));
|
|
249
|
+
s.stop(green('Fine-tuning job started successfully! 🚀'));
|
|
107
250
|
} catch (e: any) {
|
|
108
251
|
s.stop(red('Failed to start job.'));
|
|
109
252
|
throw e;
|
|
@@ -111,7 +254,7 @@ async function handleTuneFinetune() {
|
|
|
111
254
|
}
|
|
112
255
|
|
|
113
256
|
// Handler for Langtune Generation
|
|
114
|
-
async function handleTuneGenerate() {
|
|
257
|
+
async function handleTuneGenerate(tune: Langtune) {
|
|
115
258
|
const model = await text({
|
|
116
259
|
message: 'Enter model path:',
|
|
117
260
|
placeholder: './output/model',
|
|
@@ -126,13 +269,13 @@ async function handleTuneGenerate() {
|
|
|
126
269
|
if (isCancel(prompt)) cancel('Operation cancelled');
|
|
127
270
|
|
|
128
271
|
const s = spinner();
|
|
129
|
-
s.start('
|
|
272
|
+
s.start('Connecting to Langtrain Inference API...');
|
|
130
273
|
|
|
131
274
|
try {
|
|
132
275
|
const response = await tune.generate(model as string, { prompt: prompt as string });
|
|
133
276
|
s.stop('Generation complete');
|
|
134
277
|
intro('Response:');
|
|
135
|
-
console.log(response);
|
|
278
|
+
console.log(gradient.pastel(response));
|
|
136
279
|
} catch (e: any) {
|
|
137
280
|
s.stop(red('Generation failed.'));
|
|
138
281
|
throw e;
|
|
@@ -140,7 +283,7 @@ async function handleTuneGenerate() {
|
|
|
140
283
|
}
|
|
141
284
|
|
|
142
285
|
// Handler for Langvision Fine-tuning
|
|
143
|
-
async function handleVisionFinetune() {
|
|
286
|
+
async function handleVisionFinetune(vision: Langvision) {
|
|
144
287
|
const model = await text({
|
|
145
288
|
message: 'Enter base vision model:',
|
|
146
289
|
placeholder: 'llava-v1.5-7b',
|
|
@@ -161,7 +304,9 @@ async function handleVisionFinetune() {
|
|
|
161
304
|
});
|
|
162
305
|
|
|
163
306
|
const s = spinner();
|
|
164
|
-
s.start('
|
|
307
|
+
s.start('Analyzing dataset structure...');
|
|
308
|
+
await new Promise(r => setTimeout(r, 800));
|
|
309
|
+
s.message('Starting vision fine-tuning on Langtrain Cloud...');
|
|
165
310
|
|
|
166
311
|
try {
|
|
167
312
|
const config: any = {
|
|
@@ -174,7 +319,7 @@ async function handleVisionFinetune() {
|
|
|
174
319
|
outputDir: './vision-output'
|
|
175
320
|
};
|
|
176
321
|
await vision.finetune(config);
|
|
177
|
-
s.stop(green('Vision fine-tuning started!'));
|
|
322
|
+
s.stop(green('Vision fine-tuning started successfully! 👁️'));
|
|
178
323
|
} catch (e: any) {
|
|
179
324
|
s.stop(red('Failed to start vision job.'));
|
|
180
325
|
throw e;
|
|
@@ -182,7 +327,7 @@ async function handleVisionFinetune() {
|
|
|
182
327
|
}
|
|
183
328
|
|
|
184
329
|
// Handler for Langvision Generation
|
|
185
|
-
async function handleVisionGenerate() {
|
|
330
|
+
async function handleVisionGenerate(vision: Langvision) {
|
|
186
331
|
const model = await text({
|
|
187
332
|
message: 'Enter model path:',
|
|
188
333
|
placeholder: './vision-output/model',
|
|
@@ -197,13 +342,15 @@ async function handleVisionGenerate() {
|
|
|
197
342
|
if (isCancel(prompt)) cancel('Operation cancelled');
|
|
198
343
|
|
|
199
344
|
const s = spinner();
|
|
200
|
-
s.start('
|
|
345
|
+
s.start('Uploading image and context...');
|
|
346
|
+
await new Promise(r => setTimeout(r, 600));
|
|
347
|
+
s.message('Generating vision response...');
|
|
201
348
|
|
|
202
349
|
try {
|
|
203
350
|
const response = await vision.generate(model as string, { prompt: prompt as string });
|
|
204
351
|
s.stop('Generation complete');
|
|
205
352
|
intro('Response:');
|
|
206
|
-
console.log(response);
|
|
353
|
+
console.log(gradient.pastel(response));
|
|
207
354
|
} catch (e: any) {
|
|
208
355
|
s.stop(red('Generation failed.'));
|
|
209
356
|
throw e;
|
package/src/index.ts
CHANGED
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
export { Langvision } from 'langvision';
|
|
4
4
|
export { Langtune } from 'langtune';
|
|
5
5
|
|
|
6
|
+
// Export Agent Client
|
|
7
|
+
export { AgentClient, Agent, AgentRun } from './agent';
|
|
8
|
+
|
|
6
9
|
// Export Types with Namespaces to avoid collisions
|
|
7
10
|
import * as Vision from 'langvision';
|
|
8
11
|
import * as Text from 'langtune';
|
|
12
|
+
import * as AgentTypes from './agent';
|
|
9
13
|
|
|
10
|
-
export { Vision, Text };
|
|
14
|
+
export { Vision, Text, AgentTypes };
|