@thinkhive/sdk 3.1.0 → 3.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.
@@ -0,0 +1,188 @@
1
+ /**
2
+ * ThinkHive SDK v3.2 - Business Metrics API
3
+ *
4
+ * Industry-driven business metrics with historical tracking and external data support
5
+ */
6
+ /**
7
+ * Metric trend information
8
+ */
9
+ export interface MetricTrend {
10
+ direction: 'up' | 'down' | 'stable';
11
+ value: number;
12
+ isPositive: boolean;
13
+ }
14
+ /**
15
+ * Current metric status
16
+ */
17
+ export type MetricStatus = 'ready' | 'insufficient_data' | 'awaiting_external' | 'stale';
18
+ /**
19
+ * Current metric response from the API
20
+ */
21
+ export interface CurrentMetricResponse {
22
+ metricName: string;
23
+ metricType: 'trace_calculated' | 'external';
24
+ value: number | null;
25
+ valueFormatted: string;
26
+ unit?: string;
27
+ status: MetricStatus;
28
+ statusMessage?: string;
29
+ trend?: MetricTrend;
30
+ traceCount?: number;
31
+ minTraceThreshold?: number;
32
+ progressPercent?: number;
33
+ lastExternalUpdate?: string;
34
+ }
35
+ /**
36
+ * Historical data point
37
+ */
38
+ export interface MetricHistoryPoint {
39
+ periodStart: string;
40
+ periodEnd: string;
41
+ value: number;
42
+ valueFormatted?: string;
43
+ source: string;
44
+ traceCount?: number;
45
+ }
46
+ /**
47
+ * Historical summary statistics
48
+ */
49
+ export interface MetricHistorySummary {
50
+ current: number | null;
51
+ previous: number | null;
52
+ changePercent: number | null;
53
+ isPositive: boolean;
54
+ dataPointCount: number;
55
+ }
56
+ /**
57
+ * Full history response
58
+ */
59
+ export interface MetricHistoryResponse {
60
+ metricName: string;
61
+ unit: string;
62
+ higherIsBetter: boolean;
63
+ dataPoints: MetricHistoryPoint[];
64
+ summary: MetricHistorySummary;
65
+ }
66
+ /**
67
+ * Options for recording external metric values
68
+ */
69
+ export interface RecordMetricOptions {
70
+ metricName: string;
71
+ value: number;
72
+ unit?: string;
73
+ periodStart: string | Date;
74
+ periodEnd: string | Date;
75
+ source?: string;
76
+ sourceDetails?: Record<string, unknown>;
77
+ }
78
+ /**
79
+ * Response from recording a metric value
80
+ */
81
+ export interface RecordMetricResponse {
82
+ success: boolean;
83
+ id: string;
84
+ recordedAt: string;
85
+ }
86
+ /**
87
+ * Business Metrics API client for industry-driven metrics with historical tracking
88
+ */
89
+ export declare const businessMetrics: {
90
+ /**
91
+ * Get current metric value with status information
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const metric = await businessMetrics.current('agent_123', 'Deflection Rate');
96
+ * console.log(`${metric.metricName}: ${metric.valueFormatted}`);
97
+ *
98
+ * if (metric.status === 'insufficient_data') {
99
+ * console.log(`Need ${metric.minTraceThreshold - metric.traceCount} more traces`);
100
+ * }
101
+ * ```
102
+ */
103
+ current(agentId: string, metricName?: string): Promise<CurrentMetricResponse>;
104
+ /**
105
+ * Get historical metric data for graphing
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const history = await businessMetrics.history('agent_123', 'Deflection Rate', {
110
+ * startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
111
+ * endDate: new Date(),
112
+ * granularity: 'daily',
113
+ * });
114
+ *
115
+ * console.log(`${history.dataPoints.length} data points`);
116
+ * console.log(`Change: ${history.summary.changePercent}%`);
117
+ * ```
118
+ */
119
+ history(agentId: string, metricName: string, options?: {
120
+ startDate?: string | Date;
121
+ endDate?: string | Date;
122
+ granularity?: "hourly" | "daily" | "weekly" | "monthly";
123
+ }): Promise<MetricHistoryResponse>;
124
+ /**
125
+ * Record an external metric value
126
+ *
127
+ * Use this to ingest metrics from external data sources (CRM, surveys, billing, etc.)
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * // Record CSAT score from survey system
132
+ * await businessMetrics.record('agent_123', {
133
+ * metricName: 'CSAT/NPS',
134
+ * value: 4.5,
135
+ * unit: 'score',
136
+ * periodStart: '2024-01-01T00:00:00Z',
137
+ * periodEnd: '2024-01-07T23:59:59Z',
138
+ * source: 'survey_system',
139
+ * sourceDetails: { surveyId: 'survey_456', responseCount: 150 },
140
+ * });
141
+ * ```
142
+ */
143
+ record(agentId: string, options: RecordMetricOptions): Promise<RecordMetricResponse>;
144
+ /**
145
+ * Batch record multiple external metric values
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * await businessMetrics.recordBatch('agent_123', [
150
+ * { metricName: 'CSAT/NPS', value: 4.5, ... },
151
+ * { metricName: 'Hours Saved', value: 120, ... },
152
+ * ]);
153
+ * ```
154
+ */
155
+ recordBatch(agentId: string, metrics: RecordMetricOptions[]): Promise<RecordMetricResponse[]>;
156
+ };
157
+ /**
158
+ * Check if a metric is ready to display
159
+ */
160
+ export declare function isMetricReady(metric: CurrentMetricResponse): boolean;
161
+ /**
162
+ * Check if a metric needs more trace data
163
+ */
164
+ export declare function needsMoreTraces(metric: CurrentMetricResponse): boolean;
165
+ /**
166
+ * Check if a metric is waiting for external data
167
+ */
168
+ export declare function awaitingExternalData(metric: CurrentMetricResponse): boolean;
169
+ /**
170
+ * Check if metric data is stale
171
+ */
172
+ export declare function isMetricStale(metric: CurrentMetricResponse): boolean;
173
+ /**
174
+ * Get human-readable status message
175
+ */
176
+ export declare function getStatusMessage(metric: CurrentMetricResponse): string;
177
+ /**
178
+ * Calculate progress toward minimum trace threshold
179
+ */
180
+ export declare function getTraceProgress(metric: CurrentMetricResponse): number;
181
+ /**
182
+ * Format metric value for display based on unit
183
+ */
184
+ export declare function formatMetricValue(value: number, unit: string): string;
185
+ /**
186
+ * Get trend direction as emoji
187
+ */
188
+ export declare function getTrendEmoji(trend: MetricTrend): string;
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /**
3
+ * ThinkHive SDK v3.2 - Business Metrics API
4
+ *
5
+ * Industry-driven business metrics with historical tracking and external data support
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.businessMetrics = void 0;
9
+ exports.isMetricReady = isMetricReady;
10
+ exports.needsMoreTraces = needsMoreTraces;
11
+ exports.awaitingExternalData = awaitingExternalData;
12
+ exports.isMetricStale = isMetricStale;
13
+ exports.getStatusMessage = getStatusMessage;
14
+ exports.getTraceProgress = getTraceProgress;
15
+ exports.formatMetricValue = formatMetricValue;
16
+ exports.getTrendEmoji = getTrendEmoji;
17
+ const client_1 = require("../core/client");
18
+ // ============================================================================
19
+ // BUSINESS METRICS API CLIENT
20
+ // ============================================================================
21
+ /**
22
+ * Business Metrics API client for industry-driven metrics with historical tracking
23
+ */
24
+ exports.businessMetrics = {
25
+ /**
26
+ * Get current metric value with status information
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const metric = await businessMetrics.current('agent_123', 'Deflection Rate');
31
+ * console.log(`${metric.metricName}: ${metric.valueFormatted}`);
32
+ *
33
+ * if (metric.status === 'insufficient_data') {
34
+ * console.log(`Need ${metric.minTraceThreshold - metric.traceCount} more traces`);
35
+ * }
36
+ * ```
37
+ */
38
+ async current(agentId, metricName) {
39
+ const params = new URLSearchParams();
40
+ if (metricName) {
41
+ params.set('metricName', metricName);
42
+ }
43
+ const queryString = params.toString();
44
+ const url = `/agents/${agentId}/metrics/current${queryString ? `?${queryString}` : ''}`;
45
+ return (0, client_1.apiRequestWithData)(url, { apiVersion: 'v3' });
46
+ },
47
+ /**
48
+ * Get historical metric data for graphing
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const history = await businessMetrics.history('agent_123', 'Deflection Rate', {
53
+ * startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
54
+ * endDate: new Date(),
55
+ * granularity: 'daily',
56
+ * });
57
+ *
58
+ * console.log(`${history.dataPoints.length} data points`);
59
+ * console.log(`Change: ${history.summary.changePercent}%`);
60
+ * ```
61
+ */
62
+ async history(agentId, metricName, options = {}) {
63
+ const params = new URLSearchParams();
64
+ params.set('metricName', metricName);
65
+ if (options.startDate) {
66
+ params.set('startDate', new Date(options.startDate).toISOString());
67
+ }
68
+ if (options.endDate) {
69
+ params.set('endDate', new Date(options.endDate).toISOString());
70
+ }
71
+ if (options.granularity) {
72
+ params.set('granularity', options.granularity);
73
+ }
74
+ return (0, client_1.apiRequestWithData)(`/agents/${agentId}/metrics/history?${params.toString()}`, { apiVersion: 'v3' });
75
+ },
76
+ /**
77
+ * Record an external metric value
78
+ *
79
+ * Use this to ingest metrics from external data sources (CRM, surveys, billing, etc.)
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * // Record CSAT score from survey system
84
+ * await businessMetrics.record('agent_123', {
85
+ * metricName: 'CSAT/NPS',
86
+ * value: 4.5,
87
+ * unit: 'score',
88
+ * periodStart: '2024-01-01T00:00:00Z',
89
+ * periodEnd: '2024-01-07T23:59:59Z',
90
+ * source: 'survey_system',
91
+ * sourceDetails: { surveyId: 'survey_456', responseCount: 150 },
92
+ * });
93
+ * ```
94
+ */
95
+ async record(agentId, options) {
96
+ const body = {
97
+ metricName: options.metricName,
98
+ value: options.value,
99
+ unit: options.unit,
100
+ periodStart: new Date(options.periodStart).toISOString(),
101
+ periodEnd: new Date(options.periodEnd).toISOString(),
102
+ source: options.source || 'api',
103
+ sourceDetails: options.sourceDetails,
104
+ };
105
+ const response = await (0, client_1.apiRequest)(`/agents/${agentId}/metrics/values`, {
106
+ method: 'POST',
107
+ body,
108
+ apiVersion: 'v3',
109
+ });
110
+ return response.data;
111
+ },
112
+ /**
113
+ * Batch record multiple external metric values
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * await businessMetrics.recordBatch('agent_123', [
118
+ * { metricName: 'CSAT/NPS', value: 4.5, ... },
119
+ * { metricName: 'Hours Saved', value: 120, ... },
120
+ * ]);
121
+ * ```
122
+ */
123
+ async recordBatch(agentId, metrics) {
124
+ const results = await Promise.all(metrics.map((metric) => this.record(agentId, metric)));
125
+ return results;
126
+ },
127
+ };
128
+ // ============================================================================
129
+ // HELPER FUNCTIONS
130
+ // ============================================================================
131
+ /**
132
+ * Check if a metric is ready to display
133
+ */
134
+ function isMetricReady(metric) {
135
+ return metric.status === 'ready';
136
+ }
137
+ /**
138
+ * Check if a metric needs more trace data
139
+ */
140
+ function needsMoreTraces(metric) {
141
+ return metric.status === 'insufficient_data';
142
+ }
143
+ /**
144
+ * Check if a metric is waiting for external data
145
+ */
146
+ function awaitingExternalData(metric) {
147
+ return metric.status === 'awaiting_external';
148
+ }
149
+ /**
150
+ * Check if metric data is stale
151
+ */
152
+ function isMetricStale(metric) {
153
+ return metric.status === 'stale';
154
+ }
155
+ /**
156
+ * Get human-readable status message
157
+ */
158
+ function getStatusMessage(metric) {
159
+ switch (metric.status) {
160
+ case 'ready':
161
+ return 'Metric is up to date';
162
+ case 'insufficient_data':
163
+ return metric.statusMessage ||
164
+ `Need ${(metric.minTraceThreshold || 50) - (metric.traceCount || 0)} more traces`;
165
+ case 'awaiting_external':
166
+ return metric.statusMessage || 'Waiting for external data source';
167
+ case 'stale':
168
+ return metric.statusMessage || 'Data may be outdated';
169
+ default:
170
+ return 'Unknown status';
171
+ }
172
+ }
173
+ /**
174
+ * Calculate progress toward minimum trace threshold
175
+ */
176
+ function getTraceProgress(metric) {
177
+ if (metric.status !== 'insufficient_data')
178
+ return 100;
179
+ return metric.progressPercent || 0;
180
+ }
181
+ /**
182
+ * Format metric value for display based on unit
183
+ */
184
+ function formatMetricValue(value, unit) {
185
+ switch (unit) {
186
+ case '%':
187
+ return `${Math.round(value * 10) / 10}%`;
188
+ case '$':
189
+ return new Intl.NumberFormat('en-US', {
190
+ style: 'currency',
191
+ currency: 'USD',
192
+ }).format(value);
193
+ case 's':
194
+ return value < 60 ? `${Math.round(value)}s` : `${Math.round(value / 60)}m`;
195
+ case 'hrs':
196
+ return `${Math.round(value * 10) / 10} hrs`;
197
+ case 'score':
198
+ return value.toFixed(1);
199
+ default:
200
+ return String(Math.round(value * 100) / 100);
201
+ }
202
+ }
203
+ /**
204
+ * Get trend direction as emoji
205
+ */
206
+ function getTrendEmoji(trend) {
207
+ if (trend.direction === 'up')
208
+ return trend.isPositive ? '📈' : '📉';
209
+ if (trend.direction === 'down')
210
+ return trend.isPositive ? '📈' : '📉';
211
+ return '➡️';
212
+ }
213
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVzaW5lc3MtbWV0cmljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvYnVzaW5lc3MtbWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7O0FBMFBILHNDQUVDO0FBS0QsMENBRUM7QUFLRCxvREFFQztBQUtELHNDQUVDO0FBS0QsNENBY0M7QUFLRCw0Q0FHQztBQUtELDhDQWtCQztBQUtELHNDQUlDO0FBMVVELDJDQUFnRTtBQStGaEUsK0VBQStFO0FBQy9FLDhCQUE4QjtBQUM5QiwrRUFBK0U7QUFFL0U7O0dBRUc7QUFDVSxRQUFBLGVBQWUsR0FBRztJQUM3Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUNYLE9BQWUsRUFDZixVQUFtQjtRQUVuQixNQUFNLE1BQU0sR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1FBQ3JDLElBQUksVUFBVSxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sR0FBRyxHQUFHLFdBQVcsT0FBTyxtQkFBbUIsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUV4RixPQUFPLElBQUEsMkJBQWtCLEVBQXdCLEdBQUcsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILEtBQUssQ0FBQyxPQUFPLENBQ1gsT0FBZSxFQUNmLFVBQWtCLEVBQ2xCLFVBSUksRUFBRTtRQUVOLE1BQU0sTUFBTSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7UUFDckMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUs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QUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQztRQUM3RSxLQUFLLEtBQUs7WUFDUixPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUM7UUFDOUMsS0FBSyxPQUFPO1lBQ1YsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFCO1lBQ0UsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7SUFDakQsQ0FBQztBQUNILENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGFBQWEsQ0FBQyxLQUFrQjtJQUM5QyxJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssSUFBSTtRQUFFLE9BQU8sS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDcEUsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLE1BQU07UUFBRSxPQUFPLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ3RFLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhpbmtIaXZlIFNESyB2My4yIC0gQnVzaW5lc3MgTWV0cmljcyBBUElcbiAqXG4gKiBJbmR1c3RyeS1kcml2ZW4gYnVzaW5lc3MgbWV0cmljcyB3aXRoIGhpc3RvcmljYWwgdHJhY2tpbmcgYW5kIGV4dGVybmFsIGRhdGEgc3VwcG9ydFxuICovXG5cbmltcG9ydCB7IGFwaVJlcXVlc3QsIGFwaVJlcXVlc3RXaXRoRGF0YSB9IGZyb20gJy4uL2NvcmUvY2xpZW50JztcbmltcG9ydCB0eXBlIHsgQXBpUmVzcG9uc2UgfSBmcm9tICcuLi9jb3JlL3R5cGVzJztcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVFlQRVNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBNZXRyaWMgdHJlbmQgaW5mb3JtYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRyaWNUcmVuZCB7XG4gIGRpcmVjdGlvbjogJ3VwJyB8ICdkb3duJyB8ICdzdGFibGUnO1xuICB2YWx1ZTogbnVtYmVyO1xuICBpc1Bvc2l0aXZlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEN1cnJlbnQgbWV0cmljIHN0YXR1c1xuICovXG5leHBvcnQgdHlwZSBNZXRyaWNTdGF0dXMgPSAncmVhZHknIHwgJ2luc3VmZmljaWVudF9kYXRhJyB8ICdhd2FpdGluZ19leHRlcm5hbCcgfCAnc3RhbGUnO1xuXG4vKipcbiAqIEN1cnJlbnQgbWV0cmljIHJlc3BvbnNlIGZyb20gdGhlIEFQSVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEN1cnJlbnRNZXRyaWNSZXNwb25zZSB7XG4gIG1ldHJpY05hbWU6IHN0cmluZztcbiAgbWV0cmljVHlwZTogJ3RyYWNlX2NhbGN1bGF0ZWQnIHwgJ2V4dGVybmFsJztcbiAgdmFsdWU6IG51bWJlciB8IG51bGw7XG4gIHZhbHVlRm9ybWF0dGVkOiBzdHJpbmc7XG4gIHVuaXQ/OiBzdHJpbmc7XG4gIHN0YXR1czogTWV0cmljU3RhdHVzO1xuICBzdGF0dXNNZXNzYWdlPzogc3RyaW5nO1xuICB0cmVuZD86IE1ldHJpY1RyZW5kO1xuICB0cmFjZUNvdW50PzogbnVtYmVyO1xuICBtaW5UcmFjZVRocmVzaG9sZD86IG51bWJlcjtcbiAgcHJvZ3Jlc3NQZXJjZW50PzogbnVtYmVyO1xuICBsYXN0RXh0ZXJuYWxVcGRhdGU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogSGlzdG9yaWNhbCBkYXRhIHBvaW50XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0cmljSGlzdG9yeVBvaW50IHtcbiAgcGVyaW9kU3RhcnQ6IHN0cmluZztcbiAgcGVyaW9kRW5kOiBzdHJpbmc7XG4gIHZhbHVlOiBudW1iZXI7XG4gIHZhbHVlRm9ybWF0dGVkPzogc3RyaW5nO1xuICBzb3VyY2U6IHN0cmluZztcbiAgdHJhY2VDb3VudD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBIaXN0b3JpY2FsIHN1bW1hcnkgc3RhdGlzdGljc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIE1ldHJpY0hpc3RvcnlTdW1tYXJ5IHtcbiAgY3VycmVudDogbnVtYmVyIHwgbnVsbDtcbiAgcHJldmlvdXM6IG51bWJlciB8IG51bGw7XG4gIGNoYW5nZVBlcmNlbnQ6IG51bWJlciB8IG51bGw7XG4gIGlzUG9zaXRpdmU6IGJvb2xlYW47XG4gIGRhdGFQb2ludENvdW50OiBudW1iZXI7XG59XG5cbi8qKlxuICogRnVsbCBoaXN0b3J5IHJlc3BvbnNlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0cmljSGlzdG9yeVJlc3BvbnNlIHtcbiAgbWV0cmljTmFtZTogc3RyaW5nO1xuICB1bml0OiBzdHJpbmc7XG4gIGhpZ2hlcklzQmV0dGVyOiBib29sZWFuO1xuICBkYXRhUG9pbnRzOiBNZXRyaWNIaXN0b3J5UG9pbnRbXTtcbiAgc3VtbWFyeTogTWV0cmljSGlzdG9yeVN1bW1hcnk7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgcmVjb3JkaW5nIGV4dGVybmFsIG1ldHJpYyB2YWx1ZXNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWNvcmRNZXRyaWNPcHRpb25zIHtcbiAgbWV0cmljTmFtZTogc3RyaW5nO1xuICB2YWx1ZTogbnVtYmVyO1xuICB1bml0Pzogc3RyaW5nO1xuICBwZXJpb2RTdGFydDogc3RyaW5nIHwgRGF0ZTtcbiAgcGVyaW9kRW5kOiBzdHJpbmcgfCBEYXRlO1xuICBzb3VyY2U/OiBzdHJpbmc7XG4gIHNvdXJjZURldGFpbHM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqXG4gKiBSZXNwb25zZSBmcm9tIHJlY29yZGluZyBhIG1ldHJpYyB2YWx1ZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlY29yZE1ldHJpY1Jlc3BvbnNlIHtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgaWQ6IHN0cmluZztcbiAgcmVjb3JkZWRBdDogc3RyaW5nO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBCVVNJTkVTUyBNRVRSSUNTIEFQSSBDTElFTlRcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBCdXNpbmVzcyBNZXRyaWNzIEFQSSBjbGllbnQgZm9yIGluZHVzdHJ5LWRyaXZlbiBtZXRyaWNzIHdpdGggaGlzdG9yaWNhbCB0cmFja2luZ1xuICovXG5leHBvcnQgY29uc3QgYnVzaW5lc3NNZXRyaWNzID0ge1xuICAvKipcbiAgICogR2V0IGN1cnJlbnQgbWV0cmljIHZhbHVlIHdpdGggc3RhdHVzIGluZm9ybWF0aW9uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgbWV0cmljID0gYXdhaXQgYnVzaW5lc3NNZXRyaWNzLmN1cnJlbnQoJ2FnZW50XzEyMycsICdEZWZsZWN0aW9uIFJhdGUnKTtcbiAgICogY29uc29sZS5sb2coYCR7bWV0cmljLm1ldHJpY05hbWV9OiAke21ldHJpYy52YWx1ZUZvcm1hdHRlZH1gKTtcbiAgICpcbiAgICogaWYgKG1ldHJpYy5zdGF0dXMgPT09ICdpbnN1ZmZpY2llbnRfZGF0YScpIHtcbiAgICogICBjb25zb2xlLmxvZyhgTmVlZCAke21ldHJpYy5taW5UcmFjZVRocmVzaG9sZCAtIG1ldHJpYy50cmFjZUNvdW50fSBtb3JlIHRyYWNlc2ApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgY3VycmVudChcbiAgICBhZ2VudElkOiBzdHJpbmcsXG4gICAgbWV0cmljTmFtZT86IHN0cmluZ1xuICApOiBQcm9taXNlPEN1cnJlbnRNZXRyaWNSZXNwb25zZT4ge1xuICAgIGNvbnN0IHBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoKTtcbiAgICBpZiAobWV0cmljTmFtZSkge1xuICAgICAgcGFyYW1zLnNldCgnbWV0cmljTmFtZScsIG1ldHJpY05hbWUpO1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXJ5U3RyaW5nID0gcGFyYW1zLnRvU3RyaW5nKCk7XG4gICAgY29uc3QgdXJsID0gYC9hZ2VudHMvJHthZ2VudElkfS9tZXRyaWNzL2N1cnJlbnQke3F1ZXJ5U3RyaW5nID8gYD8ke3F1ZXJ5U3RyaW5nfWAgOiAnJ31gO1xuXG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YTxDdXJyZW50TWV0cmljUmVzcG9uc2U+KHVybCwgeyBhcGlWZXJzaW9uOiAndjMnIH0pO1xuICB9LFxuXG4gIC8qKlxuICAgKiBHZXQgaGlzdG9yaWNhbCBtZXRyaWMgZGF0YSBmb3IgZ3JhcGhpbmdcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBoaXN0b3J5ID0gYXdhaXQgYnVzaW5lc3NNZXRyaWNzLmhpc3RvcnkoJ2FnZW50XzEyMycsICdEZWZsZWN0aW9uIFJhdGUnLCB7XG4gICAqICAgc3RhcnREYXRlOiBuZXcgRGF0ZShEYXRlLm5vdygpIC0gMzAgKiAyNCAqIDYwICogNjAgKiAxMDAwKSxcbiAgICogICBlbmREYXRlOiBuZXcgRGF0ZSgpLFxuICAgKiAgIGdyYW51bGFyaXR5OiAnZGFpbHknLFxuICAgKiB9KTtcbiAgICpcbiAgICogY29uc29sZS5sb2coYCR7aGlzdG9yeS5kYXRhUG9pbnRzLmxlbmd0aH0gZGF0YSBwb2ludHNgKTtcbiAgICogY29uc29sZS5sb2coYENoYW5nZTogJHtoaXN0b3J5LnN1bW1hcnkuY2hhbmdlUGVyY2VudH0lYCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgaGlzdG9yeShcbiAgICBhZ2VudElkOiBzdHJpbmcsXG4gICAgbWV0cmljTmFtZTogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIHN0YXJ0RGF0ZT86IHN0cmluZyB8IERhdGU7XG4gICAgICBlbmREYXRlPzogc3RyaW5nIHwgRGF0ZTtcbiAgICAgIGdyYW51bGFyaXR5PzogJ2hvdXJseScgfCAnZGFpbHknIHwgJ3dlZWtseScgfCAnbW9udGhseSc7XG4gICAgfSA9IHt9XG4gICk6IFByb21pc2U8TWV0cmljSGlzdG9yeVJlc3BvbnNlPiB7XG4gICAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcygpO1xuICAgIHBhcmFtcy5zZXQoJ21ldHJpY05hbWUnLCBtZXRyaWNOYW1lKTtcblxuICAgIGlmIChvcHRpb25zLnN0YXJ0RGF0ZSkge1xuICAgICAgcGFyYW1zLnNldCgnc3RhcnREYXRlJywgbmV3IERhdGUob3B0aW9ucy5zdGFydERhdGUpLnRvSVNPU3RyaW5nKCkpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5lbmREYXRlKSB7XG4gICAgICBwYXJhbXMuc2V0KCdlbmREYXRlJywgbmV3IERhdGUob3B0aW9ucy5lbmREYXRlKS50b0lTT1N0cmluZygpKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuZ3JhbnVsYXJpdHkpIHtcbiAgICAgIHBhcmFtcy5zZXQoJ2dyYW51bGFyaXR5Jywgb3B0aW9ucy5ncmFudWxhcml0eSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YTxNZXRyaWNIaXN0b3J5UmVzcG9uc2U+KFxuICAgICAgYC9hZ2VudHMvJHthZ2VudElkfS9tZXRyaWNzL2hpc3Rvcnk/JHtwYXJhbXMudG9TdHJpbmcoKX1gLFxuICAgICAgeyBhcGlWZXJzaW9uOiAndjMnIH1cbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZWNvcmQgYW4gZXh0ZXJuYWwgbWV0cmljIHZhbHVlXG4gICAqXG4gICAqIFVzZSB0aGlzIHRvIGluZ2VzdCBtZXRyaWNzIGZyb20gZXh0ZXJuYWwgZGF0YSBzb3VyY2VzIChDUk0sIHN1cnZleXMsIGJpbGxpbmcsIGV0Yy4pXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gUmVjb3JkIENTQVQgc2NvcmUgZnJvbSBzdXJ2ZXkgc3lzdGVtXG4gICAqIGF3YWl0IGJ1c2luZXNzTWV0cmljcy5yZWNvcmQoJ2FnZW50XzEyMycsIHtcbiAgICogICBtZXRyaWNOYW1lOiAnQ1NBVC9OUFMnLFxuICAgKiAgIHZhbHVlOiA0LjUsXG4gICAqICAgdW5pdDogJ3Njb3JlJyxcbiAgICogICBwZXJpb2RTdGFydDogJzIwMjQtMDEtMDFUMDA6MDA6MDBaJyxcbiAgICogICBwZXJpb2RFbmQ6ICcyMDI0LTAxLTA3VDIzOjU5OjU5WicsXG4gICAqICAgc291cmNlOiAnc3VydmV5X3N5c3RlbScsXG4gICAqICAgc291cmNlRGV0YWlsczogeyBzdXJ2ZXlJZDogJ3N1cnZleV80NTYnLCByZXNwb25zZUNvdW50OiAxNTAgfSxcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgcmVjb3JkKFxuICAgIGFnZW50SWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiBSZWNvcmRNZXRyaWNPcHRpb25zXG4gICk6IFByb21pc2U8UmVjb3JkTWV0cmljUmVzcG9uc2U+IHtcbiAgICBjb25zdCBib2R5ID0ge1xuICAgICAgbWV0cmljTmFtZTogb3B0aW9ucy5tZXRyaWNOYW1lLFxuICAgICAgdmFsdWU6IG9wdGlvbnMudmFsdWUsXG4gICAgICB1bml0OiBvcHRpb25zLnVuaXQsXG4gICAgICBwZXJpb2RTdGFydDogbmV3IERhdGUob3B0aW9ucy5wZXJpb2RTdGFydCkudG9JU09TdHJpbmcoKSxcbiAgICAgIHBlcmlvZEVuZDogbmV3IERhdGUob3B0aW9ucy5wZXJpb2RFbmQpLnRvSVNPU3RyaW5nKCksXG4gICAgICBzb3VyY2U6IG9wdGlvbnMuc291cmNlIHx8ICdhcGknLFxuICAgICAgc291cmNlRGV0YWlsczogb3B0aW9ucy5zb3VyY2VEZXRhaWxzLFxuICAgIH07XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGFwaVJlcXVlc3Q8QXBpUmVzcG9uc2U8UmVjb3JkTWV0cmljUmVzcG9uc2U+PihcbiAgICAgIGAvYWdlbnRzLyR7YWdlbnRJZH0vbWV0cmljcy92YWx1ZXNgLFxuICAgICAge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgYm9keSxcbiAgICAgICAgYXBpVmVyc2lvbjogJ3YzJyxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgcmV0dXJuIHJlc3BvbnNlLmRhdGEhO1xuICB9LFxuXG4gIC8qKlxuICAgKiBCYXRjaCByZWNvcmQgbXVsdGlwbGUgZXh0ZXJuYWwgbWV0cmljIHZhbHVlc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGF3YWl0IGJ1c2luZXNzTWV0cmljcy5yZWNvcmRCYXRjaCgnYWdlbnRfMTIzJywgW1xuICAgKiAgIHsgbWV0cmljTmFtZTogJ0NTQVQvTlBTJywgdmFsdWU6IDQuNSwgLi4uIH0sXG4gICAqICAgeyBtZXRyaWNOYW1lOiAnSG91cnMgU2F2ZWQnLCB2YWx1ZTogMTIwLCAuLi4gfSxcbiAgICogXSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgcmVjb3JkQmF0Y2goXG4gICAgYWdlbnRJZDogc3RyaW5nLFxuICAgIG1ldHJpY3M6IFJlY29yZE1ldHJpY09wdGlvbnNbXVxuICApOiBQcm9taXNlPFJlY29yZE1ldHJpY1Jlc3BvbnNlW10+IHtcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtZXRyaWNzLm1hcCgobWV0cmljKSA9PiB0aGlzLnJlY29yZChhZ2VudElkLCBtZXRyaWMpKVxuICAgICk7XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH0sXG59O1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBIRUxQRVIgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ2hlY2sgaWYgYSBtZXRyaWMgaXMgcmVhZHkgdG8gZGlzcGxheVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNNZXRyaWNSZWFkeShtZXRyaWM6IEN1cnJlbnRNZXRyaWNSZXNwb25zZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbWV0cmljLnN0YXR1cyA9PT0gJ3JlYWR5Jztcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIG1ldHJpYyBuZWVkcyBtb3JlIHRyYWNlIGRhdGFcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5lZWRzTW9yZVRyYWNlcyhtZXRyaWM6IEN1cnJlbnRNZXRyaWNSZXNwb25zZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbWV0cmljLnN0YXR1cyA9PT0gJ2luc3VmZmljaWVudF9kYXRhJztcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIG1ldHJpYyBpcyB3YWl0aW5nIGZvciBleHRlcm5hbCBkYXRhXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhd2FpdGluZ0V4dGVybmFsRGF0YShtZXRyaWM6IEN1cnJlbnRNZXRyaWNSZXNwb25zZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbWV0cmljLnN0YXR1cyA9PT0gJ2F3YWl0aW5nX2V4dGVybmFsJztcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBtZXRyaWMgZGF0YSBpcyBzdGFsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNNZXRyaWNTdGFsZShtZXRyaWM6IEN1cnJlbnRNZXRyaWNSZXNwb25zZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbWV0cmljLnN0YXR1cyA9PT0gJ3N0YWxlJztcbn1cblxuLyoqXG4gKiBHZXQgaHVtYW4tcmVhZGFibGUgc3RhdHVzIG1lc3NhZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFN0YXR1c01lc3NhZ2UobWV0cmljOiBDdXJyZW50TWV0cmljUmVzcG9uc2UpOiBzdHJpbmcge1xuICBzd2l0Y2ggKG1ldHJpYy5zdGF0dXMpIHtcbiAgICBjYXNlICdyZWFkeSc6XG4gICAgICByZXR1cm4gJ01ldHJpYyBpcyB1cCB0byBkYXRlJztcbiAgICBjYXNlICdpbnN1ZmZpY2llbnRfZGF0YSc6XG4gICAgICByZXR1cm4gbWV0cmljLnN0YXR1c01lc3NhZ2UgfHxcbiAgICAgICAgYE5lZWQgJHsobWV0cmljLm1pblRyYWNlVGhyZXNob2xkIHx8IDUwKSAtIChtZXRyaWMudHJhY2VDb3VudCB8fCAwKX0gbW9yZSB0cmFjZXNgO1xuICAgIGNhc2UgJ2F3YWl0aW5nX2V4dGVybmFsJzpcbiAgICAgIHJldHVybiBtZXRyaWMuc3RhdHVzTWVzc2FnZSB8fCAnV2FpdGluZyBmb3IgZXh0ZXJuYWwgZGF0YSBzb3VyY2UnO1xuICAgIGNhc2UgJ3N0YWxlJzpcbiAgICAgIHJldHVybiBtZXRyaWMuc3RhdHVzTWVzc2FnZSB8fCAnRGF0YSBtYXkgYmUgb3V0ZGF0ZWQnO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gJ1Vua25vd24gc3RhdHVzJztcbiAgfVxufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBwcm9ncmVzcyB0b3dhcmQgbWluaW11bSB0cmFjZSB0aHJlc2hvbGRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRyYWNlUHJvZ3Jlc3MobWV0cmljOiBDdXJyZW50TWV0cmljUmVzcG9uc2UpOiBudW1iZXIge1xuICBpZiAobWV0cmljLnN0YXR1cyAhPT0gJ2luc3VmZmljaWVudF9kYXRhJykgcmV0dXJuIDEwMDtcbiAgcmV0dXJuIG1ldHJpYy5wcm9ncmVzc1BlcmNlbnQgfHwgMDtcbn1cblxuLyoqXG4gKiBGb3JtYXQgbWV0cmljIHZhbHVlIGZvciBkaXNwbGF5IGJhc2VkIG9uIHVuaXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdE1ldHJpY1ZhbHVlKHZhbHVlOiBudW1iZXIsIHVuaXQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHN3aXRjaCAodW5pdCkge1xuICAgIGNhc2UgJyUnOlxuICAgICAgcmV0dXJuIGAke01hdGgucm91bmQodmFsdWUgKiAxMCkgLyAxMH0lYDtcbiAgICBjYXNlICckJzpcbiAgICAgIHJldHVybiBuZXcgSW50bC5OdW1iZXJGb3JtYXQoJ2VuLVVTJywge1xuICAgICAgICBzdHlsZTogJ2N1cnJlbmN5JyxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgfSkuZm9ybWF0KHZhbHVlKTtcbiAgICBjYXNlICdzJzpcbiAgICAgIHJldHVybiB2YWx1ZSA8IDYwID8gYCR7TWF0aC5yb3VuZCh2YWx1ZSl9c2AgOiBgJHtNYXRoLnJvdW5kKHZhbHVlIC8gNjApfW1gO1xuICAgIGNhc2UgJ2hycyc6XG4gICAgICByZXR1cm4gYCR7TWF0aC5yb3VuZCh2YWx1ZSAqIDEwKSAvIDEwfSBocnNgO1xuICAgIGNhc2UgJ3Njb3JlJzpcbiAgICAgIHJldHVybiB2YWx1ZS50b0ZpeGVkKDEpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gU3RyaW5nKE1hdGgucm91bmQodmFsdWUgKiAxMDApIC8gMTAwKTtcbiAgfVxufVxuXG4vKipcbiAqIEdldCB0cmVuZCBkaXJlY3Rpb24gYXMgZW1vamlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRyZW5kRW1vamkodHJlbmQ6IE1ldHJpY1RyZW5kKTogc3RyaW5nIHtcbiAgaWYgKHRyZW5kLmRpcmVjdGlvbiA9PT0gJ3VwJykgcmV0dXJuIHRyZW5kLmlzUG9zaXRpdmUgPyAn8J+TiCcgOiAn8J+TiSc7XG4gIGlmICh0cmVuZC5kaXJlY3Rpb24gPT09ICdkb3duJykgcmV0dXJuIHRyZW5kLmlzUG9zaXRpdmUgPyAn8J+TiCcgOiAn8J+TiSc7XG4gIHJldHVybiAn4p6h77iPJztcbn1cbiJdfQ==
@@ -0,0 +1,200 @@
1
+ /**
2
+ * ThinkHive SDK v3.0 - Conversation Evaluation API
3
+ *
4
+ * API for multi-turn conversation evaluation
5
+ */
6
+ export type AggregateMethod = 'worst' | 'average' | 'weighted' | 'final_turn' | 'majority';
7
+ export interface SessionTrace {
8
+ id: string;
9
+ sessionId: string;
10
+ turnNumber: number;
11
+ userMessage: string;
12
+ agentResponse: string;
13
+ timestamp: string;
14
+ metadata?: Record<string, unknown>;
15
+ }
16
+ export interface TurnEvaluation {
17
+ traceId: string;
18
+ turnNumber: number;
19
+ passed: boolean;
20
+ score: number;
21
+ reasoning: string;
22
+ }
23
+ export interface ConversationEvalResult {
24
+ sessionId: string;
25
+ criterionId: string;
26
+ turnCount: number;
27
+ turnResults: TurnEvaluation[];
28
+ aggregatePassed: boolean;
29
+ aggregateScore: number;
30
+ aggregateMethod: AggregateMethod;
31
+ reasoning: string;
32
+ metadata?: Record<string, unknown>;
33
+ }
34
+ export interface EvaluateConversationOptions {
35
+ sessionId: string;
36
+ criterionId: string;
37
+ options?: {
38
+ aggregateMethod?: AggregateMethod;
39
+ minTurns?: number;
40
+ maxTurns?: number;
41
+ };
42
+ }
43
+ export interface AggregationMethodInfo {
44
+ id: AggregateMethod;
45
+ name: string;
46
+ description: string;
47
+ useCase: string;
48
+ }
49
+ /**
50
+ * Conversation Evaluation API client for multi-turn evaluation
51
+ */
52
+ export declare const conversationEval: {
53
+ /**
54
+ * Get traces for a conversation session
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const traces = await conversationEval.getSessionTraces('session_123');
59
+ * console.log(`Conversation has ${traces.length} turns`);
60
+ * ```
61
+ */
62
+ getSessionTraces(sessionId: string): Promise<SessionTrace[]>;
63
+ /**
64
+ * Run conversation-level evaluation
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const result = await conversationEval.evaluate({
69
+ * sessionId: 'session_123',
70
+ * criterionId: 'criterion_456',
71
+ * options: {
72
+ * aggregateMethod: 'average',
73
+ * minTurns: 2,
74
+ * },
75
+ * });
76
+ * console.log(`Conversation score: ${result.aggregateScore}`);
77
+ * ```
78
+ */
79
+ evaluate(options: EvaluateConversationOptions): Promise<ConversationEvalResult>;
80
+ /**
81
+ * Get available aggregation methods with descriptions
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const methods = await conversationEval.getAggregationMethods();
86
+ * for (const method of methods) {
87
+ * console.log(`${method.name}: ${method.description}`);
88
+ * }
89
+ * ```
90
+ */
91
+ getAggregationMethods(): Promise<AggregationMethodInfo[]>;
92
+ };
93
+ /**
94
+ * Calculate worst-turn aggregation
95
+ *
96
+ * @param turnResults - Array of turn evaluation results
97
+ * @returns Aggregated result using worst turn logic
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const result = aggregateWorst(turnResults);
102
+ * // Fails if any turn fails
103
+ * ```
104
+ */
105
+ export declare function aggregateWorst(turnResults: TurnEvaluation[]): {
106
+ passed: boolean;
107
+ score: number;
108
+ };
109
+ /**
110
+ * Calculate average aggregation
111
+ *
112
+ * @param turnResults - Array of turn evaluation results
113
+ * @returns Aggregated result using average logic
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const result = aggregateAverage(turnResults);
118
+ * ```
119
+ */
120
+ export declare function aggregateAverage(turnResults: TurnEvaluation[]): {
121
+ passed: boolean;
122
+ score: number;
123
+ };
124
+ /**
125
+ * Calculate weighted average aggregation (later turns weighted more)
126
+ *
127
+ * @param turnResults - Array of turn evaluation results
128
+ * @returns Aggregated result using weighted average logic
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const result = aggregateWeighted(turnResults);
133
+ * // Later turns have higher weight
134
+ * ```
135
+ */
136
+ export declare function aggregateWeighted(turnResults: TurnEvaluation[]): {
137
+ passed: boolean;
138
+ score: number;
139
+ };
140
+ /**
141
+ * Calculate final-turn aggregation
142
+ *
143
+ * @param turnResults - Array of turn evaluation results
144
+ * @returns Aggregated result using only the final turn
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * const result = aggregateFinalTurn(turnResults);
149
+ * // Only final turn matters
150
+ * ```
151
+ */
152
+ export declare function aggregateFinalTurn(turnResults: TurnEvaluation[]): {
153
+ passed: boolean;
154
+ score: number;
155
+ };
156
+ /**
157
+ * Calculate majority vote aggregation
158
+ *
159
+ * @param turnResults - Array of turn evaluation results
160
+ * @returns Aggregated result using majority vote logic
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const result = aggregateMajority(turnResults);
165
+ * // Passes if majority of turns pass
166
+ * ```
167
+ */
168
+ export declare function aggregateMajority(turnResults: TurnEvaluation[]): {
169
+ passed: boolean;
170
+ score: number;
171
+ };
172
+ /**
173
+ * Get appropriate aggregation function for a method
174
+ *
175
+ * @param method - Aggregation method name
176
+ * @returns Aggregation function
177
+ */
178
+ export declare function getAggregator(method: AggregateMethod): (turnResults: TurnEvaluation[]) => {
179
+ passed: boolean;
180
+ score: number;
181
+ };
182
+ /**
183
+ * Find problematic turns in a conversation
184
+ *
185
+ * @param result - Conversation evaluation result
186
+ * @param scoreThreshold - Minimum acceptable score (default 70)
187
+ * @returns Array of problematic turn results
188
+ */
189
+ export declare function getProblematicTurns(result: ConversationEvalResult, scoreThreshold?: number): TurnEvaluation[];
190
+ /**
191
+ * Calculate conversation quality trend
192
+ *
193
+ * @param result - Conversation evaluation result
194
+ * @returns Trend analysis
195
+ */
196
+ export declare function analyzeConversationTrend(result: ConversationEvalResult): {
197
+ direction: 'improving' | 'declining' | 'stable';
198
+ firstHalfAvg: number;
199
+ secondHalfAvg: number;
200
+ };