aigie-sdk 1.0.0
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/LICENSE +21 -0
- package/README.md +501 -0
- package/dist/index.d.mts +5657 -0
- package/dist/index.d.ts +5657 -0
- package/dist/index.js +9831 -0
- package/dist/index.mjs +9637 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Kyte AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
# @kyte/sdk - TypeScript/JavaScript SDK
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for **Kyte** - AI Agent Monitoring and Autonomous Remediation.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@kyte/sdk)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## โจ Features
|
|
10
|
+
|
|
11
|
+
- ๐ฏ **Automatic Tracing** - Zero-config tracing with `@traceable` decorator
|
|
12
|
+
- ๐ **Framework Wrappers** - Auto-trace OpenAI, Anthropic, and more
|
|
13
|
+
- ๐ **Full Observability** - Traces, spans, metrics, and scores
|
|
14
|
+
- ๐ค **Autonomous Remediation** - Automatic error fixing in production
|
|
15
|
+
- ๐ก๏ธ **Proactive Prevention** - Prevent errors before they happen
|
|
16
|
+
- ๐ **Context Tracking** - AsyncLocalStorage for automatic parent-child relationships
|
|
17
|
+
- ๐ช **Full Type Safety** - Complete TypeScript definitions
|
|
18
|
+
- ๐ฆ **Dual Package** - ESM and CommonJS support
|
|
19
|
+
- ๐ **Production Ready** - Batching, error handling, zero dependencies
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## ๐ฆ Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @kyte/sdk
|
|
27
|
+
# or
|
|
28
|
+
yarn add @kyte/sdk
|
|
29
|
+
# or
|
|
30
|
+
pnpm add @kyte/sdk
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Optional Peer Dependencies
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# For OpenAI integration
|
|
37
|
+
npm install openai
|
|
38
|
+
|
|
39
|
+
# For Anthropic integration
|
|
40
|
+
npm install @anthropic-ai/sdk
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ๐ Quick Start
|
|
46
|
+
|
|
47
|
+
### 1. Initialize Kyte
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { initKyte } from '@kyte/sdk';
|
|
51
|
+
|
|
52
|
+
initKyte({
|
|
53
|
+
apiUrl: 'https://your-kyte-instance.com/api',
|
|
54
|
+
apiKey: process.env.KYTE_API_KEY!,
|
|
55
|
+
projectName: 'my-project',
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Auto-Trace OpenAI Calls
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import OpenAI from 'openai';
|
|
63
|
+
import { wrapOpenAI } from '@kyte/sdk';
|
|
64
|
+
|
|
65
|
+
const openai = wrapOpenAI(new OpenAI({
|
|
66
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
// All calls are automatically traced!
|
|
70
|
+
const completion = await openai.chat.completions.create({
|
|
71
|
+
model: 'gpt-4',
|
|
72
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Use the `@traceable` Decorator
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { traceable } from '@kyte/sdk';
|
|
80
|
+
|
|
81
|
+
class MyService {
|
|
82
|
+
@traceable({ name: 'processData', type: 'chain' })
|
|
83
|
+
async processData(input: string) {
|
|
84
|
+
// Your code here - automatically traced!
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## ๐ Usage Guide
|
|
93
|
+
|
|
94
|
+
### Manual Tracing
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { getKyte } from '@kyte/sdk';
|
|
98
|
+
|
|
99
|
+
const kyte = getKyte();
|
|
100
|
+
|
|
101
|
+
// Create a trace
|
|
102
|
+
await kyte.trace('myOperation', async () => {
|
|
103
|
+
// Create child spans
|
|
104
|
+
const data = await kyte.span('fetchData', async () => {
|
|
105
|
+
return fetchDataFromDB();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const processed = await kyte.span('processData', async () => {
|
|
109
|
+
return processData(data);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return processed;
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Decorator-Based Tracing
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { traceable } from '@kyte/sdk';
|
|
120
|
+
|
|
121
|
+
class OrderService {
|
|
122
|
+
@traceable({ name: 'createOrder', type: 'chain' })
|
|
123
|
+
async createOrder(userId: string, items: string[]) {
|
|
124
|
+
const user = await this.fetchUser(userId);
|
|
125
|
+
const total = await this.calculateTotal(items);
|
|
126
|
+
return { user, total };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@traceable({ type: 'tool' })
|
|
130
|
+
async fetchUser(userId: string) {
|
|
131
|
+
// Automatically becomes a span
|
|
132
|
+
return await db.users.findById(userId);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@traceable({ type: 'tool' })
|
|
136
|
+
async calculateTotal(items: string[]) {
|
|
137
|
+
// Another automatic span
|
|
138
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### OpenAI Integration
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { wrapOpenAI } from '@kyte/sdk';
|
|
147
|
+
import OpenAI from 'openai';
|
|
148
|
+
|
|
149
|
+
const openai = wrapOpenAI(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }));
|
|
150
|
+
|
|
151
|
+
// All these calls are automatically traced with:
|
|
152
|
+
// - Model name
|
|
153
|
+
// - Token counts
|
|
154
|
+
// - Cost calculation
|
|
155
|
+
// - Latency tracking
|
|
156
|
+
|
|
157
|
+
await openai.chat.completions.create({ /* ... */ });
|
|
158
|
+
await openai.embeddings.create({ /* ... */ });
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Anthropic Integration
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { wrapAnthropic } from '@kyte/sdk';
|
|
165
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
166
|
+
|
|
167
|
+
const anthropic = wrapAnthropic(new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }));
|
|
168
|
+
|
|
169
|
+
// Auto-traced with full metrics
|
|
170
|
+
await anthropic.messages.create({
|
|
171
|
+
model: 'claude-3-opus-20240229',
|
|
172
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Session Tracking (Multi-Turn Conversations)
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
const sessionId = 'user-123-conversation-456';
|
|
180
|
+
|
|
181
|
+
// Turn 1
|
|
182
|
+
await kyte.trace('turn1', async () => {
|
|
183
|
+
return 'Response 1';
|
|
184
|
+
}, { sessionId });
|
|
185
|
+
|
|
186
|
+
// Turn 2
|
|
187
|
+
await kyte.trace('turn2', async () => {
|
|
188
|
+
return 'Response 2';
|
|
189
|
+
}, { sessionId });
|
|
190
|
+
|
|
191
|
+
// All traces are grouped in the same session!
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Adding Scores/Feedback
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
await kyte.trace('generateResponse', async () => {
|
|
198
|
+
const response = generateResponse();
|
|
199
|
+
|
|
200
|
+
// Add quality score
|
|
201
|
+
const context = kyte.getCurrentContext();
|
|
202
|
+
if (context.traceId) {
|
|
203
|
+
await kyte.addScore(context.traceId, {
|
|
204
|
+
name: 'quality',
|
|
205
|
+
value: 0.95,
|
|
206
|
+
comment: 'High quality response',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return response;
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Error Handling
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// Errors are automatically captured
|
|
218
|
+
await kyte.trace('riskyOperation', async () => {
|
|
219
|
+
throw new Error('Something went wrong');
|
|
220
|
+
// Error is traced with full stack trace
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Batching (Performance Optimization)
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
initKyte({
|
|
228
|
+
apiUrl: 'https://your-kyte.com/api',
|
|
229
|
+
apiKey: 'your-key',
|
|
230
|
+
batchEnabled: true, // Enable batching
|
|
231
|
+
batchSize: 10, // Batch every 10 traces
|
|
232
|
+
batchTimeout: 1000, // Or every 1 second
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Traces are now batched for better performance!
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## ๐ง Configuration
|
|
241
|
+
|
|
242
|
+
### KyteConfig Options
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
interface KyteConfig {
|
|
246
|
+
/** Kyte API endpoint URL (required) */
|
|
247
|
+
apiUrl: string;
|
|
248
|
+
|
|
249
|
+
/** API key for authentication (required) */
|
|
250
|
+
apiKey: string;
|
|
251
|
+
|
|
252
|
+
/** Project name for grouping traces */
|
|
253
|
+
projectName?: string;
|
|
254
|
+
|
|
255
|
+
/** Default tags to add to all traces */
|
|
256
|
+
defaultTags?: string[];
|
|
257
|
+
|
|
258
|
+
/** Default metadata to add to all traces */
|
|
259
|
+
defaultMetadata?: Record<string, any>;
|
|
260
|
+
|
|
261
|
+
/** Enable/disable tracing (default: true) */
|
|
262
|
+
enabled?: boolean;
|
|
263
|
+
|
|
264
|
+
/** Batch traces before sending (default: false) */
|
|
265
|
+
batchEnabled?: boolean;
|
|
266
|
+
|
|
267
|
+
/** Batch size (default: 10) */
|
|
268
|
+
batchSize?: number;
|
|
269
|
+
|
|
270
|
+
/** Batch timeout in milliseconds (default: 1000) */
|
|
271
|
+
batchTimeout?: number;
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### TraceableConfig Options
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
interface TraceableConfig {
|
|
279
|
+
/** Name override for the trace/span */
|
|
280
|
+
name?: string;
|
|
281
|
+
|
|
282
|
+
/** Type override (llm, chain, tool, etc.) */
|
|
283
|
+
type?: SpanType;
|
|
284
|
+
|
|
285
|
+
/** Tags to add */
|
|
286
|
+
tags?: string[];
|
|
287
|
+
|
|
288
|
+
/** Metadata to add */
|
|
289
|
+
metadata?: Record<string, any>;
|
|
290
|
+
|
|
291
|
+
/** Capture function arguments as input (default: true) */
|
|
292
|
+
captureInput?: boolean;
|
|
293
|
+
|
|
294
|
+
/** Capture function output (default: true) */
|
|
295
|
+
captureOutput?: boolean;
|
|
296
|
+
|
|
297
|
+
/** Capture errors (default: true) */
|
|
298
|
+
captureErrors?: boolean;
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## ๐๏ธ Architecture
|
|
305
|
+
|
|
306
|
+
### Automatic Context Propagation
|
|
307
|
+
|
|
308
|
+
Kyte uses Node.js's **AsyncLocalStorage** to automatically track parent-child relationships:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
await kyte.trace('parent', async () => {
|
|
312
|
+
// This automatically becomes a child span
|
|
313
|
+
await kyte.span('child1', async () => { /* ... */ });
|
|
314
|
+
|
|
315
|
+
// This too!
|
|
316
|
+
await kyte.span('child2', async () => { /* ... */ });
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
No need to manually pass trace IDs around!
|
|
321
|
+
|
|
322
|
+
### Dual Package Support
|
|
323
|
+
|
|
324
|
+
The SDK works in both ESM and CommonJS projects:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
// ESM
|
|
328
|
+
import { initKyte } from '@kyte/sdk';
|
|
329
|
+
|
|
330
|
+
// CommonJS
|
|
331
|
+
const { initKyte } = require('@kyte/sdk');
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## ๐ Framework Integration
|
|
337
|
+
|
|
338
|
+
### Next.js (App Router)
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// app/api/chat/route.ts
|
|
342
|
+
import { initKyte, wrapOpenAI } from '@kyte/sdk';
|
|
343
|
+
import OpenAI from 'openai';
|
|
344
|
+
|
|
345
|
+
initKyte({
|
|
346
|
+
apiUrl: process.env.KYTE_API_URL!,
|
|
347
|
+
apiKey: process.env.KYTE_API_KEY!,
|
|
348
|
+
projectName: 'nextjs-app',
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const openai = wrapOpenAI(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }));
|
|
352
|
+
|
|
353
|
+
export async function POST(req: Request) {
|
|
354
|
+
const { message } = await req.json();
|
|
355
|
+
|
|
356
|
+
const completion = await openai.chat.completions.create({
|
|
357
|
+
model: 'gpt-4',
|
|
358
|
+
messages: [{ role: 'user', content: message }],
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
return Response.json(completion);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Express.js
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import express from 'express';
|
|
369
|
+
import { initKyte, getKyte } from '@kyte/sdk';
|
|
370
|
+
|
|
371
|
+
initKyte({
|
|
372
|
+
apiUrl: process.env.KYTE_API_URL!,
|
|
373
|
+
apiKey: process.env.KYTE_API_KEY!,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const app = express();
|
|
377
|
+
|
|
378
|
+
app.post('/api/process', async (req, res) => {
|
|
379
|
+
const kyte = getKyte();
|
|
380
|
+
|
|
381
|
+
const result = await kyte.trace('processRequest', async () => {
|
|
382
|
+
// Your processing logic
|
|
383
|
+
return processData(req.body);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
res.json(result);
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### NestJS
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import { Injectable } from '@nestjs/common';
|
|
394
|
+
import { traceable } from '@kyte/sdk';
|
|
395
|
+
|
|
396
|
+
@Injectable()
|
|
397
|
+
export class UserService {
|
|
398
|
+
@traceable({ name: 'getUser', type: 'tool' })
|
|
399
|
+
async getUser(id: string) {
|
|
400
|
+
return await this.userRepository.findById(id);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
@traceable({ name: 'createUser', type: 'tool' })
|
|
404
|
+
async createUser(data: CreateUserDto) {
|
|
405
|
+
return await this.userRepository.create(data);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## ๐ Advanced Features
|
|
413
|
+
|
|
414
|
+
### Kyte's Unique Capabilities
|
|
415
|
+
|
|
416
|
+
Once you're using the SDK, you automatically get access to Kyte's advanced features:
|
|
417
|
+
|
|
418
|
+
#### 1. **Autonomous Error Remediation**
|
|
419
|
+
- Kyte automatically detects errors in your traces
|
|
420
|
+
- Generates fixes using AI
|
|
421
|
+
- Applies fixes to production
|
|
422
|
+
- Monitors for success
|
|
423
|
+
|
|
424
|
+
#### 2. **Proactive Error Prevention**
|
|
425
|
+
- Analyzes patterns across all traces
|
|
426
|
+
- Predicts potential failures
|
|
427
|
+
- Alerts before errors occur
|
|
428
|
+
|
|
429
|
+
#### 3. **Context Drift Detection**
|
|
430
|
+
- Monitors multi-turn conversations
|
|
431
|
+
- Detects when context is lost
|
|
432
|
+
- Alerts when agent goes off-track
|
|
433
|
+
|
|
434
|
+
#### 4. **Advanced Analytics**
|
|
435
|
+
- Success rate by operation
|
|
436
|
+
- Latency percentiles
|
|
437
|
+
- Cost tracking
|
|
438
|
+
- Token usage patterns
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## ๐งช Testing
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
import { initKyte, getKyte } from '@kyte/sdk';
|
|
446
|
+
|
|
447
|
+
// Disable tracing in tests
|
|
448
|
+
initKyte({
|
|
449
|
+
apiUrl: 'http://localhost:8000/api',
|
|
450
|
+
apiKey: 'test-key',
|
|
451
|
+
enabled: false, // Tracing disabled
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// Or enable/disable dynamically
|
|
455
|
+
const kyte = getKyte();
|
|
456
|
+
kyte.disable(); // Disable
|
|
457
|
+
kyte.enable(); // Enable
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## ๐ Examples
|
|
463
|
+
|
|
464
|
+
Check out the `/examples` directory:
|
|
465
|
+
- `basic-usage.ts` - Core SDK features
|
|
466
|
+
- `openai-example.ts` - OpenAI integration
|
|
467
|
+
- `next-js-app/` - Full Next.js example
|
|
468
|
+
- `express-api/` - Express.js example
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## ๐ค Contributing
|
|
473
|
+
|
|
474
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## ๐ License
|
|
479
|
+
|
|
480
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## ๐ Links
|
|
485
|
+
|
|
486
|
+
- **Website:** https://kyte.ai
|
|
487
|
+
- **Documentation:** https://docs.kyte.ai
|
|
488
|
+
- **GitHub:** https://github.com/kyte-ai/kyte
|
|
489
|
+
- **NPM:** https://www.npmjs.com/package/@kyte/sdk
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## ๐ฌ Support
|
|
494
|
+
|
|
495
|
+
- **Email:** support@kyte.ai
|
|
496
|
+
- **Slack:** kyte-community.slack.com
|
|
497
|
+
- **Issues:** https://github.com/kyte-ai/kyte/issues
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
**Built with โค๏ธ by the Kyte team**
|