langtrain 0.1.19 → 0.1.21
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/.agent/workflows/gsd.md +27 -0
- package/.agent/workflows/ralph.md +28 -0
- package/README.md +73 -68
- package/assets/cli-demo.png +0 -0
- package/dist/chunk-QZ6U7AJN.js +30 -0
- package/dist/chunk-QZ6U7AJN.js.map +1 -0
- package/dist/chunk-TDQXC2RA.mjs +30 -0
- package/dist/chunk-TDQXC2RA.mjs.map +1 -0
- package/dist/cli.js +8 -6
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +8 -6
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +67 -1
- package/dist/index.d.ts +67 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -1
- package/src/cli/auth.ts +2 -2
- package/src/cli/components/Table.ts +20 -0
- package/src/cli/handlers/agent.ts +35 -3
- package/src/cli/handlers/data.ts +128 -5
- package/src/cli/handlers/env.ts +89 -0
- package/src/cli/handlers/guardrails.ts +100 -0
- package/src/cli/handlers/logs.ts +68 -0
- package/src/cli/handlers/subscription.ts +2 -2
- package/src/cli/handlers/tune.ts +18 -8
- package/src/cli/handlers/vision.ts +2 -2
- package/src/cli/index.ts +100 -15
- package/src/cli/menu.ts +12 -1
- package/src/cli/ui.ts +13 -8
- package/src/index.ts +4 -1
- package/src/lib/agent.ts +7 -0
- package/src/lib/guardrails.ts +72 -0
- package/src/lib/secrets.ts +39 -0
- package/dist/chunk-PAHGEWDE.js +0 -30
- package/dist/chunk-PAHGEWDE.js.map +0 -1
- package/dist/chunk-Q46V6ODQ.mjs +0 -30
- package/dist/chunk-Q46V6ODQ.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,9 @@ declare class AgentClient {
|
|
|
37
37
|
create(agent: AgentCreate): Promise<Agent>;
|
|
38
38
|
delete(agentId: string): Promise<void>;
|
|
39
39
|
execute(agentId: string, input: any, messages?: any[], conversationId?: string): Promise<AgentRun>;
|
|
40
|
+
logs(agentId: string, limit?: number): Promise<{
|
|
41
|
+
logs: string[];
|
|
42
|
+
}>;
|
|
40
43
|
}
|
|
41
44
|
interface AgentConfig {
|
|
42
45
|
system_prompt?: string;
|
|
@@ -183,4 +186,67 @@ declare namespace models {
|
|
|
183
186
|
export { type models_Model as Model, models_ModelClient as ModelClient, type models_Permission as Permission };
|
|
184
187
|
}
|
|
185
188
|
|
|
186
|
-
|
|
189
|
+
interface Secret {
|
|
190
|
+
key: string;
|
|
191
|
+
created_at: string;
|
|
192
|
+
updated_at: string;
|
|
193
|
+
}
|
|
194
|
+
declare class SecretClient {
|
|
195
|
+
private config;
|
|
196
|
+
private client;
|
|
197
|
+
constructor(config: {
|
|
198
|
+
apiKey: string;
|
|
199
|
+
baseUrl?: string;
|
|
200
|
+
});
|
|
201
|
+
list(workspaceId?: string): Promise<Secret[]>;
|
|
202
|
+
set(key: string, value: string, workspaceId?: string): Promise<Secret>;
|
|
203
|
+
delete(key: string, workspaceId?: string): Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type secrets_Secret = Secret;
|
|
207
|
+
type secrets_SecretClient = SecretClient;
|
|
208
|
+
declare const secrets_SecretClient: typeof SecretClient;
|
|
209
|
+
declare namespace secrets {
|
|
210
|
+
export { type secrets_Secret as Secret, secrets_SecretClient as SecretClient };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interface GuardrailConfig {
|
|
214
|
+
pii_enabled: boolean;
|
|
215
|
+
pii_entities?: string[];
|
|
216
|
+
profanity_enabled: boolean;
|
|
217
|
+
profanity_threshold?: number;
|
|
218
|
+
blocked_topics?: string[];
|
|
219
|
+
regex_patterns?: string[];
|
|
220
|
+
min_length?: number;
|
|
221
|
+
max_length?: number;
|
|
222
|
+
}
|
|
223
|
+
interface Guardrail {
|
|
224
|
+
id: string;
|
|
225
|
+
workspace_id: string;
|
|
226
|
+
name: string;
|
|
227
|
+
description?: string;
|
|
228
|
+
config: GuardrailConfig;
|
|
229
|
+
is_active: boolean;
|
|
230
|
+
created_at: string;
|
|
231
|
+
updated_at: string;
|
|
232
|
+
}
|
|
233
|
+
interface GuardrailCreate {
|
|
234
|
+
name: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
config: GuardrailConfig;
|
|
237
|
+
}
|
|
238
|
+
declare class GuardrailClient {
|
|
239
|
+
private config;
|
|
240
|
+
private client;
|
|
241
|
+
constructor(config: {
|
|
242
|
+
apiKey: string;
|
|
243
|
+
baseUrl?: string;
|
|
244
|
+
});
|
|
245
|
+
list(workspaceId?: string): Promise<Guardrail[]>;
|
|
246
|
+
get(guardrailId: string): Promise<Guardrail>;
|
|
247
|
+
create(data: GuardrailCreate): Promise<Guardrail>;
|
|
248
|
+
delete(guardrailId: string): Promise<void>;
|
|
249
|
+
apply(datasetId: string, guardrailId: string): Promise<any>;
|
|
250
|
+
}
|
|
251
|
+
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,9 @@ declare class AgentClient {
|
|
|
37
37
|
create(agent: AgentCreate): Promise<Agent>;
|
|
38
38
|
delete(agentId: string): Promise<void>;
|
|
39
39
|
execute(agentId: string, input: any, messages?: any[], conversationId?: string): Promise<AgentRun>;
|
|
40
|
+
logs(agentId: string, limit?: number): Promise<{
|
|
41
|
+
logs: string[];
|
|
42
|
+
}>;
|
|
40
43
|
}
|
|
41
44
|
interface AgentConfig {
|
|
42
45
|
system_prompt?: string;
|
|
@@ -183,4 +186,67 @@ declare namespace models {
|
|
|
183
186
|
export { type models_Model as Model, models_ModelClient as ModelClient, type models_Permission as Permission };
|
|
184
187
|
}
|
|
185
188
|
|
|
186
|
-
|
|
189
|
+
interface Secret {
|
|
190
|
+
key: string;
|
|
191
|
+
created_at: string;
|
|
192
|
+
updated_at: string;
|
|
193
|
+
}
|
|
194
|
+
declare class SecretClient {
|
|
195
|
+
private config;
|
|
196
|
+
private client;
|
|
197
|
+
constructor(config: {
|
|
198
|
+
apiKey: string;
|
|
199
|
+
baseUrl?: string;
|
|
200
|
+
});
|
|
201
|
+
list(workspaceId?: string): Promise<Secret[]>;
|
|
202
|
+
set(key: string, value: string, workspaceId?: string): Promise<Secret>;
|
|
203
|
+
delete(key: string, workspaceId?: string): Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type secrets_Secret = Secret;
|
|
207
|
+
type secrets_SecretClient = SecretClient;
|
|
208
|
+
declare const secrets_SecretClient: typeof SecretClient;
|
|
209
|
+
declare namespace secrets {
|
|
210
|
+
export { type secrets_Secret as Secret, secrets_SecretClient as SecretClient };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interface GuardrailConfig {
|
|
214
|
+
pii_enabled: boolean;
|
|
215
|
+
pii_entities?: string[];
|
|
216
|
+
profanity_enabled: boolean;
|
|
217
|
+
profanity_threshold?: number;
|
|
218
|
+
blocked_topics?: string[];
|
|
219
|
+
regex_patterns?: string[];
|
|
220
|
+
min_length?: number;
|
|
221
|
+
max_length?: number;
|
|
222
|
+
}
|
|
223
|
+
interface Guardrail {
|
|
224
|
+
id: string;
|
|
225
|
+
workspace_id: string;
|
|
226
|
+
name: string;
|
|
227
|
+
description?: string;
|
|
228
|
+
config: GuardrailConfig;
|
|
229
|
+
is_active: boolean;
|
|
230
|
+
created_at: string;
|
|
231
|
+
updated_at: string;
|
|
232
|
+
}
|
|
233
|
+
interface GuardrailCreate {
|
|
234
|
+
name: string;
|
|
235
|
+
description?: string;
|
|
236
|
+
config: GuardrailConfig;
|
|
237
|
+
}
|
|
238
|
+
declare class GuardrailClient {
|
|
239
|
+
private config;
|
|
240
|
+
private client;
|
|
241
|
+
constructor(config: {
|
|
242
|
+
apiKey: string;
|
|
243
|
+
baseUrl?: string;
|
|
244
|
+
});
|
|
245
|
+
list(workspaceId?: string): Promise<Guardrail[]>;
|
|
246
|
+
get(guardrailId: string): Promise<Guardrail>;
|
|
247
|
+
create(data: GuardrailCreate): Promise<Guardrail>;
|
|
248
|
+
delete(guardrailId: string): Promise<void>;
|
|
249
|
+
apply(datasetId: string, guardrailId: string): Promise<any>;
|
|
250
|
+
}
|
|
251
|
+
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkQZ6U7AJN_js=require('./chunk-QZ6U7AJN.js');chunkQZ6U7AJN_js.r();Object.defineProperty(exports,"AgentClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.h}});Object.defineProperty(exports,"AgentTypes",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.i}});Object.defineProperty(exports,"FileClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.j}});Object.defineProperty(exports,"GuardrailClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.q}});Object.defineProperty(exports,"Langtune",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.f}});Object.defineProperty(exports,"Langvision",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.d}});Object.defineProperty(exports,"ModelClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.m}});Object.defineProperty(exports,"ModelTypes",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.n}});Object.defineProperty(exports,"SecretClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.o}});Object.defineProperty(exports,"SecretTypes",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.p}});Object.defineProperty(exports,"SubscriptionClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.l}});Object.defineProperty(exports,"Text",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.g}});Object.defineProperty(exports,"TrainingClient",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.k}});Object.defineProperty(exports,"Vision",{enumerable:true,get:function(){return chunkQZ6U7AJN_js.e}});//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{
|
|
1
|
+
import {r}from'./chunk-TDQXC2RA.mjs';export{h as AgentClient,i as AgentTypes,j as FileClient,q as GuardrailClient,f as Langtune,d as Langvision,m as ModelClient,n as ModelTypes,o as SecretClient,p as SecretTypes,l as SubscriptionClient,g as Text,k as TrainingClient,e as Vision}from'./chunk-TDQXC2RA.mjs';r();//# 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.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Unified JavaScript SDK for Langtrain Ecosystem",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@clack/prompts": "^1.0.1",
|
|
43
43
|
"axios": "^1.13.5",
|
|
44
|
+
"cli-table3": "^0.6.5",
|
|
44
45
|
"commander": "^14.0.3",
|
|
45
46
|
"gradient-string": "^3.0.0",
|
|
46
47
|
"kleur": "^4.1.5",
|
package/src/cli/auth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { password, isCancel, cancel, intro, green, yellow, red,
|
|
1
|
+
import { password, isCancel, cancel, intro, green, yellow, red, bgMagenta, black, spinner, gray } from './ui';
|
|
2
2
|
import { getConfig, saveConfig } from './config';
|
|
3
3
|
import { SubscriptionClient, SubscriptionInfo } from '../index';
|
|
4
4
|
|
|
@@ -58,7 +58,7 @@ export async function getSubscription(apiKey: string): Promise<SubscriptionInfo
|
|
|
58
58
|
const info = await client.getStatus();
|
|
59
59
|
|
|
60
60
|
// Enhance: Show plan details immediately on auth check
|
|
61
|
-
const planLabel = info.plan === 'pro' ?
|
|
61
|
+
const planLabel = info.plan === 'pro' ? bgMagenta(' PRO ') : info.plan.toUpperCase();
|
|
62
62
|
s.stop(green(`Authenticated as ${planLabel}`));
|
|
63
63
|
|
|
64
64
|
if (info.is_active === false) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Table from 'cli-table3';
|
|
2
|
+
import { colors } from '../ui';
|
|
3
|
+
|
|
4
|
+
export function createTable(headers: string[]) {
|
|
5
|
+
return new Table({
|
|
6
|
+
head: headers.map(h => colors.magenta(colors.bold(h))),
|
|
7
|
+
chars: {
|
|
8
|
+
'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
|
|
9
|
+
'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘',
|
|
10
|
+
'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
|
|
11
|
+
'right': '│', 'right-mid': '┤', 'middle': '│'
|
|
12
|
+
},
|
|
13
|
+
style: {
|
|
14
|
+
'padding-left': 1,
|
|
15
|
+
'padding-right': 1,
|
|
16
|
+
head: [], // handle colors manually
|
|
17
|
+
border: ['gray']
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { text, select, confirm, isCancel, cancel, spinner, intro, red, green, yellow, gray,
|
|
1
|
+
import { text, select, confirm, isCancel, cancel, spinner, intro, red, green, yellow, gray, bgMagenta, black, gradient, createTable } from '../ui';
|
|
2
2
|
import { AgentClient, ModelClient } from '../../index';
|
|
3
3
|
|
|
4
4
|
export async function handleAgentCreate(client: AgentClient, modelClient: ModelClient) {
|
|
@@ -136,6 +136,19 @@ export async function handleAgentList(client: AgentClient) {
|
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
// Display Table
|
|
140
|
+
const table = createTable(['ID', 'Name', 'Model', 'Created']);
|
|
141
|
+
agents.forEach(a => {
|
|
142
|
+
table.push([
|
|
143
|
+
a.id.substring(0, 8) + '...',
|
|
144
|
+
a.name,
|
|
145
|
+
(a.config as any)?.model || 'default',
|
|
146
|
+
new Date(a.created_at).toLocaleDateString()
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
console.log(table.toString());
|
|
150
|
+
console.log(''); // spacer
|
|
151
|
+
|
|
139
152
|
const agentId = await select({
|
|
140
153
|
message: 'Select an agent to run:',
|
|
141
154
|
options: agents.map(a => ({ value: a.id, label: a.name, hint: a.description || 'No description' }))
|
|
@@ -146,12 +159,31 @@ export async function handleAgentList(client: AgentClient) {
|
|
|
146
159
|
await handleAgentRun(client, agentId as string, agents.find(a => a.id === agentId)?.name || 'Agent');
|
|
147
160
|
}
|
|
148
161
|
|
|
149
|
-
export async function handleAgentRun(client: AgentClient, agentId: string, agentName: string) {
|
|
150
|
-
intro(
|
|
162
|
+
export async function handleAgentRun(client: AgentClient, agentId: string, agentName: string, initialMessage?: string) {
|
|
163
|
+
intro(bgMagenta(black(` Chatting with ${agentName} `)));
|
|
151
164
|
console.log(gray('Type "exit" to quit conversation.'));
|
|
152
165
|
|
|
153
166
|
let conversationId: string | undefined = undefined;
|
|
154
167
|
|
|
168
|
+
// Send initial message if provided
|
|
169
|
+
if (initialMessage) {
|
|
170
|
+
const s = spinner();
|
|
171
|
+
s.start('Agent is analyzing...');
|
|
172
|
+
try {
|
|
173
|
+
const result = await client.execute(agentId, { prompt: initialMessage }, [], conversationId);
|
|
174
|
+
s.stop();
|
|
175
|
+
if ((result.output as any)?.response) {
|
|
176
|
+
console.log(gradient.pastel(`Agent: ${(result.output as any).response}`));
|
|
177
|
+
} else {
|
|
178
|
+
console.log(gradient.pastel(`Agent: ${JSON.stringify(result.output)}`));
|
|
179
|
+
}
|
|
180
|
+
conversationId = result.conversation_id;
|
|
181
|
+
} catch (e: any) {
|
|
182
|
+
s.stop(red('Error running agent.'));
|
|
183
|
+
console.error(e);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
155
187
|
while (true) {
|
|
156
188
|
const input = await text({
|
|
157
189
|
message: 'You:',
|
package/src/cli/handlers/data.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { text, select, confirm, isCancel, cancel, spinner, intro, red, green, yellow, gray } from '../ui';
|
|
2
2
|
import { getConfig } from '../config';
|
|
3
|
-
import { FileClient } from '../../index';
|
|
4
|
-
import
|
|
3
|
+
import { FileClient, AgentClient, GuardrailClient } from '../../index';
|
|
4
|
+
import { handleAgentRun } from './agent';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
|
|
7
7
|
export async function handleDataUpload(client: FileClient) {
|
|
@@ -73,12 +73,135 @@ export async function handleDataList(client: FileClient) {
|
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const file = await select({
|
|
77
|
+
message: 'Select file to analyze (or cancel to exit):',
|
|
78
|
+
options: files.map(f => ({ value: f.id, label: `${f.filename} (${formatBytes(f.bytes)})` }))
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
+
if (isCancel(file)) return;
|
|
82
|
+
|
|
83
|
+
await handleDataAnalyze(client, file as string);
|
|
84
|
+
|
|
81
85
|
} catch (e: any) {
|
|
82
86
|
s.stop(red(`Failed to list files: ${e.message}`));
|
|
83
87
|
}
|
|
84
88
|
}
|
|
89
|
+
|
|
90
|
+
export async function handleDataAnalyze(client: FileClient, fileId: string) {
|
|
91
|
+
const config = getConfig();
|
|
92
|
+
const s2 = spinner();
|
|
93
|
+
s2.start('Connecting to Data Analyst...');
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const agentClient = new AgentClient({ apiKey: config.apiKey || '', baseUrl: config.baseUrl });
|
|
97
|
+
const agents = await agentClient.list();
|
|
98
|
+
// Check name (name is optional in type but we know it exists for system agent)
|
|
99
|
+
let analyst = agents.find(a => a.name && a.name === "Langtrain Data Analyst");
|
|
100
|
+
|
|
101
|
+
if (!analyst) {
|
|
102
|
+
s2.stop(yellow('Data Analyst agent (System) not found. Please contact admin to provision it.'));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
s2.stop(green('Connected to Data Analyst.'));
|
|
107
|
+
|
|
108
|
+
console.log(gray(`\nAnalyzing dataset ${fileId}...\n`));
|
|
109
|
+
|
|
110
|
+
await handleAgentRun(agentClient, analyst.id, analyst.name, `Please analyze the dataset with ID: ${fileId}`);
|
|
111
|
+
|
|
112
|
+
} catch (e: any) {
|
|
113
|
+
s2.stop(red(`Failed to connect: ${e.message}`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function handleDataRefine(client: FileClient, fileId?: string) {
|
|
118
|
+
const config = getConfig();
|
|
119
|
+
const gClient = new GuardrailClient({ apiKey: config.apiKey || '', baseUrl: config.baseUrl });
|
|
120
|
+
|
|
121
|
+
// 0. Select File if not provided
|
|
122
|
+
if (!fileId) {
|
|
123
|
+
const s = spinner();
|
|
124
|
+
s.start('Fetching files...');
|
|
125
|
+
try {
|
|
126
|
+
// Need workspace ID logic similar to List?
|
|
127
|
+
// client.list takes workspaceId.
|
|
128
|
+
const wId = config.workspace_id || '';
|
|
129
|
+
const files = await client.list(wId);
|
|
130
|
+
s.stop(`Found ${files.length} files`);
|
|
131
|
+
|
|
132
|
+
if (files.length === 0) {
|
|
133
|
+
console.log(yellow('No files found. Upload one first.'));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const selection = await select({
|
|
138
|
+
message: 'Select file to refine:',
|
|
139
|
+
options: files.map(f => ({ value: f.id, label: `${f.filename} (${formatBytes(f.bytes)})` }))
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (isCancel(selection)) return;
|
|
143
|
+
fileId = selection as string;
|
|
144
|
+
|
|
145
|
+
} catch (e: any) {
|
|
146
|
+
s.stop(red(`Failed to fetch files: ${e.message}`));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 1. Select Guardrail
|
|
152
|
+
const s = spinner();
|
|
153
|
+
s.start('Fetching guardrails...');
|
|
154
|
+
let guardId = "";
|
|
155
|
+
try {
|
|
156
|
+
const guards = await gClient.list();
|
|
157
|
+
s.stop(`Found ${guards.length} guardrails`);
|
|
158
|
+
|
|
159
|
+
if (guards.length === 0) {
|
|
160
|
+
console.log(yellow('No guardrails found. Please create one first using "lt guardrails create".'));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const selection = await select({
|
|
165
|
+
message: 'Select a Guardrail to apply:',
|
|
166
|
+
options: guards.map((g: any) => ({
|
|
167
|
+
value: g.id,
|
|
168
|
+
label: g.name,
|
|
169
|
+
hint: g.description
|
|
170
|
+
}))
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (isCancel(selection)) return;
|
|
174
|
+
guardId = selection as string;
|
|
175
|
+
|
|
176
|
+
} catch (e: any) {
|
|
177
|
+
s.stop(red(`Failed to fetch guardrails: ${e.message}`));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 2. Apply
|
|
182
|
+
const s2 = spinner();
|
|
183
|
+
s2.start('Applying guardrail (filtering dataset)...');
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const result = await gClient.apply(fileId, guardId);
|
|
187
|
+
s2.stop(green('Dataset refined successfully!'));
|
|
188
|
+
|
|
189
|
+
console.log(gray('Stats:'));
|
|
190
|
+
console.log(`Original Rows: ${result.original_rows}`);
|
|
191
|
+
console.log(`Filtered Rows: ${result.filtered_rows}`);
|
|
192
|
+
console.log(red(`Removed: ${result.removed_rows} rows`));
|
|
193
|
+
console.log(green(`New Dataset ID: ${result.new_dataset_id}`));
|
|
194
|
+
|
|
195
|
+
} catch (e: any) {
|
|
196
|
+
s2.stop(red(`Failed to refine dataset: ${e.message}`));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function formatBytes(bytes: number, decimals = 2) {
|
|
201
|
+
if (!+bytes) return '0 Bytes';
|
|
202
|
+
const k = 1024;
|
|
203
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
204
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
205
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
206
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
207
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { intro, outro, spinner, green, red, yellow, showInfo, gray, showSuccess } from '../ui';
|
|
2
|
+
import { SecretClient } from '../../index';
|
|
3
|
+
import { text, confirm, select, isCancel, cancel } from '../ui';
|
|
4
|
+
import { getConfig } from '../config';
|
|
5
|
+
|
|
6
|
+
export async function handleEnvList(client: SecretClient) {
|
|
7
|
+
const s = spinner();
|
|
8
|
+
s.start('Fetching secrets...');
|
|
9
|
+
const config = getConfig();
|
|
10
|
+
try {
|
|
11
|
+
const secrets = await client.list(config.workspace_id);
|
|
12
|
+
s.stop(`Found ${secrets.length} secrets`);
|
|
13
|
+
|
|
14
|
+
if (secrets.length === 0) {
|
|
15
|
+
console.log(gray('No secrets found. Use "lt env set" to add one.'));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log(gray('------------------------------------------------'));
|
|
20
|
+
secrets.forEach(sec => {
|
|
21
|
+
console.log(`${sec.key.padEnd(30)} ${gray('******')}`);
|
|
22
|
+
});
|
|
23
|
+
console.log(gray('------------------------------------------------'));
|
|
24
|
+
|
|
25
|
+
} catch (e: any) {
|
|
26
|
+
s.stop(red(`Failed to list secrets: ${e.message}`));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function handleEnvSet(client: SecretClient, keyVal?: string) {
|
|
31
|
+
let key = '';
|
|
32
|
+
let value = '';
|
|
33
|
+
|
|
34
|
+
if (keyVal && keyVal.includes('=')) {
|
|
35
|
+
const parts = keyVal.split('=');
|
|
36
|
+
key = parts[0];
|
|
37
|
+
value = parts.slice(1).join('=');
|
|
38
|
+
} else {
|
|
39
|
+
key = await text({ message: 'Secret Key:', placeholder: 'OPENAI_API_KEY' }) as string;
|
|
40
|
+
if (isCancel(key)) return;
|
|
41
|
+
|
|
42
|
+
value = await text({ message: 'Secret Value:', placeholder: 'sk-...' }) as string;
|
|
43
|
+
if (isCancel(value)) return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const s = spinner();
|
|
47
|
+
s.start(`Setting ${key}...`);
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await client.set(key, value, config.workspace_id);
|
|
52
|
+
s.stop(green(`Secret ${key} set successfully.`));
|
|
53
|
+
} catch (e: any) {
|
|
54
|
+
s.stop(red(`Failed to set secret: ${e.message}`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Interactive menu for env
|
|
59
|
+
export async function handleEnvMenu(client: SecretClient) {
|
|
60
|
+
const action = await select({
|
|
61
|
+
message: 'Manage Secrets',
|
|
62
|
+
options: [
|
|
63
|
+
{ value: 'list', label: 'List Secrets' },
|
|
64
|
+
{ value: 'set', label: 'Set Secret' },
|
|
65
|
+
{ value: 'remove', label: 'Remove Secret' },
|
|
66
|
+
{ value: 'back', label: 'Back' }
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (isCancel(action) || action === 'back') return;
|
|
71
|
+
|
|
72
|
+
if (action === 'list') await handleEnvList(client);
|
|
73
|
+
if (action === 'set') await handleEnvSet(client);
|
|
74
|
+
if (action === 'remove') {
|
|
75
|
+
const key = await text({ message: 'Key to remove:' });
|
|
76
|
+
if (!isCancel(key)) {
|
|
77
|
+
const s = spinner();
|
|
78
|
+
s.start('Removing...');
|
|
79
|
+
try {
|
|
80
|
+
// need workspace_id
|
|
81
|
+
const config = getConfig();
|
|
82
|
+
await client.delete(key as string, config.workspace_id);
|
|
83
|
+
s.stop(green('Removed.'));
|
|
84
|
+
} catch (e: any) {
|
|
85
|
+
s.stop(red(`Failed: ${e.message}`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { text, select, confirm, isCancel, cancel, spinner, intro, red, green, yellow, gray } from '../ui';
|
|
2
|
+
import { getConfig } from '../config';
|
|
3
|
+
import { GuardrailClient } from '../../index';
|
|
4
|
+
|
|
5
|
+
export async function handleGuardrailList(client: any) { // using any to match index signature, but we instantiate specific client inside
|
|
6
|
+
const config = getConfig();
|
|
7
|
+
const gClient = new GuardrailClient({ apiKey: config.apiKey || '', baseUrl: config.baseUrl });
|
|
8
|
+
|
|
9
|
+
const s = spinner();
|
|
10
|
+
s.start('Fetching guardrails...');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const guards = await gClient.list();
|
|
14
|
+
s.stop(`Found ${guards.length} guardrails`);
|
|
15
|
+
|
|
16
|
+
if (guards.length === 0) {
|
|
17
|
+
console.log(yellow('No guardrails found. Create one with "lt guardrails create".'));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
guards.forEach((g: any) => {
|
|
22
|
+
console.log(green(`• ${g.name}`) + gray(` (ID: ${g.id})`));
|
|
23
|
+
if (g.description) console.log(gray(` ${g.description}`));
|
|
24
|
+
console.log(gray(` Config: PII=${g.config.pii_enabled}, MinLen=${g.config.min_length}`));
|
|
25
|
+
console.log('');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
} catch (e: any) {
|
|
29
|
+
s.stop(red(`Failed to list guardrails: ${e.message}`));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function handleGuardrailCreate(client: any) {
|
|
34
|
+
const config = getConfig();
|
|
35
|
+
const gClient = new GuardrailClient({ apiKey: config.apiKey || '', baseUrl: config.baseUrl });
|
|
36
|
+
|
|
37
|
+
intro('Create a new Data Guardrail');
|
|
38
|
+
|
|
39
|
+
const name = await text({
|
|
40
|
+
message: 'Guardrail Name:',
|
|
41
|
+
placeholder: 'e.g. Strict Safety Policy',
|
|
42
|
+
validate(value) {
|
|
43
|
+
if (!value) return 'Name is required';
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
if (isCancel(name)) return;
|
|
47
|
+
|
|
48
|
+
const description = await text({
|
|
49
|
+
message: 'Description (optional):',
|
|
50
|
+
placeholder: 'Filters PII and short text',
|
|
51
|
+
});
|
|
52
|
+
if (isCancel(description)) return;
|
|
53
|
+
|
|
54
|
+
// Interactive Config
|
|
55
|
+
const minLen = await text({
|
|
56
|
+
message: 'Minimum Text Length (0 for no limit):',
|
|
57
|
+
initialValue: '0',
|
|
58
|
+
validate(value) {
|
|
59
|
+
if (isNaN(Number(value))) return 'Must be a number';
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (isCancel(minLen)) return;
|
|
63
|
+
|
|
64
|
+
const enablePii = await confirm({
|
|
65
|
+
message: 'Enable PII Filtering (Email/Phone)?',
|
|
66
|
+
initialValue: false
|
|
67
|
+
});
|
|
68
|
+
if (isCancel(enablePii)) return;
|
|
69
|
+
|
|
70
|
+
const patterns = await text({
|
|
71
|
+
message: 'Regex Patterns to Block (comma separated, optional):',
|
|
72
|
+
placeholder: 'e.g. bad_word, another_one',
|
|
73
|
+
});
|
|
74
|
+
if (isCancel(patterns)) return;
|
|
75
|
+
|
|
76
|
+
const s = spinner();
|
|
77
|
+
s.start('Creating guardrail...');
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const regexList = (patterns as string).split(',').map(p => p.trim()).filter(p => p.length > 0);
|
|
81
|
+
|
|
82
|
+
const payload = {
|
|
83
|
+
name,
|
|
84
|
+
description,
|
|
85
|
+
config: {
|
|
86
|
+
min_length: Number(minLen),
|
|
87
|
+
pii_enabled: enablePii,
|
|
88
|
+
regex_patterns: regexList,
|
|
89
|
+
profanity_enabled: false
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const result = await gClient.create(payload);
|
|
94
|
+
s.stop(green(`Guardrail "${result.name}" created successfully!`));
|
|
95
|
+
console.log(gray(`ID: ${result.id}`));
|
|
96
|
+
|
|
97
|
+
} catch (e: any) {
|
|
98
|
+
s.stop(red(`Failed to create guardrail: ${e.message}`));
|
|
99
|
+
}
|
|
100
|
+
}
|