teckel-ai 0.3.2
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 +53 -0
- package/dist/conversation.d.ts +64 -0
- package/dist/conversation.js +363 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +22 -0
- package/dist/schemas.d.ts +217 -0
- package/dist/schemas.js +69 -0
- package/dist/tracer.d.ts +18 -0
- package/dist/tracer.js +45 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.js +6 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Teckel 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,53 @@
|
|
|
1
|
+
# teckel-ai
|
|
2
|
+
|
|
3
|
+
## What is Teckel AI?
|
|
4
|
+
|
|
5
|
+
Teckel AI helps you understand and improve your AI chatbots by analyzing conversations your users are having. We track what questions users ask, how well your AI answers them, and tell you which areas needs improvement.
|
|
6
|
+
|
|
7
|
+
**Your Problem**: Your RAG or MCP referencing AI chat system gives incomplete or incorrect answers because your knowledge base has gaps. Users get frustrated, support tickets increase, and you don't know which areas to focus on.
|
|
8
|
+
|
|
9
|
+
**Our Service**: We analyze every AI response for accuracy and completeness, cluster similar queries to identify trending topics (or let you define an area of interest and see related questions), and tell you exactly which AI-retrieved documentation to add or update, prioritized by impact. We write your document templates for you to fill in with info your users need, and give you updates on your AI system's health via Slack.
|
|
10
|
+
|
|
11
|
+
## What This SDK Does
|
|
12
|
+
|
|
13
|
+
This lightweight SDK (one dependency, 20-minute integration) sends your AI conversations to Teckel for analysis. You get:
|
|
14
|
+
|
|
15
|
+
- **Completeness Scoring** - How well each response answers the user's question (0-100%)
|
|
16
|
+
- **Accuracy Analysis** - Whether AI claims are supported by your source documents
|
|
17
|
+
- **Topic Intelligence** - Automatic clustering of queries to reveal documentation gaps
|
|
18
|
+
- **Actionable Feedback** - Specific recommendations on what knowledge your AI needs to better answer user questions
|
|
19
|
+
|
|
20
|
+
Works with any RAG system or AI conversational framework: LangChain, LlamaIndex, Vercel AI SDK, custom implementations using vector database retrieval, or direct OpenAI/Anthropic calls.
|
|
21
|
+
|
|
22
|
+
## Getting Started
|
|
23
|
+
|
|
24
|
+
1. **Sign up** at [app.teckel.ai](https://app.teckel.ai) with a 14 day free trial
|
|
25
|
+
2. **Generate an API key** from your dashboard (Admin Panel > API Keys)
|
|
26
|
+
3. **Install the SDK**: `npm install teckel-ai`
|
|
27
|
+
4. **Follow the integration guide** at [docs.teckel.ai/docs/getting-started](https://docs.teckel.ai/docs/getting-started)
|
|
28
|
+
|
|
29
|
+
## Documentation
|
|
30
|
+
|
|
31
|
+
- [Getting Started Guide](https://docs.teckel.ai/docs/getting-started) - Step-by-step integration
|
|
32
|
+
- [API & SDK Reference](https://docs.teckel.ai/docs/api-sdk-reference) - Complete field documentation and framework examples
|
|
33
|
+
- [Troubleshooting](https://docs.teckel.ai/docs/troubleshooting) - Common issues and solutions
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Node.js 18+ (or Bun, Deno, serverless runtimes)
|
|
38
|
+
- A Teckel AI account with API key
|
|
39
|
+
- An LLM-based application (RAG system, chatbot, AI agent)
|
|
40
|
+
|
|
41
|
+
## Support
|
|
42
|
+
|
|
43
|
+
- **Documentation**: [docs.teckel.ai](https://docs.teckel.ai)
|
|
44
|
+
- **Dashboard**: [app.teckel.ai](https://app.teckel.ai)
|
|
45
|
+
- **Email**: support@teckel.ai
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
Version 0.3.2
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation class for teckel-ai SDK v0.3.1
|
|
3
|
+
* Manages a single conversation with fire-and-forget semantics
|
|
4
|
+
*/
|
|
5
|
+
import type { TraceData, FeedbackData, ConversationOptions, TraceResult } from './types';
|
|
6
|
+
export declare class Conversation {
|
|
7
|
+
private readonly apiKey;
|
|
8
|
+
private readonly endpoint;
|
|
9
|
+
private readonly sessionRef;
|
|
10
|
+
private readonly userId?;
|
|
11
|
+
private readonly metadata?;
|
|
12
|
+
private readonly startedAt;
|
|
13
|
+
private readonly debug;
|
|
14
|
+
private readonly timeoutMs;
|
|
15
|
+
private turnCount;
|
|
16
|
+
private startPromise;
|
|
17
|
+
private sendQueue;
|
|
18
|
+
constructor(apiKey: string, endpoint: string, options: ConversationOptions, debug?: boolean, extras?: {
|
|
19
|
+
timeoutMs: number;
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Record a trace (single query-response interaction)
|
|
23
|
+
* Fire-and-forget by default - never blocks
|
|
24
|
+
* For serverless, call flush() before function termination
|
|
25
|
+
*/
|
|
26
|
+
trace(data: TraceData): TraceResult | void;
|
|
27
|
+
/**
|
|
28
|
+
* Synchronous trace: waits for HTTP send to complete.
|
|
29
|
+
* Throws on network/validation errors.
|
|
30
|
+
* Respects send queue to maintain trace ordering.
|
|
31
|
+
*/
|
|
32
|
+
traceSync(data: TraceData, opt?: {
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}): Promise<TraceResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Add user feedback signal
|
|
37
|
+
* Never throws - gracefully handles errors
|
|
38
|
+
*/
|
|
39
|
+
feedback(data: FeedbackData): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* End the conversation
|
|
42
|
+
* Flushes all pending traces before sending end signal
|
|
43
|
+
* Never throws - gracefully handles errors
|
|
44
|
+
*/
|
|
45
|
+
end(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Read-only properties
|
|
48
|
+
*/
|
|
49
|
+
get id(): string;
|
|
50
|
+
get turns(): number;
|
|
51
|
+
get started(): Date;
|
|
52
|
+
private fetchWithRetry;
|
|
53
|
+
private _startConversation;
|
|
54
|
+
private _sendTrace;
|
|
55
|
+
private _sendFeedback;
|
|
56
|
+
private _endConversation;
|
|
57
|
+
private enqueueSend;
|
|
58
|
+
/**
|
|
59
|
+
* Flush queued sends with a bounded timeout.
|
|
60
|
+
* Returns when the queue is empty or the timeout elapses (whichever comes first).
|
|
61
|
+
*/
|
|
62
|
+
flush(timeoutMs?: number): Promise<void>;
|
|
63
|
+
private mapOTelAliases;
|
|
64
|
+
}
|
|
@@ -0,0 +1,363 @@
|
|
|
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/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* teckel-ai v0.3.1
|
|
3
|
+
* Simple SDK for AI conversation tracking and RAG observability
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
export { TeckelTracer } from './tracer';
|
|
8
|
+
export { Conversation } from './conversation';
|
|
9
|
+
export type { TeckelConfig, ConversationOptions, TraceData, Document, TokenUsage, FeedbackData, FeedbackType, ValidationResult, TraceResult } from './types';
|
|
10
|
+
export { TeckelConfigSchema, ConversationOptionsSchema, TraceDataSchema, DocumentSchema, TokenUsageSchema, FeedbackDataSchema } from './schemas';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* teckel-ai v0.3.1
|
|
4
|
+
* Simple SDK for AI conversation tracking and RAG observability
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.FeedbackDataSchema = exports.TokenUsageSchema = exports.DocumentSchema = exports.TraceDataSchema = exports.ConversationOptionsSchema = exports.TeckelConfigSchema = exports.Conversation = exports.TeckelTracer = void 0;
|
|
10
|
+
// Main SDK exports
|
|
11
|
+
var tracer_1 = require("./tracer");
|
|
12
|
+
Object.defineProperty(exports, "TeckelTracer", { enumerable: true, get: function () { return tracer_1.TeckelTracer; } });
|
|
13
|
+
var conversation_1 = require("./conversation");
|
|
14
|
+
Object.defineProperty(exports, "Conversation", { enumerable: true, get: function () { return conversation_1.Conversation; } });
|
|
15
|
+
// Schema exports (for advanced use cases)
|
|
16
|
+
var schemas_1 = require("./schemas");
|
|
17
|
+
Object.defineProperty(exports, "TeckelConfigSchema", { enumerable: true, get: function () { return schemas_1.TeckelConfigSchema; } });
|
|
18
|
+
Object.defineProperty(exports, "ConversationOptionsSchema", { enumerable: true, get: function () { return schemas_1.ConversationOptionsSchema; } });
|
|
19
|
+
Object.defineProperty(exports, "TraceDataSchema", { enumerable: true, get: function () { return schemas_1.TraceDataSchema; } });
|
|
20
|
+
Object.defineProperty(exports, "DocumentSchema", { enumerable: true, get: function () { return schemas_1.DocumentSchema; } });
|
|
21
|
+
Object.defineProperty(exports, "TokenUsageSchema", { enumerable: true, get: function () { return schemas_1.TokenUsageSchema; } });
|
|
22
|
+
Object.defineProperty(exports, "FeedbackDataSchema", { enumerable: true, get: function () { return schemas_1.FeedbackDataSchema; } });
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod validation schemas for teckel-ai SDK v0.3.1
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* Document schema
|
|
7
|
+
*/
|
|
8
|
+
export declare const DocumentSchema: z.ZodObject<{
|
|
9
|
+
documentRef: z.ZodString;
|
|
10
|
+
documentName: z.ZodString;
|
|
11
|
+
documentText: z.ZodString;
|
|
12
|
+
documentLastUpdated: z.ZodOptional<z.ZodString>;
|
|
13
|
+
sourceUri: z.ZodOptional<z.ZodString>;
|
|
14
|
+
sourceType: z.ZodOptional<z.ZodString>;
|
|
15
|
+
similarity: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
rank: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
ownerEmail: z.ZodOptional<z.ZodString>;
|
|
18
|
+
documentType: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
documentRef: string;
|
|
21
|
+
documentName: string;
|
|
22
|
+
documentText: string;
|
|
23
|
+
documentLastUpdated?: string | undefined;
|
|
24
|
+
sourceUri?: string | undefined;
|
|
25
|
+
sourceType?: string | undefined;
|
|
26
|
+
similarity?: number | undefined;
|
|
27
|
+
rank?: number | undefined;
|
|
28
|
+
ownerEmail?: string | undefined;
|
|
29
|
+
documentType?: string | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
documentRef: string;
|
|
32
|
+
documentName: string;
|
|
33
|
+
documentText: string;
|
|
34
|
+
documentLastUpdated?: string | undefined;
|
|
35
|
+
sourceUri?: string | undefined;
|
|
36
|
+
sourceType?: string | undefined;
|
|
37
|
+
similarity?: number | undefined;
|
|
38
|
+
rank?: number | undefined;
|
|
39
|
+
ownerEmail?: string | undefined;
|
|
40
|
+
documentType?: string | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Token usage schema
|
|
44
|
+
*/
|
|
45
|
+
export declare const TokenUsageSchema: z.ZodObject<{
|
|
46
|
+
prompt: z.ZodNumber;
|
|
47
|
+
completion: z.ZodNumber;
|
|
48
|
+
total: z.ZodNumber;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
prompt: number;
|
|
51
|
+
completion: number;
|
|
52
|
+
total: number;
|
|
53
|
+
}, {
|
|
54
|
+
prompt: number;
|
|
55
|
+
completion: number;
|
|
56
|
+
total: number;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Trace data schema
|
|
60
|
+
*/
|
|
61
|
+
export declare const TraceDataSchema: z.ZodObject<{
|
|
62
|
+
query: z.ZodString;
|
|
63
|
+
response: z.ZodString;
|
|
64
|
+
model: z.ZodOptional<z.ZodString>;
|
|
65
|
+
responseTimeMs: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
documents: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
67
|
+
documentRef: z.ZodString;
|
|
68
|
+
documentName: z.ZodString;
|
|
69
|
+
documentText: z.ZodString;
|
|
70
|
+
documentLastUpdated: z.ZodOptional<z.ZodString>;
|
|
71
|
+
sourceUri: z.ZodOptional<z.ZodString>;
|
|
72
|
+
sourceType: z.ZodOptional<z.ZodString>;
|
|
73
|
+
similarity: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
rank: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
ownerEmail: z.ZodOptional<z.ZodString>;
|
|
76
|
+
documentType: z.ZodOptional<z.ZodString>;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
documentRef: string;
|
|
79
|
+
documentName: string;
|
|
80
|
+
documentText: string;
|
|
81
|
+
documentLastUpdated?: string | undefined;
|
|
82
|
+
sourceUri?: string | undefined;
|
|
83
|
+
sourceType?: string | undefined;
|
|
84
|
+
similarity?: number | undefined;
|
|
85
|
+
rank?: number | undefined;
|
|
86
|
+
ownerEmail?: string | undefined;
|
|
87
|
+
documentType?: string | undefined;
|
|
88
|
+
}, {
|
|
89
|
+
documentRef: string;
|
|
90
|
+
documentName: string;
|
|
91
|
+
documentText: string;
|
|
92
|
+
documentLastUpdated?: string | undefined;
|
|
93
|
+
sourceUri?: string | undefined;
|
|
94
|
+
sourceType?: string | undefined;
|
|
95
|
+
similarity?: number | undefined;
|
|
96
|
+
rank?: number | undefined;
|
|
97
|
+
ownerEmail?: string | undefined;
|
|
98
|
+
documentType?: string | undefined;
|
|
99
|
+
}>, "many">>;
|
|
100
|
+
tokens: z.ZodOptional<z.ZodObject<{
|
|
101
|
+
prompt: z.ZodNumber;
|
|
102
|
+
completion: z.ZodNumber;
|
|
103
|
+
total: z.ZodNumber;
|
|
104
|
+
}, "strip", z.ZodTypeAny, {
|
|
105
|
+
prompt: number;
|
|
106
|
+
completion: number;
|
|
107
|
+
total: number;
|
|
108
|
+
}, {
|
|
109
|
+
prompt: number;
|
|
110
|
+
completion: number;
|
|
111
|
+
total: number;
|
|
112
|
+
}>>;
|
|
113
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
114
|
+
traceRef: z.ZodOptional<z.ZodString>;
|
|
115
|
+
}, "strip", z.ZodTypeAny, {
|
|
116
|
+
query: string;
|
|
117
|
+
response: string;
|
|
118
|
+
model?: string | undefined;
|
|
119
|
+
responseTimeMs?: number | undefined;
|
|
120
|
+
documents?: {
|
|
121
|
+
documentRef: string;
|
|
122
|
+
documentName: string;
|
|
123
|
+
documentText: string;
|
|
124
|
+
documentLastUpdated?: string | undefined;
|
|
125
|
+
sourceUri?: string | undefined;
|
|
126
|
+
sourceType?: string | undefined;
|
|
127
|
+
similarity?: number | undefined;
|
|
128
|
+
rank?: number | undefined;
|
|
129
|
+
ownerEmail?: string | undefined;
|
|
130
|
+
documentType?: string | undefined;
|
|
131
|
+
}[] | undefined;
|
|
132
|
+
tokens?: {
|
|
133
|
+
prompt: number;
|
|
134
|
+
completion: number;
|
|
135
|
+
total: number;
|
|
136
|
+
} | undefined;
|
|
137
|
+
metadata?: Record<string, any> | undefined;
|
|
138
|
+
traceRef?: string | undefined;
|
|
139
|
+
}, {
|
|
140
|
+
query: string;
|
|
141
|
+
response: string;
|
|
142
|
+
model?: string | undefined;
|
|
143
|
+
responseTimeMs?: number | undefined;
|
|
144
|
+
documents?: {
|
|
145
|
+
documentRef: string;
|
|
146
|
+
documentName: string;
|
|
147
|
+
documentText: string;
|
|
148
|
+
documentLastUpdated?: string | undefined;
|
|
149
|
+
sourceUri?: string | undefined;
|
|
150
|
+
sourceType?: string | undefined;
|
|
151
|
+
similarity?: number | undefined;
|
|
152
|
+
rank?: number | undefined;
|
|
153
|
+
ownerEmail?: string | undefined;
|
|
154
|
+
documentType?: string | undefined;
|
|
155
|
+
}[] | undefined;
|
|
156
|
+
tokens?: {
|
|
157
|
+
prompt: number;
|
|
158
|
+
completion: number;
|
|
159
|
+
total: number;
|
|
160
|
+
} | undefined;
|
|
161
|
+
metadata?: Record<string, any> | undefined;
|
|
162
|
+
traceRef?: string | undefined;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Conversation options schema
|
|
166
|
+
*/
|
|
167
|
+
export declare const ConversationOptionsSchema: z.ZodObject<{
|
|
168
|
+
sessionRef: z.ZodString;
|
|
169
|
+
userId: z.ZodOptional<z.ZodString>;
|
|
170
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
171
|
+
}, "strip", z.ZodTypeAny, {
|
|
172
|
+
sessionRef: string;
|
|
173
|
+
metadata?: Record<string, any> | undefined;
|
|
174
|
+
userId?: string | undefined;
|
|
175
|
+
}, {
|
|
176
|
+
sessionRef: string;
|
|
177
|
+
metadata?: Record<string, any> | undefined;
|
|
178
|
+
userId?: string | undefined;
|
|
179
|
+
}>;
|
|
180
|
+
/**
|
|
181
|
+
* Feedback data schema
|
|
182
|
+
*/
|
|
183
|
+
export declare const FeedbackDataSchema: z.ZodObject<{
|
|
184
|
+
type: z.ZodEnum<["thumbs_up", "thumbs_down", "flag", "rating"]>;
|
|
185
|
+
value: z.ZodOptional<z.ZodString>;
|
|
186
|
+
comment: z.ZodOptional<z.ZodString>;
|
|
187
|
+
traceRef: z.ZodOptional<z.ZodString>;
|
|
188
|
+
}, "strip", z.ZodTypeAny, {
|
|
189
|
+
type: "thumbs_up" | "thumbs_down" | "flag" | "rating";
|
|
190
|
+
value?: string | undefined;
|
|
191
|
+
traceRef?: string | undefined;
|
|
192
|
+
comment?: string | undefined;
|
|
193
|
+
}, {
|
|
194
|
+
type: "thumbs_up" | "thumbs_down" | "flag" | "rating";
|
|
195
|
+
value?: string | undefined;
|
|
196
|
+
traceRef?: string | undefined;
|
|
197
|
+
comment?: string | undefined;
|
|
198
|
+
}>;
|
|
199
|
+
/**
|
|
200
|
+
* Config schema
|
|
201
|
+
*/
|
|
202
|
+
export declare const TeckelConfigSchema: z.ZodObject<{
|
|
203
|
+
apiKey: z.ZodString;
|
|
204
|
+
endpoint: z.ZodOptional<z.ZodString>;
|
|
205
|
+
debug: z.ZodOptional<z.ZodBoolean>;
|
|
206
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
207
|
+
}, "strip", z.ZodTypeAny, {
|
|
208
|
+
apiKey: string;
|
|
209
|
+
endpoint?: string | undefined;
|
|
210
|
+
debug?: boolean | undefined;
|
|
211
|
+
timeoutMs?: number | undefined;
|
|
212
|
+
}, {
|
|
213
|
+
apiKey: string;
|
|
214
|
+
endpoint?: string | undefined;
|
|
215
|
+
debug?: boolean | undefined;
|
|
216
|
+
timeoutMs?: number | undefined;
|
|
217
|
+
}>;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
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
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "teckel-ai",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Simple SDK for AI conversation tracking and RAG observability",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/**/*",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"llm",
|
|
18
|
+
"rag",
|
|
19
|
+
"monitoring",
|
|
20
|
+
"ai",
|
|
21
|
+
"audit",
|
|
22
|
+
"trace",
|
|
23
|
+
"observability",
|
|
24
|
+
"teckel"
|
|
25
|
+
],
|
|
26
|
+
"author": "Teckel AI",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"zod": "^3.23.8"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.0.0"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/spencine/AI-Audit-Tool.git",
|
|
37
|
+
"directory": "packages/tracer"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://teckel.ai",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/spencine/AI-Audit-Tool/issues"
|
|
42
|
+
}
|
|
43
|
+
}
|