scorecard-ai 2.2.0 → 2.4.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/client.d.mts +2 -2
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +2 -2
  5. package/client.d.ts.map +1 -1
  6. package/client.js.map +1 -1
  7. package/client.mjs.map +1 -1
  8. package/index.d.mts +1 -0
  9. package/index.d.mts.map +1 -1
  10. package/index.d.ts +1 -0
  11. package/index.d.ts.map +1 -1
  12. package/index.js +3 -1
  13. package/index.js.map +1 -1
  14. package/index.mjs +1 -0
  15. package/index.mjs.map +1 -1
  16. package/lib/wrapAISDK.d.mts +62 -0
  17. package/lib/wrapAISDK.d.mts.map +1 -0
  18. package/lib/wrapAISDK.d.ts +62 -0
  19. package/lib/wrapAISDK.d.ts.map +1 -0
  20. package/lib/wrapAISDK.js +154 -0
  21. package/lib/wrapAISDK.js.map +1 -0
  22. package/lib/wrapAISDK.mjs +151 -0
  23. package/lib/wrapAISDK.mjs.map +1 -0
  24. package/package.json +8 -2
  25. package/resources/index.d.mts +1 -1
  26. package/resources/index.d.mts.map +1 -1
  27. package/resources/index.d.ts +1 -1
  28. package/resources/index.d.ts.map +1 -1
  29. package/resources/index.js.map +1 -1
  30. package/resources/index.mjs.map +1 -1
  31. package/resources/records.d.mts +16 -1
  32. package/resources/records.d.mts.map +1 -1
  33. package/resources/records.d.ts +16 -1
  34. package/resources/records.d.ts.map +1 -1
  35. package/resources/records.js +11 -0
  36. package/resources/records.js.map +1 -1
  37. package/resources/records.mjs +11 -0
  38. package/resources/records.mjs.map +1 -1
  39. package/resources/scores.d.mts +1 -1
  40. package/resources/scores.d.ts +1 -1
  41. package/src/client.ts +2 -0
  42. package/src/index.ts +1 -0
  43. package/src/lib/wrapAISDK.ts +232 -0
  44. package/src/resources/index.ts +1 -0
  45. package/src/resources/records.ts +20 -0
  46. package/src/resources/scores.ts +1 -1
  47. package/src/version.ts +1 -1
  48. package/version.d.mts +1 -1
  49. package/version.d.ts +1 -1
  50. package/version.js +1 -1
  51. package/version.mjs +1 -1
