@tenet-ai/sdk 0.1.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/dist/client.d.ts +145 -0
- package/dist/client.js +499 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/index.d.ts +32 -0
- package/dist/integrations/index.js +42 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/langchain.d.ts +151 -0
- package/dist/integrations/langchain.js +255 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/integrations/openai.d.ts +166 -0
- package/dist/integrations/openai.js +250 -0
- package/dist/integrations/openai.js.map +1 -0
- package/dist/integrations/vercel-ai.d.ts +185 -0
- package/dist/integrations/vercel-ai.js +297 -0
- package/dist/integrations/vercel-ai.js.map +1 -0
- package/dist/types.d.ts +258 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Node SDK integration for Tenet AI.
|
|
3
|
+
*
|
|
4
|
+
* Provides a wrapper around `openai.chat.completions.create()` that
|
|
5
|
+
* automatically records prompts, responses, model versions, and tool calls
|
|
6
|
+
* in the Tenet audit trail, with replay support.
|
|
7
|
+
*
|
|
8
|
+
* This module has **no hard dependency** on the `openai` package. It defines
|
|
9
|
+
* the relevant OpenAI types inline and works with any object that matches
|
|
10
|
+
* the expected shapes.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import OpenAI from 'openai';
|
|
15
|
+
* import { Tenet } from '@tenet-ai/sdk';
|
|
16
|
+
* import { TenetOpenAITracker } from '@tenet-ai/sdk/integrations/openai';
|
|
17
|
+
*
|
|
18
|
+
* const openai = new OpenAI();
|
|
19
|
+
* const tenet = new Tenet({ apiKey: 'tenet_xxx' });
|
|
20
|
+
* const tracker = new TenetOpenAITracker(tenet, {
|
|
21
|
+
* agentId: 'openai-chatbot',
|
|
22
|
+
* tags: ['production'],
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Tracked call -- automatically logs to Tenet
|
|
26
|
+
* const response = await tracker.chatCompletion(openai, {
|
|
27
|
+
* model: 'gpt-4o',
|
|
28
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Or wrap an existing client for automatic tracking
|
|
32
|
+
* const wrappedOpenAI = tracker.wrap(openai);
|
|
33
|
+
* const res = await wrappedOpenAI.chat.completions.create({
|
|
34
|
+
* model: 'gpt-4o',
|
|
35
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
import { Tenet } from "../client";
|
|
42
|
+
/** A chat message in OpenAI format. */
|
|
43
|
+
export interface ChatMessage {
|
|
44
|
+
role: "system" | "user" | "assistant" | "tool" | "function" | string;
|
|
45
|
+
content?: string | null;
|
|
46
|
+
name?: string;
|
|
47
|
+
tool_calls?: ToolCall[];
|
|
48
|
+
tool_call_id?: string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** A tool call returned in an assistant message. */
|
|
52
|
+
export interface ToolCall {
|
|
53
|
+
id: string;
|
|
54
|
+
type: "function";
|
|
55
|
+
function: {
|
|
56
|
+
name: string;
|
|
57
|
+
arguments: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Parameters for `chat.completions.create()`. */
|
|
61
|
+
export interface ChatCompletionCreateParams {
|
|
62
|
+
model: string;
|
|
63
|
+
messages: ChatMessage[];
|
|
64
|
+
temperature?: number;
|
|
65
|
+
max_tokens?: number;
|
|
66
|
+
tools?: unknown[];
|
|
67
|
+
tool_choice?: unknown;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
/** A single choice in a chat completion response. */
|
|
71
|
+
export interface ChatCompletionChoice {
|
|
72
|
+
index: number;
|
|
73
|
+
message: ChatMessage;
|
|
74
|
+
finish_reason: string | null;
|
|
75
|
+
}
|
|
76
|
+
/** The response from `chat.completions.create()`. */
|
|
77
|
+
export interface ChatCompletionResponse {
|
|
78
|
+
id: string;
|
|
79
|
+
object: string;
|
|
80
|
+
model: string;
|
|
81
|
+
choices: ChatCompletionChoice[];
|
|
82
|
+
usage?: {
|
|
83
|
+
prompt_tokens: number;
|
|
84
|
+
completion_tokens: number;
|
|
85
|
+
total_tokens: number;
|
|
86
|
+
};
|
|
87
|
+
[key: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Minimal interface for an OpenAI client instance.
|
|
91
|
+
* Matches the shape of `new OpenAI()` from the `openai` package.
|
|
92
|
+
*/
|
|
93
|
+
export interface OpenAIClientLike {
|
|
94
|
+
chat: {
|
|
95
|
+
completions: {
|
|
96
|
+
create(params: ChatCompletionCreateParams): Promise<ChatCompletionResponse>;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** Configuration options for {@link TenetOpenAITracker}. */
|
|
101
|
+
export interface TenetOpenAITrackerConfig {
|
|
102
|
+
/** Identifier for the agent. Defaults to `"openai-chat"`. */
|
|
103
|
+
agentId?: string;
|
|
104
|
+
/** Explicit session ID. A random UUID is generated per tracker if omitted. */
|
|
105
|
+
sessionId?: string;
|
|
106
|
+
/** Tags attached to every decision. */
|
|
107
|
+
tags?: string[];
|
|
108
|
+
/** Arbitrary metadata attached to every decision. */
|
|
109
|
+
metadata?: Record<string, unknown>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wrapper for the OpenAI Node SDK that records `chat.completions.create()`
|
|
113
|
+
* calls in the Tenet audit trail.
|
|
114
|
+
*
|
|
115
|
+
* Each call records the full intent -> context -> decision -> execution
|
|
116
|
+
* chain including the prompt messages, model version, chosen response,
|
|
117
|
+
* tool calls, and token usage. The recorded decision includes a replay
|
|
118
|
+
* prompt so it can be replayed later via `tenet.replay()`.
|
|
119
|
+
*/
|
|
120
|
+
export declare class TenetOpenAITracker {
|
|
121
|
+
private client;
|
|
122
|
+
private agentId;
|
|
123
|
+
private sessionId;
|
|
124
|
+
private tags;
|
|
125
|
+
private metadata;
|
|
126
|
+
/**
|
|
127
|
+
* @param client - An initialised {@link Tenet} client instance.
|
|
128
|
+
* @param config - Optional configuration overrides.
|
|
129
|
+
*/
|
|
130
|
+
constructor(client: Tenet, config?: TenetOpenAITrackerConfig);
|
|
131
|
+
/**
|
|
132
|
+
* Execute a `chat.completions.create()` call and record it in Tenet.
|
|
133
|
+
*
|
|
134
|
+
* @param openai - An OpenAI client instance (or anything with the same shape).
|
|
135
|
+
* @param params - The parameters to pass to `chat.completions.create()`.
|
|
136
|
+
* @returns The original OpenAI `ChatCompletionResponse`.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const response = await tracker.chatCompletion(openai, {
|
|
141
|
+
* model: 'gpt-4o',
|
|
142
|
+
* messages: [{ role: 'user', content: 'Summarise this doc.' }],
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
chatCompletion(openai: OpenAIClientLike, params: ChatCompletionCreateParams): Promise<ChatCompletionResponse>;
|
|
147
|
+
/**
|
|
148
|
+
* Return a proxied OpenAI client whose `chat.completions.create()` calls
|
|
149
|
+
* are automatically tracked. All other methods pass through untouched.
|
|
150
|
+
*
|
|
151
|
+
* @param openai - The original OpenAI client instance.
|
|
152
|
+
* @returns A proxied client with transparent tracking.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* const tracked = tracker.wrap(openai);
|
|
157
|
+
* // This call is automatically recorded in Tenet:
|
|
158
|
+
* const res = await tracked.chat.completions.create({ ... });
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
wrap<T extends OpenAIClientLike>(openai: T): T;
|
|
162
|
+
/**
|
|
163
|
+
* Record a single chat completion call in Tenet.
|
|
164
|
+
*/
|
|
165
|
+
private record;
|
|
166
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Node SDK integration for Tenet AI.
|
|
4
|
+
*
|
|
5
|
+
* Provides a wrapper around `openai.chat.completions.create()` that
|
|
6
|
+
* automatically records prompts, responses, model versions, and tool calls
|
|
7
|
+
* in the Tenet audit trail, with replay support.
|
|
8
|
+
*
|
|
9
|
+
* This module has **no hard dependency** on the `openai` package. It defines
|
|
10
|
+
* the relevant OpenAI types inline and works with any object that matches
|
|
11
|
+
* the expected shapes.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import OpenAI from 'openai';
|
|
16
|
+
* import { Tenet } from '@tenet-ai/sdk';
|
|
17
|
+
* import { TenetOpenAITracker } from '@tenet-ai/sdk/integrations/openai';
|
|
18
|
+
*
|
|
19
|
+
* const openai = new OpenAI();
|
|
20
|
+
* const tenet = new Tenet({ apiKey: 'tenet_xxx' });
|
|
21
|
+
* const tracker = new TenetOpenAITracker(tenet, {
|
|
22
|
+
* agentId: 'openai-chatbot',
|
|
23
|
+
* tags: ['production'],
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Tracked call -- automatically logs to Tenet
|
|
27
|
+
* const response = await tracker.chatCompletion(openai, {
|
|
28
|
+
* model: 'gpt-4o',
|
|
29
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Or wrap an existing client for automatic tracking
|
|
33
|
+
* const wrappedOpenAI = tracker.wrap(openai);
|
|
34
|
+
* const res = await wrappedOpenAI.chat.completions.create({
|
|
35
|
+
* model: 'gpt-4o',
|
|
36
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @module
|
|
41
|
+
*/
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.TenetOpenAITracker = void 0;
|
|
44
|
+
const crypto_1 = require("crypto");
|
|
45
|
+
const types_1 = require("../types");
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Tracker
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Wrapper for the OpenAI Node SDK that records `chat.completions.create()`
|
|
51
|
+
* calls in the Tenet audit trail.
|
|
52
|
+
*
|
|
53
|
+
* Each call records the full intent -> context -> decision -> execution
|
|
54
|
+
* chain including the prompt messages, model version, chosen response,
|
|
55
|
+
* tool calls, and token usage. The recorded decision includes a replay
|
|
56
|
+
* prompt so it can be replayed later via `tenet.replay()`.
|
|
57
|
+
*/
|
|
58
|
+
class TenetOpenAITracker {
|
|
59
|
+
client;
|
|
60
|
+
agentId;
|
|
61
|
+
sessionId;
|
|
62
|
+
tags;
|
|
63
|
+
metadata;
|
|
64
|
+
/**
|
|
65
|
+
* @param client - An initialised {@link Tenet} client instance.
|
|
66
|
+
* @param config - Optional configuration overrides.
|
|
67
|
+
*/
|
|
68
|
+
constructor(client, config = {}) {
|
|
69
|
+
this.client = client;
|
|
70
|
+
this.agentId = config.agentId ?? "openai-chat";
|
|
71
|
+
this.sessionId = config.sessionId ?? (0, crypto_1.randomUUID)();
|
|
72
|
+
this.tags = config.tags ?? [];
|
|
73
|
+
this.metadata = config.metadata ?? {};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Execute a `chat.completions.create()` call and record it in Tenet.
|
|
77
|
+
*
|
|
78
|
+
* @param openai - An OpenAI client instance (or anything with the same shape).
|
|
79
|
+
* @param params - The parameters to pass to `chat.completions.create()`.
|
|
80
|
+
* @returns The original OpenAI `ChatCompletionResponse`.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const response = await tracker.chatCompletion(openai, {
|
|
85
|
+
* model: 'gpt-4o',
|
|
86
|
+
* messages: [{ role: 'user', content: 'Summarise this doc.' }],
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
async chatCompletion(openai, params) {
|
|
91
|
+
let response;
|
|
92
|
+
let error;
|
|
93
|
+
try {
|
|
94
|
+
response = await openai.chat.completions.create(params);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
98
|
+
}
|
|
99
|
+
await this.record(params, response, error);
|
|
100
|
+
if (error) {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
return response;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Return a proxied OpenAI client whose `chat.completions.create()` calls
|
|
107
|
+
* are automatically tracked. All other methods pass through untouched.
|
|
108
|
+
*
|
|
109
|
+
* @param openai - The original OpenAI client instance.
|
|
110
|
+
* @returns A proxied client with transparent tracking.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const tracked = tracker.wrap(openai);
|
|
115
|
+
* // This call is automatically recorded in Tenet:
|
|
116
|
+
* const res = await tracked.chat.completions.create({ ... });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
wrap(openai) {
|
|
120
|
+
const tracker = this;
|
|
121
|
+
const completionsProxy = new Proxy(openai.chat.completions, {
|
|
122
|
+
get(target, prop, receiver) {
|
|
123
|
+
if (prop === "create") {
|
|
124
|
+
return async (params) => {
|
|
125
|
+
return tracker.chatCompletion(openai, params);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return Reflect.get(target, prop, receiver);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
const chatProxy = new Proxy(openai.chat, {
|
|
132
|
+
get(target, prop, receiver) {
|
|
133
|
+
if (prop === "completions") {
|
|
134
|
+
return completionsProxy;
|
|
135
|
+
}
|
|
136
|
+
return Reflect.get(target, prop, receiver);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
return new Proxy(openai, {
|
|
140
|
+
get(target, prop, receiver) {
|
|
141
|
+
if (prop === "chat") {
|
|
142
|
+
return chatProxy;
|
|
143
|
+
}
|
|
144
|
+
return Reflect.get(target, prop, receiver);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// ----- Internal -----
|
|
149
|
+
/**
|
|
150
|
+
* Record a single chat completion call in Tenet.
|
|
151
|
+
*/
|
|
152
|
+
async record(params, response, error) {
|
|
153
|
+
const success = !error && !!response;
|
|
154
|
+
// Build a concise description of the prompt
|
|
155
|
+
const lastUserMessage = [...params.messages]
|
|
156
|
+
.reverse()
|
|
157
|
+
.find((m) => m.role === "user");
|
|
158
|
+
const goal = lastUserMessage?.content
|
|
159
|
+
? String(lastUserMessage.content).slice(0, 200)
|
|
160
|
+
: `chat:${params.model}`;
|
|
161
|
+
// Extract the assistant reply and tool calls
|
|
162
|
+
const choice = response?.choices?.[0];
|
|
163
|
+
const assistantContent = choice?.message?.content ?? "";
|
|
164
|
+
const toolCalls = choice?.message?.tool_calls ?? [];
|
|
165
|
+
// Build options
|
|
166
|
+
const options = [];
|
|
167
|
+
if (toolCalls.length > 0) {
|
|
168
|
+
for (let i = 0; i < toolCalls.length; i++) {
|
|
169
|
+
options.push({
|
|
170
|
+
action: toolCalls[i].function.name,
|
|
171
|
+
score: 1.0 / (i + 1),
|
|
172
|
+
reason: toolCalls[i].function.arguments.slice(0, 100),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
options.push({
|
|
178
|
+
action: "generate_response",
|
|
179
|
+
score: success ? 1.0 : 0.0,
|
|
180
|
+
reason: success ? "Direct text response" : `error: ${error?.message}`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const chosenAction = toolCalls.length > 0
|
|
184
|
+
? toolCalls[0].function.name
|
|
185
|
+
: "generate_response";
|
|
186
|
+
// Build a replay prompt from the messages
|
|
187
|
+
const replayPrompt = params.messages
|
|
188
|
+
.map((m) => `${m.role}: ${m.content ?? ""}`)
|
|
189
|
+
.join("\n")
|
|
190
|
+
.slice(0, 4000);
|
|
191
|
+
try {
|
|
192
|
+
// 1. Intent
|
|
193
|
+
const intent = await this.client.createIntent({
|
|
194
|
+
goal,
|
|
195
|
+
agentId: this.agentId,
|
|
196
|
+
sessionId: this.sessionId,
|
|
197
|
+
origin: types_1.OriginType.AGENT,
|
|
198
|
+
});
|
|
199
|
+
// 2. Context
|
|
200
|
+
await intent.snapshotContext({
|
|
201
|
+
messages: params.messages,
|
|
202
|
+
model: params.model,
|
|
203
|
+
temperature: params.temperature,
|
|
204
|
+
max_tokens: params.max_tokens,
|
|
205
|
+
tools: params.tools ?? [],
|
|
206
|
+
});
|
|
207
|
+
// 3. Decision
|
|
208
|
+
await intent.decide({
|
|
209
|
+
options,
|
|
210
|
+
chosenAction,
|
|
211
|
+
confidence: success ? 0.95 : 0.0,
|
|
212
|
+
modelVersion: response?.model ?? params.model,
|
|
213
|
+
reasoning: success
|
|
214
|
+
? `Model responded with ${choice?.finish_reason ?? "unknown"} finish reason`
|
|
215
|
+
: `Error: ${error?.message}`,
|
|
216
|
+
tags: this.tags,
|
|
217
|
+
metadata: {
|
|
218
|
+
...this.metadata,
|
|
219
|
+
usage: response?.usage ?? null,
|
|
220
|
+
finish_reason: choice?.finish_reason ?? null,
|
|
221
|
+
},
|
|
222
|
+
replayPrompt,
|
|
223
|
+
replayConfig: {
|
|
224
|
+
model: params.model,
|
|
225
|
+
temperature: params.temperature,
|
|
226
|
+
maxTokens: params.max_tokens,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
// 4. Execution
|
|
230
|
+
await intent.execute({
|
|
231
|
+
action: chosenAction,
|
|
232
|
+
target: {
|
|
233
|
+
response: assistantContent.slice(0, 2000),
|
|
234
|
+
tool_calls: toolCalls.map((tc) => ({
|
|
235
|
+
name: tc.function.name,
|
|
236
|
+
arguments: tc.function.arguments,
|
|
237
|
+
})),
|
|
238
|
+
},
|
|
239
|
+
result: success ? types_1.ResultType.SUCCESS : types_1.ResultType.FAILURE,
|
|
240
|
+
sideEffects: toolCalls.map((tc) => `tool:${tc.function.name}`),
|
|
241
|
+
actor: types_1.ActorType.AGENT,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Swallow tracking errors so the caller is not impacted.
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
exports.TenetOpenAITracker = TenetOpenAITracker;
|
|
250
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/integrations/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel AI SDK integration for Tenet AI.
|
|
3
|
+
*
|
|
4
|
+
* Provides wrappers for the Vercel AI SDK's `generateText` and `streamText`
|
|
5
|
+
* functions that automatically record prompts, responses, tool calls, and
|
|
6
|
+
* model metadata in the Tenet audit trail.
|
|
7
|
+
*
|
|
8
|
+
* This module has **no hard dependency** on the `ai` (Vercel AI SDK) package.
|
|
9
|
+
* All relevant types are defined inline and the wrappers accept generic
|
|
10
|
+
* function references.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { generateText, streamText } from 'ai';
|
|
15
|
+
* import { openai } from '@ai-sdk/openai';
|
|
16
|
+
* import { Tenet } from '@tenet-ai/sdk';
|
|
17
|
+
* import { TenetVercelAITracker } from '@tenet-ai/sdk/integrations/vercel-ai';
|
|
18
|
+
*
|
|
19
|
+
* const tenet = new Tenet({ apiKey: 'tenet_xxx' });
|
|
20
|
+
* const tracker = new TenetVercelAITracker(tenet, {
|
|
21
|
+
* agentId: 'vercel-ai-agent',
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Wrap generateText for automatic tracking
|
|
25
|
+
* const trackedGenerate = tracker.wrapGenerateText(generateText);
|
|
26
|
+
* const result = await trackedGenerate({
|
|
27
|
+
* model: openai('gpt-4o'),
|
|
28
|
+
* prompt: 'What is the meaning of life?',
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Wrap streamText for automatic tracking
|
|
32
|
+
* const trackedStream = tracker.wrapStreamText(streamText);
|
|
33
|
+
* const stream = await trackedStream({
|
|
34
|
+
* model: openai('gpt-4o'),
|
|
35
|
+
* prompt: 'Tell me a story.',
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
import { Tenet } from "../client";
|
|
42
|
+
/** A tool call result shape from the Vercel AI SDK. */
|
|
43
|
+
export interface VercelToolCall {
|
|
44
|
+
toolCallId: string;
|
|
45
|
+
toolName: string;
|
|
46
|
+
args: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
/** A tool result shape from the Vercel AI SDK. */
|
|
49
|
+
export interface VercelToolResult {
|
|
50
|
+
toolCallId: string;
|
|
51
|
+
toolName: string;
|
|
52
|
+
args: Record<string, unknown>;
|
|
53
|
+
result: unknown;
|
|
54
|
+
}
|
|
55
|
+
/** A message in Vercel AI SDK format. */
|
|
56
|
+
export interface VercelMessage {
|
|
57
|
+
role: "system" | "user" | "assistant" | "tool" | string;
|
|
58
|
+
content: string;
|
|
59
|
+
[key: string]: unknown;
|
|
60
|
+
}
|
|
61
|
+
/** Token usage information. */
|
|
62
|
+
export interface VercelTokenUsage {
|
|
63
|
+
promptTokens: number;
|
|
64
|
+
completionTokens: number;
|
|
65
|
+
totalTokens: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parameters for `generateText` / `streamText`.
|
|
69
|
+
* This is a minimal subset -- the real type has many more fields.
|
|
70
|
+
*/
|
|
71
|
+
export interface VercelGenerateParams {
|
|
72
|
+
model: unknown;
|
|
73
|
+
prompt?: string;
|
|
74
|
+
messages?: VercelMessage[];
|
|
75
|
+
system?: string;
|
|
76
|
+
tools?: Record<string, unknown>;
|
|
77
|
+
maxTokens?: number;
|
|
78
|
+
temperature?: number;
|
|
79
|
+
[key: string]: unknown;
|
|
80
|
+
}
|
|
81
|
+
/** The result returned by `generateText`. */
|
|
82
|
+
export interface VercelGenerateTextResult {
|
|
83
|
+
text: string;
|
|
84
|
+
toolCalls?: VercelToolCall[];
|
|
85
|
+
toolResults?: VercelToolResult[];
|
|
86
|
+
finishReason?: string;
|
|
87
|
+
usage?: VercelTokenUsage;
|
|
88
|
+
[key: string]: unknown;
|
|
89
|
+
}
|
|
90
|
+
/** The result returned by `streamText` (before consuming the stream). */
|
|
91
|
+
export interface VercelStreamTextResult {
|
|
92
|
+
textStream: AsyncIterable<string>;
|
|
93
|
+
fullStream: AsyncIterable<unknown>;
|
|
94
|
+
text: Promise<string>;
|
|
95
|
+
toolCalls?: Promise<VercelToolCall[]>;
|
|
96
|
+
toolResults?: Promise<VercelToolResult[]>;
|
|
97
|
+
finishReason?: Promise<string>;
|
|
98
|
+
usage?: Promise<VercelTokenUsage>;
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
/** Signature of the `generateText` function from `ai`. */
|
|
102
|
+
export type GenerateTextFn = (params: VercelGenerateParams) => Promise<VercelGenerateTextResult>;
|
|
103
|
+
/** Signature of the `streamText` function from `ai`. */
|
|
104
|
+
export type StreamTextFn = (params: VercelGenerateParams) => Promise<VercelStreamTextResult>;
|
|
105
|
+
/** Configuration options for {@link TenetVercelAITracker}. */
|
|
106
|
+
export interface TenetVercelAITrackerConfig {
|
|
107
|
+
/** Identifier for the agent. Defaults to `"vercel-ai-agent"`. */
|
|
108
|
+
agentId?: string;
|
|
109
|
+
/** Explicit session ID. A random UUID is generated if omitted. */
|
|
110
|
+
sessionId?: string;
|
|
111
|
+
/** Tags attached to every decision. */
|
|
112
|
+
tags?: string[];
|
|
113
|
+
/** Arbitrary metadata attached to every decision. */
|
|
114
|
+
metadata?: Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Wrapper for the Vercel AI SDK that records `generateText` and `streamText`
|
|
118
|
+
* calls in the Tenet audit trail.
|
|
119
|
+
*
|
|
120
|
+
* Each call records the full intent -> context -> decision -> execution
|
|
121
|
+
* chain including the prompt, model, tool calls, and token usage.
|
|
122
|
+
*/
|
|
123
|
+
export declare class TenetVercelAITracker {
|
|
124
|
+
private client;
|
|
125
|
+
private agentId;
|
|
126
|
+
private sessionId;
|
|
127
|
+
private tags;
|
|
128
|
+
private metadata;
|
|
129
|
+
/**
|
|
130
|
+
* @param client - An initialised {@link Tenet} client instance.
|
|
131
|
+
* @param config - Optional configuration overrides.
|
|
132
|
+
*/
|
|
133
|
+
constructor(client: Tenet, config?: TenetVercelAITrackerConfig);
|
|
134
|
+
/**
|
|
135
|
+
* Wrap the Vercel AI SDK `generateText` function with automatic Tenet
|
|
136
|
+
* tracking. Returns a new function with the same signature.
|
|
137
|
+
*
|
|
138
|
+
* @param generateText - The `generateText` function from the `ai` package.
|
|
139
|
+
* @returns A wrapped function that records calls in Tenet.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { generateText } from 'ai';
|
|
144
|
+
* const trackedGenerate = tracker.wrapGenerateText(generateText);
|
|
145
|
+
* const result = await trackedGenerate({ model, prompt: 'Hello' });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
wrapGenerateText(generateText: GenerateTextFn): GenerateTextFn;
|
|
149
|
+
/**
|
|
150
|
+
* Wrap the Vercel AI SDK `streamText` function with automatic Tenet
|
|
151
|
+
* tracking. The tracking data is recorded after the stream completes
|
|
152
|
+
* (resolves its promises).
|
|
153
|
+
*
|
|
154
|
+
* @param streamText - The `streamText` function from the `ai` package.
|
|
155
|
+
* @returns A wrapped function that records calls in Tenet.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* import { streamText } from 'ai';
|
|
160
|
+
* const trackedStream = tracker.wrapStreamText(streamText);
|
|
161
|
+
* const result = await trackedStream({ model, prompt: 'Hello' });
|
|
162
|
+
* for await (const chunk of result.textStream) {
|
|
163
|
+
* process.stdout.write(chunk);
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
wrapStreamText(streamText: StreamTextFn): StreamTextFn;
|
|
168
|
+
/**
|
|
169
|
+
* Manually record a `generateText` call. Useful when you want to call
|
|
170
|
+
* `generateText` yourself and record after the fact.
|
|
171
|
+
*
|
|
172
|
+
* @param params - The parameters that were passed to `generateText`.
|
|
173
|
+
* @param result - The result, if the call succeeded.
|
|
174
|
+
* @param error - The error, if the call failed.
|
|
175
|
+
*/
|
|
176
|
+
recordGenerateText(params: VercelGenerateParams, result?: VercelGenerateTextResult, error?: Error): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Record a streaming result after its promises resolve.
|
|
179
|
+
*/
|
|
180
|
+
private recordStreamResult;
|
|
181
|
+
/**
|
|
182
|
+
* Core recording logic shared by generate and stream paths.
|
|
183
|
+
*/
|
|
184
|
+
private record;
|
|
185
|
+
}
|