@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.
- package/README.md +279 -128
- package/dist/api/apiKeys.d.ts +252 -0
- package/dist/api/apiKeys.js +298 -0
- package/dist/api/business-metrics.d.ts +188 -0
- package/dist/api/business-metrics.js +213 -0
- package/dist/api/conversation-eval.d.ts +200 -0
- package/dist/api/conversation-eval.js +235 -0
- package/dist/api/deterministic-graders.d.ts +205 -0
- package/dist/api/deterministic-graders.js +191 -0
- package/dist/api/eval-health.d.ts +250 -0
- package/dist/api/eval-health.js +224 -0
- package/dist/api/human-review.d.ts +275 -0
- package/dist/api/human-review.js +236 -0
- package/dist/api/nondeterminism.d.ts +300 -0
- package/dist/api/nondeterminism.js +250 -0
- package/dist/api/quality-metrics.d.ts +303 -0
- package/dist/api/quality-metrics.js +198 -0
- package/dist/api/roi-analytics.d.ts +263 -0
- package/dist/api/roi-analytics.js +204 -0
- package/dist/api/transcript-patterns.d.ts +204 -0
- package/dist/api/transcript-patterns.js +227 -0
- package/dist/core/client.d.ts +82 -8
- package/dist/core/client.js +223 -32
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +2 -2
- package/dist/core/types.d.ts +27 -2
- package/dist/core/types.js +1 -1
- package/dist/index.d.ts +415 -62
- package/dist/index.js +253 -37
- package/package.json +8 -4
|
@@ -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
|
+
};
|