@@ -0,0 +1,232 @@
1
+ import { NodeTracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace-node';
2
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
3
+ import { defaultResource, resourceFromAttributes } from '@opentelemetry/resources';
4
+ import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
5
+ import { Tracer } from '@opentelemetry/api';
6
+ import { readEnv } from '../internal/utils';
7
+ import { ScorecardError } from '../error';
8
+ import { Scorecard } from '../client';
9
+
10
+ /**
11
+ * Configuration for the Scorecard AI SDK wrapper
12
+ */
13
+ interface ScorecardConfig {
14
+ /**
15
+ * ID of the Scorecard project that traces should be associated with.
16
+ * Defaults to SCORECARD_PROJECT_ID environment variable.
17
+ */
18
+ projectId?: string;
19
+
20
+ /**
21
+ * Metrics to score the traces against.
22
+ * It can be a list of metric IDs, descriptions of what you want the metric to do, or a mix of both.
23
+ * For example: ['123', 'Check if the response is concise'].
24
+ * If it's a description, the metric will be created if it doesn't exist.
25
+ * Defaults to empty array.
26
+ */
27
+ metrics?: string[];
28
+
29
+ /**
30
+ * Scorecard API key for authentication.
31
+ * Defaults to SCORECARD_API_KEY environment variable.
32
+ */
33
+ apiKey?: string;
34
+
35
+ /**
36
+ * Service name for telemetry.
37
+ * Defaults to "ai-sdk-app".
38
+ */
39
+ serviceName?: string;
40
+
41
+ /**
42
+ * Service version for telemetry.
43
+ * Defaults to undefined.
44
+ */
45
+ serviceVersion?: string;
46
+
47
+ /**
48
+ * Max export batch size for the batch span processor.
49
+ * Defaults to 1 so the traces are exported immediately.
50
+ */
51
+ maxExportBatchSize?: number;
52
+ }
53
+
54
+ const DEFAULT_SERVICE_NAME = 'ai-sdk-app';
55
+ const AI_SDK_FUNCTIONS_WITH_TELEMETRY = new Set([
56
+ 'embed',
57
+ 'embedMany',
58
+ 'generateObject',
59
+ 'generateText',
60
+ 'streamObject',
61
+ 'streamText',
62
+ ]);
63
+ /**
64
+ * Initialize the OpenTelemetry tracer with Scorecard configuration.
65
+ */
66
+ function initializeTracer(config: ScorecardConfig = {}): Tracer {
67
+ const {
68
+ projectId = readEnv('SCORECARD_PROJECT_ID'),
69
+ apiKey = readEnv('SCORECARD_API_KEY'),
70
+ serviceName = DEFAULT_SERVICE_NAME,
71
+ serviceVersion,
72
+ maxExportBatchSize = 1,
73
+ } = config;
74
+
75
+ // Create resource with service information
76
+ const resource = defaultResource().merge(
77
+ resourceFromAttributes({
78
+ [ATTR_SERVICE_NAME]: serviceName,
79
+ ...(serviceVersion != null ? { [ATTR_SERVICE_VERSION]: serviceVersion } : null),
80
+ ...(projectId != null ? { 'scorecard.project_id': projectId } : null),
81
+ }),
82
+ );
83
+
84
+ // Create span processors
85
+ const spanProcessors = [];
86
+
87
+ try {
88
+ const tracingUrl = readEnv('SCORECARD_TRACING_URL') || 'https://tracing.scorecard.io/otel/v1/traces';
89
+ // Create OTLP exporter for Scorecard
90
+ const otlpExporter = new OTLPTraceExporter({
91
+ url: tracingUrl,
92
+ headers:
93
+ apiKey ?
94
+ {
95
+ Authorization: `Bearer ${apiKey}`,
96
+ }
97
+ : {},
98
+ });
99
+
100
+ // Add batch span processor with OTLP exporter
101
+ spanProcessors.push(
102
+ new BatchSpanProcessor(otlpExporter, {
103
+ maxExportBatchSize,
104
+ }),
105
+ );
106
+ } catch (error) {
107
+ // Handle initialization errors
108
+ console.error(error);
109
+ throw new ScorecardError('Failed to initialize Scorecard telemetry');
110
+ }
111
+
112
+ // Create tracer provider with span processors
113
+ const tracerProvider = new NodeTracerProvider({
114
+ resource,
115
+ spanProcessors,
116
+ });
117
+
118
+ // Register the provider
119
+ tracerProvider.register();
120
+
121
+ // Return the tracer instance
122
+ return tracerProvider.getTracer('ai-sdk-wrapper');
123
+ }
124
+
125
+ /**
126
+ * Wraps the AI SDK module to automatically inject telemetry configuration.
127
+ *
128
+ * @param aiSDKModule - The AI SDK module (e.g., import('ai'))
129
+ * @param config - Optional Scorecard configuration
130
+ * @returns Proxied AI SDK module with automatic telemetry injection
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * import ai from 'ai';
135
+ * import { wrapAISDK } from 'scorecard-ai';
136
+ *
137
+ * const aiSDK = await wrapAISDK(ai);
138
+ *
139
+ * // Now all AI SDK calls will automatically send traces to Scorecard.
140
+ * const { text } = await aiSDK.generateText({
141
+ * model: openai('gpt-4o-mini'),
142
+ * prompt: 'What is the capital of France? Answer in one sentence.',
143
+ * });
144
+ * ```
145
+ */
146
+ export function wrapAISDK<T extends Record<string, unknown>>(
147
+ aiSDKModule: T,
148
+ config: ScorecardConfig = {},
149
+ ): T {
150
+ const projectId = config.projectId || readEnv('SCORECARD_PROJECT_ID');
151
+ const apiKey = config.apiKey || readEnv('SCORECARD_API_KEY');
152
+ const serviceName = config.serviceName || DEFAULT_SERVICE_NAME;
153
+ if (!apiKey) {
154
+ throw new ScorecardError(
155
+ 'The SCORECARD_API_KEY environment variable is missing or empty; either provide it, or instantiate the AI SDK wrapper client with an apiKey option, like wrapAISDK(ai, { apiKey: "My API Key" }).',
156
+ );
157
+ }
158
+ const client = new Scorecard({ apiKey });
159
+
160
+ if (config.metrics && config.metrics.length > 0 && !projectId) {
161
+ throw new ScorecardError(
162
+ "The SCORECARD_PROJECT_ID environment variable is missing or empty; either provide it, or instantiate the AI SDK wrapper with a projectId option, like wrapAISDK(ai, { projectId: '123' }).",
163
+ );
164
+ }
165
+
166
+ // Create metrics and monitor if needed
167
+ if (config.metrics && config.metrics.length > 0 && projectId) {
168
+ client
169
+ .put(`/api/v2/projects/${projectId}/monitors`, {
170
+ body: {
171
+ description: serviceName,
172
+ metrics: config.metrics,
173
+ filter: {
174
+ serviceName,
175
+ },
176
+ },
177
+ })
178
+ // we use .catch instead of try/catch to avoid needing async/await in the wrapper
179
+ // otherwise the code would await here before giving back the wrapped AI SDK module
180
+ .catch((error) => {
181
+ console.error(
182
+ 'Failed to create a Scorecard monitor for your AI SDK traces. The most common case is that the projectId is incorrect.',
183
+ error,
184
+ );
185
+ });
186
+ }
187
+ // Initialize tracer
188
+ const tracerInstance = initializeTracer(config);
189
+
190
+ // Create telemetry configuration to inject
191
+ const telemetryConfig = {
192
+ isEnabled: true,
193
+ recordInputs: true,
194
+ recordOutputs: true,
195
+ tracer: tracerInstance,
196
+ };
197
+
198
+ // Create a proxy to intercept function calls
199
+ return new Proxy(aiSDKModule, {
200
+ get(target, prop: string | symbol) {
201
+ const originalValue = target[prop as keyof T];
202
+
203
+ // Only wrap functions that support telemetry
204
+ if (
205
+ typeof prop === 'string' &&
206
+ AI_SDK_FUNCTIONS_WITH_TELEMETRY.has(prop) &&
207
+ typeof originalValue === 'function'
208
+ ) {
209
+ return function (this: any, ...args: any[]) {
210
+ try {
211
+ // The first argument is typically the options object
212
+ if (args.length > 0 && args[0] && typeof args[0] === 'object') {
213
+ args[0].experimental_telemetry = {
214
+ ...telemetryConfig,
215
+ ...(args[0].experimental_telemetry || {}),
216
+ };
217
+ }
218
+ } catch (error) {
219
+ // Silently handle any errors during injection
220
+ console.error('Failed to inject telemetry config:', error);
221
+ }
222
+
223
+ // Call the original function
224
+ return originalValue.apply(this, args);
225
+ };
226
+ }
227
+
228
+ // Return original value for non-function properties or non-telemetry functions
229
+ return originalValue;
230
+ },
231
+ });
232
+ }
@@ -20,6 +20,7 @@ export {
20
20
  Records,
21
21
  type Record,
22
22
  type RecordListResponse,
23
+ type RecordDeleteResponse,
23
24
  type RecordCreateParams,
24
25
  type RecordListParams,
25
26
  type RecordListResponsesPaginatedResponse,
@@ -51,6 +51,18 @@ export class Records extends APIResource {
51
51
  ...options,
52
52
  });
53
53
  }
