langtrain 0.1.6 → 0.1.9
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 +301 -125
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +303 -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 +206 -49
- 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.9",
|
|
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,12 +1,35 @@
|
|
|
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
|
+
// Initialize clients with config
|
|
32
|
+
// Clients are initialized inside main loop to support re-login
|
|
10
33
|
|
|
11
34
|
async function main() {
|
|
12
35
|
const program = new Command();
|
|
@@ -14,51 +37,179 @@ async function main() {
|
|
|
14
37
|
program
|
|
15
38
|
.name('langtrain')
|
|
16
39
|
.description('Langtrain CLI for AI Model Fine-tuning and Generation')
|
|
17
|
-
.version('0.1.
|
|
40
|
+
.version('0.1.9');
|
|
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
|
-
|
|
37
|
-
|
|
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 v0.1.9 '))}`);
|
|
38
56
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
// Check auth
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
if (!config.apiKey) {
|
|
60
|
+
intro(yellow('Authentication required'));
|
|
61
|
+
const apiKey = await password({
|
|
62
|
+
message: 'Enter your Langtrain API Key:',
|
|
63
|
+
validate(value) {
|
|
64
|
+
if (!value || value.length === 0) return 'API Key is required';
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (isCancel(apiKey)) {
|
|
69
|
+
cancel('Operation cancelled');
|
|
70
|
+
process.exit(0);
|
|
48
71
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
|
|
73
|
+
saveConfig({ ...config, apiKey });
|
|
74
|
+
intro(green('Successfully logged in!'));
|
|
52
75
|
}
|
|
53
76
|
|
|
54
|
-
|
|
77
|
+
while (true) {
|
|
78
|
+
const operation = await select({
|
|
79
|
+
message: 'Select an operation:',
|
|
80
|
+
options: [
|
|
81
|
+
{ value: 'group-agents', label: '🤖 Agents (Server)', hint: 'Chat with custom agents' },
|
|
82
|
+
{ value: 'agent-list', label: ' ↳ List & Run Agents' },
|
|
83
|
+
|
|
84
|
+
{ value: 'group-tune', label: '🧠 Langtune (LLM)', hint: 'Fine-tuning & Text Generation' },
|
|
85
|
+
{ value: 'tune-finetune', label: ' ↳ Fine-tune Text Model' },
|
|
86
|
+
{ value: 'tune-generate', label: ' ↳ Generate Text' },
|
|
87
|
+
|
|
88
|
+
{ value: 'group-vision', label: '👁️ Langvision (Vision)', hint: 'Vision Analysis & Tuning' },
|
|
89
|
+
{ value: 'vision-finetune', label: ' ↳ Fine-tune Vision Model' },
|
|
90
|
+
{ value: 'vision-generate', label: ' ↳ Generate Vision Response' },
|
|
91
|
+
|
|
92
|
+
{ value: 'group-settings', label: '⚙️ Settings' },
|
|
93
|
+
{ value: 'login', label: ' ↳ Update API Key' },
|
|
94
|
+
{ value: 'exit', label: ' ↳ Exit' }
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (isCancel(operation) || operation === 'exit') {
|
|
99
|
+
outro('Goodbye!');
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof operation === 'string' && operation.startsWith('group-')) {
|
|
104
|
+
// Header selected, just loop
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
// Re-read config & re-init clients
|
|
110
|
+
const currentConfig = getConfig();
|
|
111
|
+
const currentVision = new Langvision({ apiKey: currentConfig.apiKey });
|
|
112
|
+
const currentTune = new Langtune({ apiKey: currentConfig.apiKey });
|
|
113
|
+
const currentAgent = new AgentClient({ apiKey: currentConfig.apiKey, baseUrl: currentConfig.baseUrl });
|
|
114
|
+
|
|
115
|
+
if (operation === 'login') {
|
|
116
|
+
await handleLogin();
|
|
117
|
+
} else if (operation === 'tune-finetune') {
|
|
118
|
+
await handleTuneFinetune(currentTune);
|
|
119
|
+
} else if (operation === 'tune-generate') {
|
|
120
|
+
await handleTuneGenerate(currentTune);
|
|
121
|
+
} else if (operation === 'vision-finetune') {
|
|
122
|
+
await handleVisionFinetune(currentVision);
|
|
123
|
+
} else if (operation === 'vision-generate') {
|
|
124
|
+
await handleVisionGenerate(currentVision);
|
|
125
|
+
} else if (operation === 'agent-list') {
|
|
126
|
+
await handleAgentList(currentAgent);
|
|
127
|
+
}
|
|
128
|
+
} catch (error: any) {
|
|
129
|
+
outro(red(`Error: ${error.message}`));
|
|
130
|
+
// Don't exit, just loop back to menu
|
|
131
|
+
}
|
|
132
|
+
}
|
|
55
133
|
});
|
|
56
134
|
|
|
57
135
|
program.parse(process.argv);
|
|
58
136
|
}
|
|
59
137
|
|
|
138
|
+
async function handleLogin() {
|
|
139
|
+
const apiKey = await password({
|
|
140
|
+
message: 'Enter your new Langtrain API Key:',
|
|
141
|
+
validate(value) {
|
|
142
|
+
if (!value || value.length === 0) return 'API Key is required';
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (isCancel(apiKey)) cancel('Operation cancelled');
|
|
147
|
+
|
|
148
|
+
const config = getConfig();
|
|
149
|
+
saveConfig({ ...config, apiKey });
|
|
150
|
+
intro(green('API Key updated successfully!'));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function handleAgentList(client: AgentClient) {
|
|
154
|
+
const s = spinner();
|
|
155
|
+
s.start('Fetching agents...');
|
|
156
|
+
const agents = await client.list();
|
|
157
|
+
s.stop(`Found ${agents.length} agents`);
|
|
158
|
+
|
|
159
|
+
if (agents.length === 0) {
|
|
160
|
+
intro(yellow('No agents found in your workspace.'));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const agentId = await select({
|
|
165
|
+
message: 'Select an agent to run:',
|
|
166
|
+
options: agents.map(a => ({ value: a.id, label: a.name, hint: a.description || 'No description' }))
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (isCancel(agentId)) return;
|
|
170
|
+
|
|
171
|
+
await handleAgentRun(client, agentId as string, agents.find(a => a.id === agentId)?.name || 'Agent');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function handleAgentRun(client: AgentClient, agentId: string, agentName: string) {
|
|
175
|
+
intro(bgCyan(black(` Chatting with ${agentName} `)));
|
|
176
|
+
console.log(gray('Type "exit" to quit conversation.'));
|
|
177
|
+
|
|
178
|
+
let conversationId: string | undefined = undefined;
|
|
179
|
+
|
|
180
|
+
while (true) {
|
|
181
|
+
const input = await text({
|
|
182
|
+
message: 'You:',
|
|
183
|
+
placeholder: 'Type a message...',
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (isCancel(input) || input === 'exit') {
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const s = spinner();
|
|
191
|
+
s.start('Agent is thinking...');
|
|
192
|
+
try {
|
|
193
|
+
const result = await client.execute(agentId, { prompt: input }, [], conversationId);
|
|
194
|
+
s.stop();
|
|
195
|
+
|
|
196
|
+
if (result.output && result.output.response) {
|
|
197
|
+
console.log(gradient.pastel(`Agent: ${result.output.response}`));
|
|
198
|
+
} else {
|
|
199
|
+
console.log(gradient.pastel(`Agent: ${JSON.stringify(result.output)}`));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
conversationId = result.conversation_id;
|
|
203
|
+
} catch (e: any) {
|
|
204
|
+
s.stop(red('Error running agent.'));
|
|
205
|
+
console.error(e);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
60
211
|
// Handler for Langtune Fine-tuning
|
|
61
|
-
async function handleTuneFinetune() {
|
|
212
|
+
async function handleTuneFinetune(tune: Langtune) {
|
|
62
213
|
const model = await text({
|
|
63
214
|
message: 'Enter base model (e.g., gpt-3.5-turbo):',
|
|
64
215
|
placeholder: 'gpt-3.5-turbo',
|
|
@@ -85,10 +236,12 @@ async function handleTuneFinetune() {
|
|
|
85
236
|
if (isCancel(epochs)) cancel('Operation cancelled.');
|
|
86
237
|
|
|
87
238
|
const s = spinner();
|
|
88
|
-
s.start('
|
|
239
|
+
s.start('Connecting to Langtrain Cloud...');
|
|
240
|
+
await new Promise(r => setTimeout(r, 800)); // Simulatoin
|
|
241
|
+
s.message('Starting fine-tuning job...');
|
|
89
242
|
|
|
90
243
|
try {
|
|
91
|
-
// Check if FinetuneConfig types match what's needed.
|
|
244
|
+
// Check if FinetuneConfig types match what's needed.
|
|
92
245
|
// Casting to any to bypass strict type checking for this demo or ensure types are imported correctly.
|
|
93
246
|
// In a real scenario, we'd construct the full config object.
|
|
94
247
|
const config: any = {
|
|
@@ -103,7 +256,7 @@ async function handleTuneFinetune() {
|
|
|
103
256
|
};
|
|
104
257
|
|
|
105
258
|
await tune.finetune(config);
|
|
106
|
-
s.stop(green('Fine-tuning job started!'));
|
|
259
|
+
s.stop(green('Fine-tuning job started successfully! 🚀'));
|
|
107
260
|
} catch (e: any) {
|
|
108
261
|
s.stop(red('Failed to start job.'));
|
|
109
262
|
throw e;
|
|
@@ -111,7 +264,7 @@ async function handleTuneFinetune() {
|
|
|
111
264
|
}
|
|
112
265
|
|
|
113
266
|
// Handler for Langtune Generation
|
|
114
|
-
async function handleTuneGenerate() {
|
|
267
|
+
async function handleTuneGenerate(tune: Langtune) {
|
|
115
268
|
const model = await text({
|
|
116
269
|
message: 'Enter model path:',
|
|
117
270
|
placeholder: './output/model',
|
|
@@ -126,13 +279,13 @@ async function handleTuneGenerate() {
|
|
|
126
279
|
if (isCancel(prompt)) cancel('Operation cancelled');
|
|
127
280
|
|
|
128
281
|
const s = spinner();
|
|
129
|
-
s.start('
|
|
282
|
+
s.start('Connecting to Langtrain Inference API...');
|
|
130
283
|
|
|
131
284
|
try {
|
|
132
285
|
const response = await tune.generate(model as string, { prompt: prompt as string });
|
|
133
286
|
s.stop('Generation complete');
|
|
134
287
|
intro('Response:');
|
|
135
|
-
console.log(response);
|
|
288
|
+
console.log(gradient.pastel(response));
|
|
136
289
|
} catch (e: any) {
|
|
137
290
|
s.stop(red('Generation failed.'));
|
|
138
291
|
throw e;
|
|
@@ -140,7 +293,7 @@ async function handleTuneGenerate() {
|
|
|
140
293
|
}
|
|
141
294
|
|
|
142
295
|
// Handler for Langvision Fine-tuning
|
|
143
|
-
async function handleVisionFinetune() {
|
|
296
|
+
async function handleVisionFinetune(vision: Langvision) {
|
|
144
297
|
const model = await text({
|
|
145
298
|
message: 'Enter base vision model:',
|
|
146
299
|
placeholder: 'llava-v1.5-7b',
|
|
@@ -161,7 +314,9 @@ async function handleVisionFinetune() {
|
|
|
161
314
|
});
|
|
162
315
|
|
|
163
316
|
const s = spinner();
|
|
164
|
-
s.start('
|
|
317
|
+
s.start('Analyzing dataset structure...');
|
|
318
|
+
await new Promise(r => setTimeout(r, 800));
|
|
319
|
+
s.message('Starting vision fine-tuning on Langtrain Cloud...');
|
|
165
320
|
|
|
166
321
|
try {
|
|
167
322
|
const config: any = {
|
|
@@ -174,7 +329,7 @@ async function handleVisionFinetune() {
|
|
|
174
329
|
outputDir: './vision-output'
|
|
175
330
|
};
|
|
176
331
|
await vision.finetune(config);
|
|
177
|
-
s.stop(green('Vision fine-tuning started!'));
|
|
332
|
+
s.stop(green('Vision fine-tuning started successfully! 👁️'));
|
|
178
333
|
} catch (e: any) {
|
|
179
334
|
s.stop(red('Failed to start vision job.'));
|
|
180
335
|
throw e;
|
|
@@ -182,7 +337,7 @@ async function handleVisionFinetune() {
|
|
|
182
337
|
}
|
|
183
338
|
|
|
184
339
|
// Handler for Langvision Generation
|
|
185
|
-
async function handleVisionGenerate() {
|
|
340
|
+
async function handleVisionGenerate(vision: Langvision) {
|
|
186
341
|
const model = await text({
|
|
187
342
|
message: 'Enter model path:',
|
|
188
343
|
placeholder: './vision-output/model',
|
|
@@ -197,13 +352,15 @@ async function handleVisionGenerate() {
|
|
|
197
352
|
if (isCancel(prompt)) cancel('Operation cancelled');
|
|
198
353
|
|
|
199
354
|
const s = spinner();
|
|
200
|
-
s.start('
|
|
355
|
+
s.start('Uploading image and context...');
|
|
356
|
+
await new Promise(r => setTimeout(r, 600));
|
|
357
|
+
s.message('Generating vision response...');
|
|
201
358
|
|
|
202
359
|
try {
|
|
203
360
|
const response = await vision.generate(model as string, { prompt: prompt as string });
|
|
204
361
|
s.stop('Generation complete');
|
|
205
362
|
intro('Response:');
|
|
206
|
-
console.log(response);
|
|
363
|
+
console.log(gradient.pastel(response));
|
|
207
364
|
} catch (e: any) {
|
|
208
365
|
s.stop(red('Generation failed.'));
|
|
209
366
|
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 };
|