@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.
@@ -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
+ }