@pauly4010/evalai-sdk 1.3.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/CHANGELOG.md +289 -0
- package/LICENSE +21 -0
- package/README.md +565 -0
- package/dist/assertions.d.ts +189 -0
- package/dist/assertions.js +596 -0
- package/dist/batch.d.ts +68 -0
- package/dist/batch.js +178 -0
- package/dist/cache.d.ts +65 -0
- package/dist/cache.js +135 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +181 -0
- package/dist/client.d.ts +358 -0
- package/dist/client.js +802 -0
- package/dist/context.d.ts +134 -0
- package/dist/context.js +215 -0
- package/dist/errors.d.ts +80 -0
- package/dist/errors.js +285 -0
- package/dist/export.d.ts +195 -0
- package/dist/export.js +334 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +111 -0
- package/dist/integrations/anthropic.d.ts +72 -0
- package/dist/integrations/anthropic.js +159 -0
- package/dist/integrations/openai.d.ts +69 -0
- package/dist/integrations/openai.js +156 -0
- package/dist/local.d.ts +39 -0
- package/dist/local.js +146 -0
- package/dist/logger.d.ts +128 -0
- package/dist/logger.js +227 -0
- package/dist/pagination.d.ts +74 -0
- package/dist/pagination.js +135 -0
- package/dist/snapshot.d.ts +176 -0
- package/dist/snapshot.js +322 -0
- package/dist/streaming.d.ts +173 -0
- package/dist/streaming.js +268 -0
- package/dist/testing.d.ts +204 -0
- package/dist/testing.js +252 -0
- package/dist/types.d.ts +715 -0
- package/dist/types.js +54 -0
- package/dist/workflows.d.ts +378 -0
- package/dist/workflows.js +628 -0
- package/package.json +102 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic Integration
|
|
3
|
+
* Tier 1.2: Framework Auto-Instrumentation - Anthropic wrapper
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { traceAnthropic } from '@ai-eval-platform/sdk/integrations/anthropic';
|
|
8
|
+
* import Anthropic from '@anthropic-ai/sdk';
|
|
9
|
+
*
|
|
10
|
+
* const anthropic = new Anthropic({ apiKey: '...' });
|
|
11
|
+
* const tracedAnthropic = traceAnthropic(anthropic, client);
|
|
12
|
+
*
|
|
13
|
+
* // All calls are automatically traced
|
|
14
|
+
* const message = await tracedAnthropic.messages.create({
|
|
15
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
16
|
+
* max_tokens: 1024,
|
|
17
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import type { AIEvalClient } from '../client';
|
|
22
|
+
export interface AnthropicTraceOptions {
|
|
23
|
+
/** Whether to capture input (default: true) */
|
|
24
|
+
captureInput?: boolean;
|
|
25
|
+
/** Whether to capture output (default: true) */
|
|
26
|
+
captureOutput?: boolean;
|
|
27
|
+
/** Whether to capture metadata (default: true) */
|
|
28
|
+
captureMetadata?: boolean;
|
|
29
|
+
/** Organization ID for traces */
|
|
30
|
+
organizationId?: number;
|
|
31
|
+
/** Custom trace name prefix */
|
|
32
|
+
tracePrefix?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Wrap Anthropic client with automatic tracing
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import Anthropic from '@anthropic-ai/sdk';
|
|
40
|
+
* import { traceAnthropic } from '@ai-eval-platform/sdk/integrations/anthropic';
|
|
41
|
+
*
|
|
42
|
+
* const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
43
|
+
* const tracedAnthropic = traceAnthropic(anthropic, evalClient);
|
|
44
|
+
*
|
|
45
|
+
* // Automatically traced
|
|
46
|
+
* const message = await tracedAnthropic.messages.create({
|
|
47
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
48
|
+
* max_tokens: 1024,
|
|
49
|
+
* messages: [{ role: 'user', content: 'Hello, Claude!' }]
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function traceAnthropic(anthropic: any, evalClient: AIEvalClient, options?: AnthropicTraceOptions): any;
|
|
54
|
+
/**
|
|
55
|
+
* Manual trace wrapper for Anthropic calls
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const message = await traceAnthropicCall(
|
|
60
|
+
* evalClient,
|
|
61
|
+
* 'claude-completion',
|
|
62
|
+
* async () => {
|
|
63
|
+
* return await anthropic.messages.create({
|
|
64
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
65
|
+
* max_tokens: 1024,
|
|
66
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
67
|
+
* });
|
|
68
|
+
* }
|
|
69
|
+
* );
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function traceAnthropicCall<T>(evalClient: AIEvalClient, name: string, fn: () => Promise<T>, options?: AnthropicTraceOptions): Promise<T>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic Integration
|
|
4
|
+
* Tier 1.2: Framework Auto-Instrumentation - Anthropic wrapper
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { traceAnthropic } from '@ai-eval-platform/sdk/integrations/anthropic';
|
|
9
|
+
* import Anthropic from '@anthropic-ai/sdk';
|
|
10
|
+
*
|
|
11
|
+
* const anthropic = new Anthropic({ apiKey: '...' });
|
|
12
|
+
* const tracedAnthropic = traceAnthropic(anthropic, client);
|
|
13
|
+
*
|
|
14
|
+
* // All calls are automatically traced
|
|
15
|
+
* const message = await tracedAnthropic.messages.create({
|
|
16
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
17
|
+
* max_tokens: 1024,
|
|
18
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.traceAnthropic = traceAnthropic;
|
|
24
|
+
exports.traceAnthropicCall = traceAnthropicCall;
|
|
25
|
+
const context_1 = require("../context");
|
|
26
|
+
/**
|
|
27
|
+
* Wrap Anthropic client with automatic tracing
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import Anthropic from '@anthropic-ai/sdk';
|
|
32
|
+
* import { traceAnthropic } from '@ai-eval-platform/sdk/integrations/anthropic';
|
|
33
|
+
*
|
|
34
|
+
* const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
35
|
+
* const tracedAnthropic = traceAnthropic(anthropic, evalClient);
|
|
36
|
+
*
|
|
37
|
+
* // Automatically traced
|
|
38
|
+
* const message = await tracedAnthropic.messages.create({
|
|
39
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
40
|
+
* max_tokens: 1024,
|
|
41
|
+
* messages: [{ role: 'user', content: 'Hello, Claude!' }]
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
function traceAnthropic(anthropic, evalClient, options = {}) {
|
|
46
|
+
const { captureInput = true, captureOutput = true, captureMetadata = true, organizationId, tracePrefix = 'anthropic' } = options;
|
|
47
|
+
// Create proxy for messages.create
|
|
48
|
+
const originalCreate = anthropic.messages.create.bind(anthropic.messages);
|
|
49
|
+
anthropic.messages.create = async (params, requestOptions) => {
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
const traceId = `${tracePrefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
52
|
+
try {
|
|
53
|
+
// Call original method
|
|
54
|
+
const message = await originalCreate(params, requestOptions);
|
|
55
|
+
const durationMs = Date.now() - startTime;
|
|
56
|
+
// Create trace with success status and complete metadata
|
|
57
|
+
const traceMetadata = (0, context_1.mergeWithContext)({
|
|
58
|
+
model: params.model,
|
|
59
|
+
temperature: params.temperature,
|
|
60
|
+
max_tokens: params.max_tokens,
|
|
61
|
+
...(captureInput ? { input: params.messages } : {}),
|
|
62
|
+
...(captureOutput ? { output: message.content } : {}),
|
|
63
|
+
...(captureMetadata ? {
|
|
64
|
+
usage: message.usage,
|
|
65
|
+
stop_reason: message.stop_reason
|
|
66
|
+
} : {})
|
|
67
|
+
});
|
|
68
|
+
await evalClient.traces.create({
|
|
69
|
+
name: `Anthropic: ${params.model}`,
|
|
70
|
+
traceId,
|
|
71
|
+
organizationId: organizationId || evalClient.getOrganizationId(),
|
|
72
|
+
status: 'success',
|
|
73
|
+
durationMs,
|
|
74
|
+
metadata: traceMetadata
|
|
75
|
+
});
|
|
76
|
+
return message;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const durationMs = Date.now() - startTime;
|
|
80
|
+
// Create trace with error status
|
|
81
|
+
const errorMetadata = (0, context_1.mergeWithContext)({
|
|
82
|
+
model: params.model,
|
|
83
|
+
temperature: params.temperature,
|
|
84
|
+
max_tokens: params.max_tokens,
|
|
85
|
+
...(captureInput ? { input: params.messages } : {}),
|
|
86
|
+
...(captureMetadata ? { params } : {}),
|
|
87
|
+
error: error instanceof Error ? error.message : String(error)
|
|
88
|
+
});
|
|
89
|
+
await evalClient.traces.create({
|
|
90
|
+
name: `Anthropic: ${params.model}`,
|
|
91
|
+
traceId,
|
|
92
|
+
organizationId: organizationId || evalClient.getOrganizationId(),
|
|
93
|
+
status: 'error',
|
|
94
|
+
durationMs,
|
|
95
|
+
metadata: errorMetadata
|
|
96
|
+
}).catch(() => {
|
|
97
|
+
// Ignore errors in trace creation to avoid masking the original error
|
|
98
|
+
});
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return anthropic;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Manual trace wrapper for Anthropic calls
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const message = await traceAnthropicCall(
|
|
110
|
+
* evalClient,
|
|
111
|
+
* 'claude-completion',
|
|
112
|
+
* async () => {
|
|
113
|
+
* return await anthropic.messages.create({
|
|
114
|
+
* model: 'claude-3-5-sonnet-20241022',
|
|
115
|
+
* max_tokens: 1024,
|
|
116
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
117
|
+
* });
|
|
118
|
+
* }
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
async function traceAnthropicCall(evalClient, name, fn, options = {}) {
|
|
123
|
+
const startTime = Date.now();
|
|
124
|
+
const traceId = `anthropic-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
125
|
+
try {
|
|
126
|
+
await evalClient.traces.create({
|
|
127
|
+
name,
|
|
128
|
+
traceId,
|
|
129
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
130
|
+
status: 'pending',
|
|
131
|
+
metadata: (0, context_1.mergeWithContext)({})
|
|
132
|
+
});
|
|
133
|
+
const result = await fn();
|
|
134
|
+
const durationMs = Date.now() - startTime;
|
|
135
|
+
await evalClient.traces.create({
|
|
136
|
+
name,
|
|
137
|
+
traceId,
|
|
138
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
139
|
+
status: 'success',
|
|
140
|
+
durationMs,
|
|
141
|
+
metadata: (0, context_1.mergeWithContext)({})
|
|
142
|
+
});
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
const durationMs = Date.now() - startTime;
|
|
147
|
+
await evalClient.traces.create({
|
|
148
|
+
name,
|
|
149
|
+
traceId,
|
|
150
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
151
|
+
status: 'error',
|
|
152
|
+
durationMs,
|
|
153
|
+
metadata: (0, context_1.mergeWithContext)({
|
|
154
|
+
error: error instanceof Error ? error.message : String(error)
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Integration
|
|
3
|
+
* Tier 1.2: Framework Auto-Instrumentation - OpenAI wrapper
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { traceOpenAI } from '@ai-eval-platform/sdk/integrations/openai';
|
|
8
|
+
* import OpenAI from 'openai';
|
|
9
|
+
*
|
|
10
|
+
* const openai = new OpenAI({ apiKey: '...' });
|
|
11
|
+
* const tracedOpenAI = traceOpenAI(openai, client);
|
|
12
|
+
*
|
|
13
|
+
* // All calls are automatically traced
|
|
14
|
+
* const response = await tracedOpenAI.chat.completions.create({
|
|
15
|
+
* model: 'gpt-4',
|
|
16
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import type { AIEvalClient } from '../client';
|
|
21
|
+
export interface OpenAITraceOptions {
|
|
22
|
+
/** Whether to capture input (default: true) */
|
|
23
|
+
captureInput?: boolean;
|
|
24
|
+
/** Whether to capture output (default: true) */
|
|
25
|
+
captureOutput?: boolean;
|
|
26
|
+
/** Whether to capture metadata (default: true) */
|
|
27
|
+
captureMetadata?: boolean;
|
|
28
|
+
/** Organization ID for traces */
|
|
29
|
+
organizationId?: number;
|
|
30
|
+
/** Custom trace name prefix */
|
|
31
|
+
tracePrefix?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Wrap OpenAI client with automatic tracing
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import OpenAI from 'openai';
|
|
39
|
+
* import { traceOpenAI } from '@ai-eval-platform/sdk/integrations/openai';
|
|
40
|
+
*
|
|
41
|
+
* const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
42
|
+
* const tracedOpenAI = traceOpenAI(openai, evalClient);
|
|
43
|
+
*
|
|
44
|
+
* // Automatically traced
|
|
45
|
+
* const completion = await tracedOpenAI.chat.completions.create({
|
|
46
|
+
* model: 'gpt-4',
|
|
47
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function traceOpenAI(openai: any, evalClient: AIEvalClient, options?: OpenAITraceOptions): any;
|
|
52
|
+
/**
|
|
53
|
+
* Manual trace wrapper for OpenAI calls
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const response = await traceOpenAICall(
|
|
58
|
+
* evalClient,
|
|
59
|
+
* 'gpt-4-completion',
|
|
60
|
+
* async () => {
|
|
61
|
+
* return await openai.chat.completions.create({
|
|
62
|
+
* model: 'gpt-4',
|
|
63
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
64
|
+
* });
|
|
65
|
+
* }
|
|
66
|
+
* );
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function traceOpenAICall<T>(evalClient: AIEvalClient, name: string, fn: () => Promise<T>, options?: OpenAITraceOptions): Promise<T>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Integration
|
|
4
|
+
* Tier 1.2: Framework Auto-Instrumentation - OpenAI wrapper
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { traceOpenAI } from '@ai-eval-platform/sdk/integrations/openai';
|
|
9
|
+
* import OpenAI from 'openai';
|
|
10
|
+
*
|
|
11
|
+
* const openai = new OpenAI({ apiKey: '...' });
|
|
12
|
+
* const tracedOpenAI = traceOpenAI(openai, client);
|
|
13
|
+
*
|
|
14
|
+
* // All calls are automatically traced
|
|
15
|
+
* const response = await tracedOpenAI.chat.completions.create({
|
|
16
|
+
* model: 'gpt-4',
|
|
17
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.traceOpenAI = traceOpenAI;
|
|
23
|
+
exports.traceOpenAICall = traceOpenAICall;
|
|
24
|
+
const context_1 = require("../context");
|
|
25
|
+
/**
|
|
26
|
+
* Wrap OpenAI client with automatic tracing
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import OpenAI from 'openai';
|
|
31
|
+
* import { traceOpenAI } from '@ai-eval-platform/sdk/integrations/openai';
|
|
32
|
+
*
|
|
33
|
+
* const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
34
|
+
* const tracedOpenAI = traceOpenAI(openai, evalClient);
|
|
35
|
+
*
|
|
36
|
+
* // Automatically traced
|
|
37
|
+
* const completion = await tracedOpenAI.chat.completions.create({
|
|
38
|
+
* model: 'gpt-4',
|
|
39
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
function traceOpenAI(openai, evalClient, options = {}) {
|
|
44
|
+
const { captureInput = true, captureOutput = true, captureMetadata = true, organizationId, tracePrefix = 'openai' } = options;
|
|
45
|
+
// Create proxy for chat.completions.create
|
|
46
|
+
const originalCreate = openai.chat.completions.create.bind(openai.chat.completions);
|
|
47
|
+
openai.chat.completions.create = async (params, requestOptions) => {
|
|
48
|
+
const startTime = Date.now();
|
|
49
|
+
const traceId = `${tracePrefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
50
|
+
try {
|
|
51
|
+
// Call original method
|
|
52
|
+
const response = await originalCreate(params, requestOptions);
|
|
53
|
+
const durationMs = Date.now() - startTime;
|
|
54
|
+
// Create trace with success status and complete metadata
|
|
55
|
+
const traceMetadata = (0, context_1.mergeWithContext)({
|
|
56
|
+
model: params.model,
|
|
57
|
+
temperature: params.temperature,
|
|
58
|
+
max_tokens: params.max_tokens,
|
|
59
|
+
...(captureInput ? { input: params.messages } : {}),
|
|
60
|
+
...(captureOutput ? { output: response.choices[0]?.message } : {}),
|
|
61
|
+
...(captureMetadata ? {
|
|
62
|
+
usage: response.usage,
|
|
63
|
+
finish_reason: response.choices[0]?.finish_reason
|
|
64
|
+
} : {})
|
|
65
|
+
});
|
|
66
|
+
await evalClient.traces.create({
|
|
67
|
+
name: `OpenAI: ${params.model}`,
|
|
68
|
+
traceId,
|
|
69
|
+
organizationId: organizationId || evalClient.getOrganizationId(),
|
|
70
|
+
status: 'success',
|
|
71
|
+
durationMs,
|
|
72
|
+
metadata: traceMetadata
|
|
73
|
+
});
|
|
74
|
+
return response;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const durationMs = Date.now() - startTime;
|
|
78
|
+
// Create trace with error status
|
|
79
|
+
const errorMetadata = (0, context_1.mergeWithContext)({
|
|
80
|
+
model: params.model,
|
|
81
|
+
temperature: params.temperature,
|
|
82
|
+
max_tokens: params.max_tokens,
|
|
83
|
+
...(captureInput ? { input: params.messages } : {}),
|
|
84
|
+
...(captureMetadata ? { params } : {}),
|
|
85
|
+
error: error instanceof Error ? error.message : String(error)
|
|
86
|
+
});
|
|
87
|
+
await evalClient.traces.create({
|
|
88
|
+
name: `OpenAI: ${params.model}`,
|
|
89
|
+
traceId,
|
|
90
|
+
organizationId: organizationId || evalClient.getOrganizationId(),
|
|
91
|
+
status: 'error',
|
|
92
|
+
durationMs,
|
|
93
|
+
metadata: errorMetadata
|
|
94
|
+
}).catch(() => {
|
|
95
|
+
// Ignore errors in trace creation to avoid masking the original error
|
|
96
|
+
});
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
return openai;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Manual trace wrapper for OpenAI calls
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const response = await traceOpenAICall(
|
|
108
|
+
* evalClient,
|
|
109
|
+
* 'gpt-4-completion',
|
|
110
|
+
* async () => {
|
|
111
|
+
* return await openai.chat.completions.create({
|
|
112
|
+
* model: 'gpt-4',
|
|
113
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
114
|
+
* });
|
|
115
|
+
* }
|
|
116
|
+
* );
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
async function traceOpenAICall(evalClient, name, fn, options = {}) {
|
|
120
|
+
const startTime = Date.now();
|
|
121
|
+
const traceId = `openai-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
122
|
+
try {
|
|
123
|
+
await evalClient.traces.create({
|
|
124
|
+
name,
|
|
125
|
+
traceId,
|
|
126
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
127
|
+
status: 'pending',
|
|
128
|
+
metadata: (0, context_1.mergeWithContext)({})
|
|
129
|
+
});
|
|
130
|
+
const result = await fn();
|
|
131
|
+
const durationMs = Date.now() - startTime;
|
|
132
|
+
await evalClient.traces.create({
|
|
133
|
+
name,
|
|
134
|
+
traceId,
|
|
135
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
136
|
+
status: 'success',
|
|
137
|
+
durationMs,
|
|
138
|
+
metadata: (0, context_1.mergeWithContext)({})
|
|
139
|
+
});
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
const durationMs = Date.now() - startTime;
|
|
144
|
+
await evalClient.traces.create({
|
|
145
|
+
name,
|
|
146
|
+
traceId,
|
|
147
|
+
organizationId: options.organizationId || evalClient.getOrganizationId(),
|
|
148
|
+
status: 'error',
|
|
149
|
+
durationMs,
|
|
150
|
+
metadata: (0, context_1.mergeWithContext)({
|
|
151
|
+
error: error instanceof Error ? error.message : String(error)
|
|
152
|
+
})
|
|
153
|
+
});
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
package/dist/local.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Development Mode (Tier 2.10)
|
|
3
|
+
* Offline mode with local storage for development
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ NOTE: This module requires Node.js and will not work in browsers.
|
|
6
|
+
*/
|
|
7
|
+
import type { Trace, Evaluation, Span } from './types';
|
|
8
|
+
export interface LocalStorageOptions {
|
|
9
|
+
directory?: string;
|
|
10
|
+
autoSave?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class LocalStorage {
|
|
13
|
+
private directory;
|
|
14
|
+
private autoSave;
|
|
15
|
+
private traces;
|
|
16
|
+
private evaluations;
|
|
17
|
+
private spans;
|
|
18
|
+
constructor(options?: LocalStorageOptions);
|
|
19
|
+
private initialize;
|
|
20
|
+
private loadAllData;
|
|
21
|
+
private saveTraceToDisk;
|
|
22
|
+
saveTrace(trace: Trace): Promise<void>;
|
|
23
|
+
getTrace(id: string): Promise<Trace | undefined>;
|
|
24
|
+
listTraces(): Promise<Trace[]>;
|
|
25
|
+
private saveEvaluationToDisk;
|
|
26
|
+
saveEvaluation(evaluation: Evaluation): Promise<void>;
|
|
27
|
+
getEvaluation(id: string): Promise<Evaluation | undefined>;
|
|
28
|
+
listEvaluations(): Promise<Evaluation[]>;
|
|
29
|
+
private saveSpansToDisk;
|
|
30
|
+
saveSpans(traceId: string, spans: Span[]): Promise<void>;
|
|
31
|
+
getSpans(traceId: string): Promise<Span[] | undefined>;
|
|
32
|
+
clear(): Promise<void>;
|
|
33
|
+
export(format: 'json'): Promise<string>;
|
|
34
|
+
getStats(): {
|
|
35
|
+
traces: number;
|
|
36
|
+
evaluations: number;
|
|
37
|
+
totalSpans: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
package/dist/local.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local Development Mode (Tier 2.10)
|
|
4
|
+
* Offline mode with local storage for development
|
|
5
|
+
*
|
|
6
|
+
* ⚠️ NOTE: This module requires Node.js and will not work in browsers.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.LocalStorage = void 0;
|
|
13
|
+
// Environment check
|
|
14
|
+
const isNode = typeof process !== 'undefined' && process.versions?.node;
|
|
15
|
+
if (!isNode) {
|
|
16
|
+
throw new Error('Local storage mode requires Node.js and cannot run in browsers. ' +
|
|
17
|
+
'This feature uses the filesystem for storing data.');
|
|
18
|
+
}
|
|
19
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
class LocalStorage {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.traces = new Map();
|
|
24
|
+
this.evaluations = new Map();
|
|
25
|
+
this.spans = new Map();
|
|
26
|
+
this.directory = options.directory || './.evalai-data';
|
|
27
|
+
this.autoSave = options.autoSave !== false;
|
|
28
|
+
this.initialize();
|
|
29
|
+
}
|
|
30
|
+
async initialize() {
|
|
31
|
+
try {
|
|
32
|
+
await promises_1.default.mkdir(this.directory, { recursive: true });
|
|
33
|
+
await promises_1.default.mkdir(path_1.default.join(this.directory, 'traces'), { recursive: true });
|
|
34
|
+
await promises_1.default.mkdir(path_1.default.join(this.directory, 'evaluations'), { recursive: true });
|
|
35
|
+
await promises_1.default.mkdir(path_1.default.join(this.directory, 'spans'), { recursive: true });
|
|
36
|
+
// Load existing data
|
|
37
|
+
await this.loadAllData();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn('Failed to initialize local storage:', error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async loadAllData() {
|
|
44
|
+
try {
|
|
45
|
+
// Load traces
|
|
46
|
+
const tracesDir = path_1.default.join(this.directory, 'traces');
|
|
47
|
+
const traceFiles = await promises_1.default.readdir(tracesDir);
|
|
48
|
+
for (const file of traceFiles) {
|
|
49
|
+
if (file.endsWith('.json')) {
|
|
50
|
+
const content = await promises_1.default.readFile(path_1.default.join(tracesDir, file), 'utf-8');
|
|
51
|
+
const trace = JSON.parse(content);
|
|
52
|
+
this.traces.set(trace.id.toString(), trace);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Load evaluations
|
|
56
|
+
const evalsDir = path_1.default.join(this.directory, 'evaluations');
|
|
57
|
+
const evalFiles = await promises_1.default.readdir(evalsDir);
|
|
58
|
+
for (const file of evalFiles) {
|
|
59
|
+
if (file.endsWith('.json')) {
|
|
60
|
+
const content = await promises_1.default.readFile(path_1.default.join(evalsDir, file), 'utf-8');
|
|
61
|
+
const evaluation = JSON.parse(content);
|
|
62
|
+
this.evaluations.set(evaluation.id.toString(), evaluation);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// Directories might not exist yet, that's fine
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async saveTraceToDisk(trace) {
|
|
71
|
+
const filePath = path_1.default.join(this.directory, 'traces', `${trace.id}.json`);
|
|
72
|
+
await promises_1.default.writeFile(filePath, JSON.stringify(trace, null, 2));
|
|
73
|
+
}
|
|
74
|
+
async saveTrace(trace) {
|
|
75
|
+
this.traces.set(trace.id.toString(), trace);
|
|
76
|
+
if (this.autoSave) {
|
|
77
|
+
await this.saveTraceToDisk(trace);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async getTrace(id) {
|
|
81
|
+
return this.traces.get(id);
|
|
82
|
+
}
|
|
83
|
+
async listTraces() {
|
|
84
|
+
return Array.from(this.traces.values());
|
|
85
|
+
}
|
|
86
|
+
async saveEvaluationToDisk(evaluation) {
|
|
87
|
+
const filePath = path_1.default.join(this.directory, 'evaluations', `${evaluation.id}.json`);
|
|
88
|
+
await promises_1.default.writeFile(filePath, JSON.stringify(evaluation, null, 2));
|
|
89
|
+
}
|
|
90
|
+
async saveEvaluation(evaluation) {
|
|
91
|
+
this.evaluations.set(evaluation.id.toString(), evaluation);
|
|
92
|
+
if (this.autoSave) {
|
|
93
|
+
await this.saveEvaluationToDisk(evaluation);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async getEvaluation(id) {
|
|
97
|
+
return this.evaluations.get(id);
|
|
98
|
+
}
|
|
99
|
+
async listEvaluations() {
|
|
100
|
+
return Array.from(this.evaluations.values());
|
|
101
|
+
}
|
|
102
|
+
async saveSpansToDisk(traceId, spans) {
|
|
103
|
+
const filePath = path_1.default.join(this.directory, 'spans', `${traceId}.json`);
|
|
104
|
+
await promises_1.default.writeFile(filePath, JSON.stringify(spans, null, 2));
|
|
105
|
+
}
|
|
106
|
+
async saveSpans(traceId, spans) {
|
|
107
|
+
this.spans.set(traceId, spans);
|
|
108
|
+
if (this.autoSave) {
|
|
109
|
+
await this.saveSpansToDisk(traceId, spans);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async getSpans(traceId) {
|
|
113
|
+
return this.spans.get(traceId);
|
|
114
|
+
}
|
|
115
|
+
async clear() {
|
|
116
|
+
this.traces.clear();
|
|
117
|
+
this.evaluations.clear();
|
|
118
|
+
this.spans.clear();
|
|
119
|
+
// Optionally delete files
|
|
120
|
+
try {
|
|
121
|
+
await promises_1.default.rm(this.directory, { recursive: true, force: true });
|
|
122
|
+
await this.initialize();
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.warn('Failed to clear local storage:', error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async export(format) {
|
|
129
|
+
const data = {
|
|
130
|
+
traces: Array.from(this.traces.values()),
|
|
131
|
+
evaluations: Array.from(this.evaluations.values()),
|
|
132
|
+
spans: Object.fromEntries(this.spans)
|
|
133
|
+
};
|
|
134
|
+
const exportPath = path_1.default.join(this.directory, `export-${Date.now()}.json`);
|
|
135
|
+
await promises_1.default.writeFile(exportPath, JSON.stringify(data, null, 2));
|
|
136
|
+
return exportPath;
|
|
137
|
+
}
|
|
138
|
+
getStats() {
|
|
139
|
+
return {
|
|
140
|
+
traces: this.traces.size,
|
|
141
|
+
evaluations: this.evaluations.size,
|
|
142
|
+
totalSpans: Array.from(this.spans.values()).reduce((sum, spans) => sum + spans.length, 0)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.LocalStorage = LocalStorage;
|