54
+
55
+ /**
56
+ * Delete a specific Record by ID.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const record = await client.records.delete('777');
61
+ * ```
62
+ */
63
+ delete(recordID: string, options?: RequestOptions): APIPromise<RecordDeleteResponse> {
64
+ return this._client.delete(path`/records/${recordID}`, options);
65
+ }
54
66
  }
55
67
 
56
68
  export type RecordListResponsesPaginatedResponse = PaginatedResponse<RecordListResponse>;
@@ -101,6 +113,13 @@ export interface RecordListResponse extends Record {
101
113
  scores: Array<ScoresAPI.Score>;
102
114
  }
103
115
 
116
+ export interface RecordDeleteResponse {
117
+ /**
118
+ * Whether the deletion was successful.
119
+ */
120
+ success: boolean;
121
+ }
122
+
104
123
  export interface RecordCreateParams {
105
124
  /**
106
125
  * The expected outputs for the Testcase.
@@ -130,6 +149,7 @@ export declare namespace Records {
130
149
  export {
131
150
  type Record as Record,
132
151
  type RecordListResponse as RecordListResponse,
152
+ type RecordDeleteResponse as RecordDeleteResponse,
133
153
  type RecordListResponsesPaginatedResponse as RecordListResponsesPaginatedResponse,
134
154
  type RecordCreateParams as RecordCreateParams,
135
155
  type RecordListParams as RecordListParams,
@@ -81,7 +81,7 @@ export namespace Score {
81
81
 
82
82
  export interface ScoreUpsertParams {
83
83
  /**
84
- * Path param: The ID of the Record.
84
+ * Path param: The ID of the Record to upsert the Score for.
85
85
  */
86
86
  recordId: string;
87
87
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '2.2.0'; // x-release-please-version
1
+ export const VERSION = '2.4.0'; // x-release-please-version
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.2.0";
1
+ export declare const VERSION = "2.4.0";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.2.0";
1
+ export declare const VERSION = "2.4.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '2.2.0'; // x-release-please-version
4
+ exports.VERSION = '2.4.0'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.2.0'; // x-release-please-version
1
+ export const VERSION = '2.4.0'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map