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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langtrain",
3
- "version": "0.1.6",
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
- // Initialize clients
8
- const vision = new Langvision();
9
- const tune = new Langtune();
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('0.1.5');
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
- if (isCancel(operation) || operation === 'exit') {
35
- outro('Goodbye!');
36
- process.exit(0);
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
- try {
40
- if (operation === 'tune-finetune') {
41
- await handleTuneFinetune();
42
- } else if (operation === 'tune-generate') {
43
- await handleTuneGenerate();
44
- } else if (operation === 'vision-finetune') {
45
- await handleVisionFinetune();
46
- } else if (operation === 'vision-generate') {
47
- await handleVisionGenerate();
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
- outro(green('Operation completed successfully!'));
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('Starting fine-tuning job...');
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('Generating response...');
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('Starting vision fine-tuning...');
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('Generating vision response...');
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 };