teckel-ai 0.3.2 → 0.3.5

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.
@@ -1,363 +0,0 @@
1
- "use strict";
2
- /**
3
- * Conversation class for teckel-ai SDK v0.3.1
4
- * Manages a single conversation with fire-and-forget semantics
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.Conversation = void 0;
8
- const schemas_1 = require("./schemas");
9
- class Conversation {
10
- constructor(apiKey, endpoint, options, debug = false, extras = { timeoutMs: 5000 }) {
11
- this.turnCount = 0;
12
- this.sendQueue = Promise.resolve();
13
- this.apiKey = apiKey;
14
- this.endpoint = endpoint;
15
- this.sessionRef = options.sessionRef;
16
- this.userId = options.userId;
17
- this.metadata = options.metadata;
18
- this.startedAt = new Date();
19
- this.debug = debug;
20
- this.timeoutMs = extras.timeoutMs;
21
- if (this.debug) {
22
- console.log('[Teckel] Conversation started:', {
23
- sessionRef: this.sessionRef,
24
- userId: this.userId
25
- });
26
- }
27
- // Start conversation and store promise
28
- this.startPromise = this._startConversation().catch(err => {
29
- if (this.debug) {
30
- console.warn('[Teckel] Start failed:', err.message);
31
- }
32
- });
33
- }
34
- /**
35
- * Record a trace (single query-response interaction)
36
- * Fire-and-forget by default - never blocks
37
- * For serverless, call flush() before function termination
38
- */
39
- trace(data) {
40
- var _a;
41
- try {
42
- // Validate with Zod
43
- const validated = schemas_1.TraceDataSchema.parse(data);
44
- // Apply OTel alias mapping (beta): infer canonical fields from metadata if missing
45
- const mapped = this.mapOTelAliases(validated);
46
- // Increment local turn number immediately (client-side counter)
47
- const localTurn = ++this.turnCount;
48
- // Ensure we have a client-provided traceRef; if missing, generate a deterministic one
49
- const finalTraceRef = mapped.traceRef && mapped.traceRef.length > 0
50
- ? mapped.traceRef
51
- : `${this.sessionRef}:${localTurn}`;
52
- if (this.debug) {
53
- console.log('[Teckel] Queueing trace (fire-and-forget):', {
54
- sessionRef: this.sessionRef,
55
- turnNumber: localTurn,
56
- queryLength: mapped.query.length,
57
- responseLength: mapped.response.length,
58
- documentCount: ((_a = mapped.documents) === null || _a === void 0 ? void 0 : _a.length) || 0
59
- });
60
- }
61
- const toSend = Object.assign(Object.assign({}, mapped), { traceRef: finalTraceRef });
62
- // Fire-and-forget: enqueue and return immediately
63
- this.enqueueSend(async () => {
64
- try {
65
- await this.startPromise; // ensure conversation exists
66
- await this._sendTrace(toSend);
67
- }
68
- catch (err) {
69
- if (this.debug) {
70
- console.warn('[Teckel] Trace send failed (non-blocking):', (err === null || err === void 0 ? void 0 : err.message) || err);
71
- }
72
- }
73
- });
74
- return { traceRef: finalTraceRef, turnNumber: localTurn };
75
- }
76
- catch (err) {
77
- // Validation failed - log and continue (never throw to user)
78
- if (this.debug) {
79
- console.warn('[Teckel] Invalid trace data:', err);
80
- }
81
- }
82
- }
83
- /**
84
- * Synchronous trace: waits for HTTP send to complete.
85
- * Throws on network/validation errors.
86
- * Respects send queue to maintain trace ordering.
87
- */
88
- async traceSync(data, opt) {
89
- // Validate with Zod
90
- const validated = schemas_1.TraceDataSchema.parse(data);
91
- // Apply OTel alias mapping
92
- const mapped = this.mapOTelAliases(validated);
93
- // Increment local turn and compute final traceRef
94
- const localTurn = ++this.turnCount;
95
- const finalTraceRef = mapped.traceRef && mapped.traceRef.length > 0
96
- ? mapped.traceRef
97
- : `${this.sessionRef}:${localTurn}`;
98
- const toSend = Object.assign(Object.assign({}, mapped), { traceRef: finalTraceRef });
99
- try {
100
- await this.startPromise;
101
- // Wait for any queued operations to complete first (maintains ordering)
102
- await this.sendQueue.catch(() => { });
103
- await this._sendTrace(toSend, { timeoutMs: opt === null || opt === void 0 ? void 0 : opt.timeoutMs });
104
- return { traceRef: finalTraceRef, turnNumber: localTurn };
105
- }
106
- catch (err) {
107
- if (this.debug) {
108
- console.warn('[Teckel] Sync trace failed:', (err === null || err === void 0 ? void 0 : err.message) || err);
109
- }
110
- throw err;
111
- }
112
- }
113
- /**
114
- * Add user feedback signal
115
- * Never throws - gracefully handles errors
116
- */
117
- async feedback(data) {
118
- try {
119
- // Validate with Zod
120
- const validated = schemas_1.FeedbackDataSchema.parse(data);
121
- if (this.debug) {
122
- console.log('[Teckel] Sending feedback:', {
123
- sessionRef: this.sessionRef,
124
- type: validated.type
125
- });
126
- }
127
- // Enqueue feedback so flush() covers it in serverless
128
- this.enqueueSend(async () => {
129
- try {
130
- await this._sendFeedback(validated);
131
- }
132
- catch (err) {
133
- if (this.debug) {
134
- console.warn('[Teckel] Feedback failed:', (err === null || err === void 0 ? void 0 : err.message) || err);
135
- }
136
- }
137
- });
138
- }
139
- catch (err) {
140
- // Validation failed - log and continue
141
- if (this.debug) {
142
- console.warn('[Teckel] Invalid feedback data:', err);
143
- }
144
- }
145
- }
146
- /**
147
- * End the conversation
148
- * Flushes all pending traces before sending end signal
149
- * Never throws - gracefully handles errors
150
- */
151
- async end() {
152
- const duration = Date.now() - this.startedAt.getTime();
153
- if (this.debug) {
154
- console.log('[Teckel] Ending conversation:', {
155
- sessionRef: this.sessionRef,
156
- durationMs: duration,
157
- turnCount: this.turnCount
158
- });
159
- }
160
- // Enqueue end so it occurs after any pending sends
161
- this.enqueueSend(async () => {
162
- try {
163
- await this._endConversation(duration);
164
- }
165
- catch (err) {
166
- if (this.debug) {
167
- console.warn('[Teckel] End failed:', (err === null || err === void 0 ? void 0 : err.message) || err);
168
- }
169
- }
170
- });
171
- // Flush queue (serverless-safe)
172
- await this.flush();
173
- }
174
- /**
175
- * Read-only properties
176
- */
177
- get id() {
178
- return this.sessionRef;
179
- }
180
- get turns() {
181
- return this.turnCount;
182
- }
183
- get started() {
184
- return this.startedAt;
185
- }
186
- // Private HTTP methods
187
- // Lightweight fetch with a single retry on transient errors (429/5xx or network)
188
- async fetchWithRetry(url, init, opts) {
189
- var _a, _b;
190
- const retries = (_a = opts === null || opts === void 0 ? void 0 : opts.retries) !== null && _a !== void 0 ? _a : 1;
191
- const retryDelayMs = (_b = opts === null || opts === void 0 ? void 0 : opts.retryDelayMs) !== null && _b !== void 0 ? _b : 250;
192
- let attempt = 0;
193
- // Simple jittered delay
194
- const sleep = (ms) => new Promise(res => setTimeout(res, ms));
195
- // We reuse the same init; AbortSignal.timeout recreates a fresh signal per call
196
- while (true) {
197
- try {
198
- const response = await fetch(url, init);
199
- if (!response.ok && (response.status === 429 || (response.status >= 500 && response.status <= 599))) {
200
- if (attempt < retries) {
201
- attempt++;
202
- if (this.debug)
203
- console.warn('[Teckel] HTTP retry', { url, status: response.status, attempt });
204
- await sleep(retryDelayMs + Math.floor(Math.random() * 100));
205
- continue;
206
- }
207
- }
208
- return response;
209
- }
210
- catch (err) {
211
- if (attempt < retries) {
212
- attempt++;
213
- if (this.debug)
214
- console.warn('[Teckel] Network retry', { url, attempt, error: err instanceof Error ? err.message : String(err) });
215
- await sleep(retryDelayMs + Math.floor(Math.random() * 100));
216
- continue;
217
- }
218
- throw err;
219
- }
220
- }
221
- }
222
- async _startConversation() {
223
- const response = await this.fetchWithRetry(`${this.endpoint}/conversations`, {
224
- method: 'POST',
225
- headers: {
226
- 'Authorization': `Bearer ${this.apiKey}`,
227
- 'Content-Type': 'application/json'
228
- },
229
- keepalive: true,
230
- signal: AbortSignal.timeout ? AbortSignal.timeout(this.timeoutMs) : undefined,
231
- body: JSON.stringify({
232
- sessionRef: this.sessionRef,
233
- userId: this.userId,
234
- metadata: this.metadata
235
- })
236
- }, { retries: 1, retryDelayMs: 300 });
237
- if (!response.ok) {
238
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
239
- }
240
- }
241
- async _sendTrace(data, opt) {
242
- var _a;
243
- const response = await this.fetchWithRetry(`${this.endpoint}/conversations/${this.sessionRef}/traces`, {
244
- method: 'POST',
245
- headers: {
246
- 'Authorization': `Bearer ${this.apiKey}`,
247
- 'Content-Type': 'application/json'
248
- },
249
- keepalive: true,
250
- signal: AbortSignal.timeout ? AbortSignal.timeout((_a = opt === null || opt === void 0 ? void 0 : opt.timeoutMs) !== null && _a !== void 0 ? _a : this.timeoutMs) : undefined,
251
- body: JSON.stringify(data)
252
- }, { retries: 1, retryDelayMs: 300 });
253
- if (!response.ok) {
254
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
255
- }
256
- const result = await response.json();
257
- return result;
258
- }
259
- async _sendFeedback(data) {
260
- const response = await this.fetchWithRetry(`${this.endpoint}/conversations/${this.sessionRef}/feedback`, {
261
- method: 'POST',
262
- headers: {
263
- 'Authorization': `Bearer ${this.apiKey}`,
264
- 'Content-Type': 'application/json'
265
- },
266
- keepalive: true,
267
- signal: AbortSignal.timeout ? AbortSignal.timeout(this.timeoutMs) : undefined,
268
- body: JSON.stringify(data)
269
- }, { retries: 1, retryDelayMs: 300 });
270
- if (!response.ok) {
271
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
272
- }
273
- }
274
- async _endConversation(duration) {
275
- const response = await this.fetchWithRetry(`${this.endpoint}/conversations/${this.sessionRef}`, {
276
- method: 'PATCH',
277
- headers: {
278
- 'Authorization': `Bearer ${this.apiKey}`,
279
- 'Content-Type': 'application/json'
280
- },
281
- keepalive: true,
282
- signal: AbortSignal.timeout ? AbortSignal.timeout(this.timeoutMs) : undefined,
283
- body: JSON.stringify({
284
- durationMs: duration,
285
- turnCount: this.turnCount
286
- })
287
- }, { retries: 1, retryDelayMs: 300 });
288
- if (!response.ok) {
289
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
290
- }
291
- }
292
- // Utility: append a send task to the queue
293
- enqueueSend(task) {
294
- this.sendQueue = this.sendQueue.then(() => task()).catch(() => {
295
- // Errors are handled where task is defined; keep queue alive
296
- });
297
- }
298
- /**
299
- * Flush queued sends with a bounded timeout.
300
- * Returns when the queue is empty or the timeout elapses (whichever comes first).
301
- */
302
- async flush(timeoutMs) {
303
- const waitMs = (typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) && timeoutMs >= 0)
304
- ? timeoutMs
305
- : this.timeoutMs;
306
- // Snapshot current queue to cover all work up to this call
307
- const done = this.sendQueue.catch(() => { });
308
- let timer;
309
- try {
310
- await Promise.race([
311
- done,
312
- new Promise((_, reject) => {
313
- timer = setTimeout(() => reject(new Error('Flush timeout')), waitMs);
314
- })
315
- ]);
316
- }
317
- catch (err) {
318
- if (this.debug) {
319
- console.warn('[Teckel] Flush incomplete:', (err === null || err === void 0 ? void 0 : err.message) || err);
320
- }
321
- // Surface timeout so callers can react in serverless
322
- throw err;
323
- }
324
- finally {
325
- if (timer)
326
- clearTimeout(timer);
327
- }
328
- }
329
- // Utility: map OpenTelemetry-like metadata to canonical fields (beta)
330
- mapOTelAliases(data) {
331
- try {
332
- const meta = data.metadata;
333
- if (!meta)
334
- return data;
335
- const mapped = Object.assign({}, data);
336
- // Model
337
- if (!mapped.model && typeof meta['gen_ai.request.model'] === 'string') {
338
- mapped.model = meta['gen_ai.request.model'];
339
- }
340
- // Tokens
341
- const inTok = meta['gen_ai.usage.input_tokens'];
342
- const outTok = meta['gen_ai.usage.output_tokens'];
343
- const totTok = meta['gen_ai.usage.total_tokens'];
344
- if (!mapped.tokens && (typeof inTok === 'number' || typeof outTok === 'number')) {
345
- mapped.tokens = {
346
- prompt: typeof inTok === 'number' ? inTok : 0,
347
- completion: typeof outTok === 'number' ? outTok : 0,
348
- total: typeof totTok === 'number' ? totTok : ((typeof inTok === 'number' ? inTok : 0) + (typeof outTok === 'number' ? outTok : 0))
349
- };
350
- }
351
- // Latency
352
- const latency = meta['gen_ai.response.latency'];
353
- if (!mapped.responseTimeMs && typeof latency === 'number') {
354
- mapped.responseTimeMs = latency;
355
- }
356
- return mapped;
357
- }
358
- catch (_a) {
359
- return data;
360
- }
361
- }
362
- }
363
- exports.Conversation = Conversation;
package/dist/schemas.js DELETED
@@ -1,69 +0,0 @@
1
- "use strict";
2
- /**
3
- * Zod validation schemas for teckel-ai SDK v0.3.1
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TeckelConfigSchema = exports.FeedbackDataSchema = exports.ConversationOptionsSchema = exports.TraceDataSchema = exports.TokenUsageSchema = exports.DocumentSchema = void 0;
7
- const zod_1 = require("zod");
8
- /**
9
- * Document schema
10
- */
11
- exports.DocumentSchema = zod_1.z.object({
12
- documentRef: zod_1.z.string().min(1, 'documentRef is required'),
13
- documentName: zod_1.z.string().min(1, 'documentName is required'),
14
- documentText: zod_1.z.string().min(1, 'documentText is required'),
15
- documentLastUpdated: zod_1.z.string().optional(),
16
- sourceUri: zod_1.z.string().optional(),
17
- sourceType: zod_1.z.string().optional(),
18
- similarity: zod_1.z.number().min(0).max(1).optional(),
19
- rank: zod_1.z.number().int().nonnegative().optional(),
20
- ownerEmail: zod_1.z.string().email().optional(),
21
- documentType: zod_1.z.string().optional()
22
- });
23
- /**
24
- * Token usage schema
25
- */
26
- exports.TokenUsageSchema = zod_1.z.object({
27
- prompt: zod_1.z.number().int().nonnegative(),
28
- completion: zod_1.z.number().int().nonnegative(),
29
- total: zod_1.z.number().int().nonnegative()
30
- });
31
- /**
32
- * Trace data schema
33
- */
34
- exports.TraceDataSchema = zod_1.z.object({
35
- query: zod_1.z.string().min(1, 'query is required').max(10000, 'query too long (max 10,000 characters)'),
36
- response: zod_1.z.string().min(1, 'response is required').max(50000, 'response too long (max 50,000 characters)'),
37
- model: zod_1.z.string().optional(),
38
- responseTimeMs: zod_1.z.number().positive().optional(),
39
- documents: zod_1.z.array(exports.DocumentSchema).max(50, 'Too many documents (max 50)').optional(),
40
- tokens: exports.TokenUsageSchema.optional(),
41
- metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
42
- traceRef: zod_1.z.string().min(1).optional()
43
- });
44
- /**
45
- * Conversation options schema
46
- */
47
- exports.ConversationOptionsSchema = zod_1.z.object({
48
- sessionRef: zod_1.z.string().min(1, 'sessionRef is required'),
49
- userId: zod_1.z.string().optional(),
50
- metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional()
51
- });
52
- /**
53
- * Feedback data schema
54
- */
55
- exports.FeedbackDataSchema = zod_1.z.object({
56
- type: zod_1.z.enum(['thumbs_up', 'thumbs_down', 'flag', 'rating']),
57
- value: zod_1.z.string().optional(),
58
- comment: zod_1.z.string().optional(),
59
- traceRef: zod_1.z.string().optional()
60
- });
61
- /**
62
- * Config schema
63
- */
64
- exports.TeckelConfigSchema = zod_1.z.object({
65
- apiKey: zod_1.z.string().min(1, 'apiKey is required'),
66
- endpoint: zod_1.z.string().url().optional(),
67
- debug: zod_1.z.boolean().optional(),
68
- timeoutMs: zod_1.z.number().int().positive().max(60000).optional()
69
- });
package/dist/tracer.d.ts DELETED
@@ -1,18 +0,0 @@
1
- /**
2
- * TeckelTracer - Main SDK class for teckel-ai v0.3.1
3
- * Simple, lightweight SDK for AI conversation tracking
4
- */
5
- import { Conversation } from './conversation';
6
- import type { TeckelConfig, ConversationOptions } from './types';
7
- export declare class TeckelTracer {
8
- private readonly apiKey;
9
- private readonly endpoint;
10
- private readonly debug;
11
- private readonly timeoutMs;
12
- constructor(config: TeckelConfig);
13
- /**
14
- * Start a new conversation
15
- * sessionRef IS the public conversation identifier (sessionId is legacy alias)
16
- */
17
- start(options: ConversationOptions): Conversation;
18
- }
package/dist/tracer.js DELETED
@@ -1,45 +0,0 @@
1
- "use strict";
2
- /**
3
- * TeckelTracer - Main SDK class for teckel-ai v0.3.1
4
- * Simple, lightweight SDK for AI conversation tracking
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.TeckelTracer = void 0;
8
- const conversation_1 = require("./conversation");
9
- const schemas_1 = require("./schemas");
10
- class TeckelTracer {
11
- constructor(config) {
12
- // Validate config with Zod
13
- const validated = schemas_1.TeckelConfigSchema.parse(config);
14
- // API key format warning
15
- if (!validated.apiKey.startsWith('tk_live_')) {
16
- console.warn('[Teckel] API key should start with "tk_live_". ' +
17
- 'Current key: ' + validated.apiKey.substring(0, 10) + '...');
18
- }
19
- this.apiKey = validated.apiKey;
20
- this.endpoint = validated.endpoint || 'https://app.teckel.ai/api';
21
- this.debug = validated.debug || false;
22
- // Default timeout mirrors common telemetry SDKs (3–5s) to tolerate cold starts
23
- this.timeoutMs = typeof validated.timeoutMs === 'number' ? validated.timeoutMs : 5000;
24
- if (this.debug) {
25
- console.log('[Teckel] SDK initialized:', {
26
- endpoint: this.endpoint,
27
- version: '0.3.1',
28
- timeoutMs: this.timeoutMs
29
- });
30
- }
31
- }
32
- /**
33
- * Start a new conversation
34
- * sessionRef IS the public conversation identifier (sessionId is legacy alias)
35
- */
36
- start(options) {
37
- // Validate options with Zod
38
- const validated = schemas_1.ConversationOptionsSchema.parse(options);
39
- // Create and return conversation instance
40
- return new conversation_1.Conversation(this.apiKey, this.endpoint, validated, this.debug, {
41
- timeoutMs: this.timeoutMs
42
- });
43
- }
44
- }
45
- exports.TeckelTracer = TeckelTracer;
package/dist/types.d.ts DELETED
@@ -1,88 +0,0 @@
1
- /**
2
- * Type definitions for teckel-ai SDK v0.3.1
3
- * Simple, clean types matching existing database schema
4
- */
5
- /**
6
- * SDK Configuration
7
- */
8
- export interface TeckelConfig {
9
- apiKey: string;
10
- endpoint?: string;
11
- debug?: boolean;
12
- timeoutMs?: number;
13
- }
14
- /**
15
- * Conversation options
16
- * sessionId IS the conversation identifier
17
- */
18
- export interface ConversationOptions {
19
- sessionRef: string;
20
- userId?: string;
21
- metadata?: Record<string, any>;
22
- }
23
- /**
24
- * Document structure for RAG systems
25
- * Matches existing documents + chunk_events schema
26
- */
27
- export interface Document {
28
- documentRef: string;
29
- documentName: string;
30
- documentText: string;
31
- documentLastUpdated?: string;
32
- sourceUri?: string;
33
- sourceType?: string;
34
- similarity?: number;
35
- rank?: number;
36
- ownerEmail?: string;
37
- documentType?: string;
38
- }
39
- /**
40
- * Token usage tracking
41
- */
42
- export interface TokenUsage {
43
- prompt: number;
44
- completion: number;
45
- total: number;
46
- }
47
- /**
48
- * Trace data for a single query-response interaction
49
- * Matches existing traces table schema
50
- */
51
- export interface TraceData {
52
- query: string;
53
- response: string;
54
- model?: string;
55
- responseTimeMs?: number;
56
- documents?: Document[];
57
- tokens?: TokenUsage;
58
- metadata?: Record<string, any>;
59
- traceRef?: string;
60
- }
61
- /**
62
- * Feedback types
63
- */
64
- export type FeedbackType = 'thumbs_up' | 'thumbs_down' | 'flag' | 'rating';
65
- /**
66
- * User feedback signal
67
- */
68
- export interface FeedbackData {
69
- type: FeedbackType;
70
- value?: string;
71
- comment?: string;
72
- traceRef?: string;
73
- }
74
- /**
75
- * Result returned when a trace is created
76
- */
77
- export interface TraceResult {
78
- traceRef: string;
79
- turnNumber: number;
80
- }
81
- /**
82
- * Validation result structure
83
- */
84
- export interface ValidationResult {
85
- valid: boolean;
86
- errors: string[];
87
- warnings: string[];
88
- }
package/dist/types.js DELETED
@@ -1,6 +0,0 @@
1
- "use strict";
2
- /**
3
- * Type definitions for teckel-ai SDK v0.3.1
4
- * Simple, clean types matching existing database schema
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });