langtrain 0.1.24 → 0.1.26

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/index.d.mts CHANGED
@@ -136,6 +136,11 @@ interface SubscriptionInfo {
136
136
  expires_at?: string;
137
137
  features: string[];
138
138
  limits: any;
139
+ usage?: {
140
+ tokensUsedThisMonth?: number;
141
+ tokenLimit?: number;
142
+ apiCalls?: number;
143
+ };
139
144
  }
140
145
  interface FeatureCheck {
141
146
  feature: string;
@@ -249,4 +254,38 @@ declare class GuardrailClient {
249
254
  apply(datasetId: string, guardrailId: string): Promise<any>;
250
255
  }
251
256
 
252
- export { type Agent, AgentClient, type AgentCreate, type AgentRun, agent as AgentTypes, type FeatureCheck, FileClient, type FileResponse, type FineTuneJobCreate, type FineTuneJobResponse, type Guardrail, GuardrailClient, type GuardrailConfig, type GuardrailCreate, type Model, ModelClient, models as ModelTypes, type Secret, SecretClient, secrets as SecretTypes, SubscriptionClient, type SubscriptionInfo, TrainingClient };
257
+ interface UsageSummary {
258
+ workspace_id: string;
259
+ plan: string;
260
+ quotas: Record<string, any>;
261
+ billing?: {
262
+ plan_id: string;
263
+ tokens_used: number;
264
+ tokens_limit: number;
265
+ period_end: string;
266
+ };
267
+ }
268
+ interface UsageHistoryPoint {
269
+ date: string;
270
+ tokens: number;
271
+ agent_runs: number;
272
+ cost: number;
273
+ }
274
+ declare class UsageClient {
275
+ private config;
276
+ private client;
277
+ constructor(config: {
278
+ apiKey: string;
279
+ baseUrl?: string;
280
+ });
281
+ /**
282
+ * Get current usage summary for a workspace.
283
+ */
284
+ getSummary(workspaceId: string): Promise<UsageSummary>;
285
+ /**
286
+ * Get historical usage data for charts.
287
+ */
288
+ getHistory(workspaceId: string, days?: number): Promise<UsageHistoryPoint[]>;
289
+ }
290
+
291
+ export { type Agent, AgentClient, type AgentCreate, type AgentRun, agent as AgentTypes, type FeatureCheck, FileClient, type FileResponse, type FineTuneJobCreate, type FineTuneJobResponse, type Guardrail, GuardrailClient, type GuardrailConfig, type GuardrailCreate, type Model, ModelClient, models as ModelTypes, type Secret, SecretClient, secrets as SecretTypes, SubscriptionClient, type SubscriptionInfo, TrainingClient, UsageClient, type UsageHistoryPoint, type UsageSummary };
package/dist/index.d.ts CHANGED
@@ -136,6 +136,11 @@ interface SubscriptionInfo {
136
136
  expires_at?: string;
137
137
  features: string[];
138
138
  limits: any;
139
+ usage?: {
140
+ tokensUsedThisMonth?: number;
141
+ tokenLimit?: number;
142
+ apiCalls?: number;
143
+ };
139
144
  }
140
145
  interface FeatureCheck {
141
146
  feature: string;
@@ -249,4 +254,38 @@ declare class GuardrailClient {
249
254
  apply(datasetId: string, guardrailId: string): Promise<any>;
250
255
  }
251
256
 
252
- export { type Agent, AgentClient, type AgentCreate, type AgentRun, agent as AgentTypes, type FeatureCheck, FileClient, type FileResponse, type FineTuneJobCreate, type FineTuneJobResponse, type Guardrail, GuardrailClient, type GuardrailConfig, type GuardrailCreate, type Model, ModelClient, models as ModelTypes, type Secret, SecretClient, secrets as SecretTypes, SubscriptionClient, type SubscriptionInfo, TrainingClient };
257
+ interface UsageSummary {
258
+ workspace_id: string;
259
+ plan: string;
260
+ quotas: Record<string, any>;
261
+ billing?: {
262
+ plan_id: string;
263
+ tokens_used: number;
264
+ tokens_limit: number;
265
+ period_end: string;
266
+ };
267
+ }
268
+ interface UsageHistoryPoint {
269
+ date: string;
270
+ tokens: number;
271
+ agent_runs: number;
272
+ cost: number;
273
+ }
274
+ declare class UsageClient {
275
+ private config;
276
+ private client;
277
+ constructor(config: {
278
+ apiKey: string;
279
+ baseUrl?: string;
280
+ });
281
+ /**
282
+ * Get current usage summary for a workspace.
283
+ */
284
+ getSummary(workspaceId: string): Promise<UsageSummary>;
285
+ /**
286
+ * Get historical usage data for charts.
287
+ */
288
+ getHistory(workspaceId: string, days?: number): Promise<UsageHistoryPoint[]>;
289
+ }
290
+
291
+ export { type Agent, AgentClient, type AgentCreate, type AgentRun, agent as AgentTypes, type FeatureCheck, FileClient, type FileResponse, type FineTuneJobCreate, type FineTuneJobResponse, type Guardrail, GuardrailClient, type GuardrailConfig, type GuardrailCreate, type Model, ModelClient, models as ModelTypes, type Secret, SecretClient, secrets as SecretTypes, SubscriptionClient, type SubscriptionInfo, TrainingClient, UsageClient, type UsageHistoryPoint, type UsageSummary };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var chunkQ5EF25B2_js=require('./chunk-Q5EF25B2.js');chunkQ5EF25B2_js.r();Object.defineProperty(exports,"AgentClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.d}});Object.defineProperty(exports,"AgentTypes",{enumerable:true,get:function(){return chunkQ5EF25B2_js.e}});Object.defineProperty(exports,"FileClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.f}});Object.defineProperty(exports,"GuardrailClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.m}});Object.defineProperty(exports,"Langtune",{enumerable:true,get:function(){return chunkQ5EF25B2_js.q}});Object.defineProperty(exports,"Langvision",{enumerable:true,get:function(){return chunkQ5EF25B2_js.p}});Object.defineProperty(exports,"ModelClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.i}});Object.defineProperty(exports,"ModelTypes",{enumerable:true,get:function(){return chunkQ5EF25B2_js.j}});Object.defineProperty(exports,"SecretClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.k}});Object.defineProperty(exports,"SecretTypes",{enumerable:true,get:function(){return chunkQ5EF25B2_js.l}});Object.defineProperty(exports,"SubscriptionClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.h}});Object.defineProperty(exports,"Text",{enumerable:true,get:function(){return chunkQ5EF25B2_js.o}});Object.defineProperty(exports,"TrainingClient",{enumerable:true,get:function(){return chunkQ5EF25B2_js.g}});Object.defineProperty(exports,"Vision",{enumerable:true,get:function(){return chunkQ5EF25B2_js.n}});//# sourceMappingURL=index.js.map
1
+ 'use strict';var chunk7D4BGTDT_js=require('./chunk-7D4BGTDT.js');Object.defineProperty(exports,"AgentClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.b}});Object.defineProperty(exports,"AgentTypes",{enumerable:true,get:function(){return chunk7D4BGTDT_js.c}});Object.defineProperty(exports,"FileClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.d}});Object.defineProperty(exports,"GuardrailClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.k}});Object.defineProperty(exports,"Langtune",{enumerable:true,get:function(){return chunk7D4BGTDT_js.p}});Object.defineProperty(exports,"Langvision",{enumerable:true,get:function(){return chunk7D4BGTDT_js.o}});Object.defineProperty(exports,"ModelClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.g}});Object.defineProperty(exports,"ModelTypes",{enumerable:true,get:function(){return chunk7D4BGTDT_js.h}});Object.defineProperty(exports,"SecretClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.i}});Object.defineProperty(exports,"SecretTypes",{enumerable:true,get:function(){return chunk7D4BGTDT_js.j}});Object.defineProperty(exports,"SubscriptionClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.f}});Object.defineProperty(exports,"Text",{enumerable:true,get:function(){return chunk7D4BGTDT_js.n}});Object.defineProperty(exports,"TrainingClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.e}});Object.defineProperty(exports,"UsageClient",{enumerable:true,get:function(){return chunk7D4BGTDT_js.l}});Object.defineProperty(exports,"Vision",{enumerable:true,get:function(){return chunk7D4BGTDT_js.m}});//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import {r}from'./chunk-XRT7LLNF.mjs';export{d as AgentClient,e as AgentTypes,f as FileClient,m as GuardrailClient,q as Langtune,p as Langvision,i as ModelClient,j as ModelTypes,k as SecretClient,l as SecretTypes,h as SubscriptionClient,o as Text,g as TrainingClient,n as Vision}from'./chunk-XRT7LLNF.mjs';r();//# sourceMappingURL=index.mjs.map
1
+ export{b as AgentClient,c as AgentTypes,d as FileClient,k as GuardrailClient,p as Langtune,o as Langvision,g as ModelClient,h as ModelTypes,i as SecretClient,j as SecretTypes,f as SubscriptionClient,n as Text,e as TrainingClient,l as UsageClient,m as Vision}from'./chunk-O3AFVWU4.mjs';//# sourceMappingURL=index.mjs.map
2
2
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langtrain",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Unified JavaScript SDK for Langtrain Ecosystem",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/src/cli/auth.ts CHANGED
@@ -1,12 +1,25 @@
1
- import { password, isCancel, cancel, intro, green, yellow, red, bgMagenta, black, spinner, gray } from './ui';
1
+ import { password, isCancel, cancel, intro, green, yellow, red, bgMagenta, black, spinner, gray, cyan, dim, bold } from './ui';
2
2
  import { getConfig, saveConfig } from './config';
3
3
  import { SubscriptionClient, SubscriptionInfo } from '../index';
4
4
 
5
+ /**
6
+ * Quick check if API key is stored (no network call).
7
+ */
8
+ export function isAuthenticated(): boolean {
9
+ const config = getConfig();
10
+ return !!config.apiKey;
11
+ }
12
+
13
+ /**
14
+ * Ensure auth — if not logged in, forces login flow.
15
+ */
5
16
  export async function ensureAuth(): Promise<string> {
6
17
  let config = getConfig();
7
18
 
8
19
  if (!config.apiKey) {
9
- intro(yellow('Authentication required to verify plan & features.'));
20
+ console.log('');
21
+ console.log(yellow(' Authentication required.'));
22
+ console.log(gray(' Login to access all features.\n'));
10
23
  await handleLogin();
11
24
  config = getConfig();
12
25
  }
@@ -14,13 +27,20 @@ export async function ensureAuth(): Promise<string> {
14
27
  return config.apiKey as string;
15
28
  }
16
29
 
30
+ /**
31
+ * Interactive login — Claude-style API key entry with immediate verification.
32
+ */
17
33
  export async function handleLogin() {
18
34
  while (true) {
19
- console.log(gray('\nGet your API Key at: https://langtrain.xyz/settings/keys\n'));
35
+ console.log(dim(' ─────────────────────────────────────'));
36
+ console.log(gray(' Get your API Key at: ') + cyan('https://app.langtrain.xyz/home/api'));
37
+ console.log(dim(' ─────────────────────────────────────\n'));
38
+
20
39
  const apiKey = await password({
21
40
  message: 'Enter your Langtrain API Key:',
22
41
  validate(value) {
23
42
  if (!value || value.length === 0) return 'API Key is required';
43
+ if (value.length < 10) return 'Invalid key format';
24
44
  },
25
45
  });
26
46
 
@@ -32,45 +52,73 @@ export async function handleLogin() {
32
52
  const s = spinner();
33
53
  s.start('Verifying API Key...');
34
54
 
35
- // Verify key immediately
36
55
  try {
37
56
  const client = new SubscriptionClient({ apiKey: apiKey as string });
38
57
  const info = await client.getStatus();
39
58
 
40
- s.stop(green(`Authenticated as ${info.plan === 'pro' ? 'PRO' : info.plan.toUpperCase()}`));
59
+ const planBadge = info.plan === 'pro'
60
+ ? bgMagenta(black(' PRO '))
61
+ : info.plan === 'enterprise'
62
+ ? bgMagenta(black(' ENTERPRISE '))
63
+ : ' FREE ';
64
+
65
+ s.stop(green(`Authenticated ${planBadge}`));
66
+
67
+ // Show initial token info if available
68
+ if (info.usage) {
69
+ const used = info.usage.tokensUsedThisMonth || 0;
70
+ const limit = info.usage.tokenLimit || 10000;
71
+ const pct = Math.round((used / limit) * 100);
72
+ console.log(dim(` Tokens: ${used.toLocaleString()} / ${limit.toLocaleString()} (${pct}% used)`));
73
+ }
41
74
 
42
75
  const config = getConfig();
43
76
  saveConfig({ ...config, apiKey: apiKey as string });
44
- // intro(green('API Key saved successfully!')); // success message above is enough
45
- return; // Exit loop on success
77
+ console.log(green(' Credentials saved to ~/.langtrain/config.json\n'));
78
+ return;
46
79
  } catch (e: any) {
47
80
  s.stop(red('Invalid API Key. Please try again.'));
48
- // Loop continues
49
81
  }
50
82
  }
51
83
  }
52
84
 
85
+ /**
86
+ * Logout — clear stored credentials.
87
+ */
88
+ export async function handleLogout() {
89
+ const config = getConfig();
90
+ delete config.apiKey;
91
+ saveConfig(config);
92
+ console.log(green('\n ✔ Logged out. Credentials cleared.\n'));
93
+ }
94
+
95
+ /**
96
+ * Fetch subscription info for status bar display.
97
+ */
53
98
  export async function getSubscription(apiKey: string): Promise<SubscriptionInfo | null> {
54
99
  const client = new SubscriptionClient({ apiKey });
55
100
  const s = spinner();
56
- s.start('Verifying subscription plan...');
101
+ s.start('Checking subscription...');
57
102
  try {
58
103
  const info = await client.getStatus();
59
104
 
60
- // Enhance: Show plan details immediately on auth check
61
- const planLabel = info.plan === 'pro' ? bgMagenta(' PRO ') : info.plan.toUpperCase();
62
- s.stop(green(`Authenticated as ${planLabel}`));
105
+ const planBadge = info.plan === 'pro'
106
+ ? bgMagenta(black(' PRO '))
107
+ : info.plan === 'enterprise'
108
+ ? bgMagenta(black(' ENTERPRISE '))
109
+ : bold(' FREE ');
110
+
111
+ s.stop(green(`Plan: ${planBadge}`));
63
112
 
64
113
  if (info.is_active === false) {
65
- console.log(yellow('Warning: Your subscription is not active. Some features may be limited.'));
114
+ console.log(yellow(' Subscription inactive. Some features may be limited.\n'));
66
115
  }
67
116
 
68
117
  return info;
69
118
  } catch (e: any) {
70
119
  s.stop(red('Failed to verify subscription.'));
71
120
  if (e.response && e.response.status === 401) {
72
- console.log(red('Invalid API Key. Please run login again.'));
73
- // Optionally clear key?
121
+ console.log(red(' API Key expired. Please login again.'));
74
122
  }
75
123
  return null;
76
124
  }
@@ -0,0 +1,127 @@
1
+ import { green, dim, cyan, bold, yellow, gray, spinner } from '../ui';
2
+ import { getConfig } from '../config';
3
+
4
+ // Session-level telemetry tracker
5
+ let sessionStart = Date.now();
6
+ let apiCallCount = 0;
7
+ let totalLatencyMs = 0;
8
+ let errorCount = 0;
9
+
10
+ export function trackApiCall(latencyMs: number, isError: boolean = false) {
11
+ apiCallCount++;
12
+ totalLatencyMs += latencyMs;
13
+ if (isError) errorCount++;
14
+ }
15
+
16
+ export async function handleTokens() {
17
+ const config = getConfig();
18
+ const apiKey = config.apiKey;
19
+
20
+ console.log('');
21
+ console.log(bold(' ╔══════════════════════════════════════╗'));
22
+ console.log(bold(' ║ TOKEN USAGE ║'));
23
+ console.log(bold(' ╚══════════════════════════════════════╝'));
24
+ console.log('');
25
+
26
+ if (!apiKey) {
27
+ console.log(yellow(' Login required to view token usage.\n'));
28
+ return;
29
+ }
30
+
31
+ const s = spinner();
32
+ s.start('Fetching token usage...');
33
+
34
+ try {
35
+ const axios = require('axios');
36
+ const baseUrl = config.baseUrl || 'https://api.langtrain.xyz';
37
+ const res = await axios.get(`${baseUrl}/v1/usage/tokens`, {
38
+ headers: { Authorization: `Bearer ${apiKey}` }
39
+ });
40
+
41
+ const usage = res.data;
42
+ s.stop(green('Token usage retrieved'));
43
+ console.log('');
44
+
45
+ const used = usage.tokens_used || 0;
46
+ const limit = usage.token_limit || 10000;
47
+ const pct = Math.round((used / limit) * 100);
48
+ const remaining = Math.max(0, limit - used);
49
+
50
+ // Visual bar
51
+ const barWidth = 30;
52
+ const filled = Math.round((pct / 100) * barWidth);
53
+ const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
54
+ const barColor = pct > 90 ? '\x1b[31m' : pct > 70 ? '\x1b[33m' : '\x1b[32m';
55
+
56
+ console.log(` ${dim('Period:')} ${usage.period || 'Current Month'}`);
57
+ console.log(` ${dim('Used:')} ${used.toLocaleString()} tokens`);
58
+ console.log(` ${dim('Limit:')} ${limit.toLocaleString()} tokens`);
59
+ console.log(` ${dim('Remaining:')} ${remaining.toLocaleString()} tokens`);
60
+ console.log(` ${dim('Usage:')} ${barColor}${bar}\x1b[0m ${pct}%`);
61
+ console.log('');
62
+
63
+ if (usage.breakdown) {
64
+ console.log(dim(' ── Breakdown ────────────────────────'));
65
+ console.log(` ${dim('Training:')} ${(usage.breakdown.training || 0).toLocaleString()}`);
66
+ console.log(` ${dim('Inference:')} ${(usage.breakdown.inference || 0).toLocaleString()}`);
67
+ console.log(` ${dim('Agents:')} ${(usage.breakdown.agents || 0).toLocaleString()}`);
68
+ console.log('');
69
+ }
70
+ } catch (e: any) {
71
+ s.stop('');
72
+ // Show mock data if API not available
73
+ console.log(dim(' Token data not available from server.'));
74
+ console.log(dim(' Showing session estimates:\n'));
75
+
76
+ console.log(` ${dim('Session calls:')} ${apiCallCount}`);
77
+ console.log(` ${dim('Est. tokens:')} ~${apiCallCount * 150}`);
78
+ console.log('');
79
+ }
80
+ }
81
+
82
+ export async function handleTelemetry() {
83
+ const uptimeMs = Date.now() - sessionStart;
84
+ const uptimeSec = Math.round(uptimeMs / 1000);
85
+ const uptimeMin = Math.floor(uptimeSec / 60);
86
+ const uptimeStr = uptimeMin > 0 ? `${uptimeMin}m ${uptimeSec % 60}s` : `${uptimeSec}s`;
87
+
88
+ const avgLatency = apiCallCount > 0 ? Math.round(totalLatencyMs / apiCallCount) : 0;
89
+ const errorRate = apiCallCount > 0 ? Math.round((errorCount / apiCallCount) * 100) : 0;
90
+
91
+ console.log('');
92
+ console.log(bold(' ╔══════════════════════════════════════╗'));
93
+ console.log(bold(' ║ SESSION TELEMETRY ║'));
94
+ console.log(bold(' ╚══════════════════════════════════════╝'));
95
+ console.log('');
96
+
97
+ console.log(` ${dim('Session:')} ${uptimeStr}`);
98
+ console.log(` ${dim('API calls:')} ${apiCallCount}`);
99
+ console.log(` ${dim('Avg latency:')} ${avgLatency}ms`);
100
+ console.log(` ${dim('Errors:')} ${errorCount} (${errorRate}%)`);
101
+ console.log('');
102
+
103
+ console.log(dim(' ── Environment ──────────────────────'));
104
+ console.log(` ${dim('Node:')} ${process.version}`);
105
+ console.log(` ${dim('Platform:')} ${process.platform} ${process.arch}`);
106
+ console.log(` ${dim('Memory:')} ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB heap`);
107
+ console.log(` ${dim('Config:')} ~/.langtrain/config.json`);
108
+ console.log('');
109
+
110
+ // API health check
111
+ const config = getConfig();
112
+ if (config.apiKey) {
113
+ const s = spinner();
114
+ s.start('Pinging API...');
115
+ try {
116
+ const axios = require('axios');
117
+ const baseUrl = config.baseUrl || 'https://api.langtrain.xyz';
118
+ const start = Date.now();
119
+ await axios.get(`${baseUrl}/health`, { timeout: 5000 });
120
+ const latency = Date.now() - start;
121
+ s.stop(green(`API healthy (${latency}ms)`));
122
+ } catch {
123
+ s.stop(yellow('API unreachable'));
124
+ }
125
+ }
126
+ console.log('');
127
+ }