@thinkhive/sdk 2.0.1 → 3.0.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,274 @@
1
+ "use strict";
2
+ /**
3
+ * ThinkHive SDK v3.0 - Customer Context
4
+ *
5
+ * Time-series customer metrics snapshots
6
+ * Captures ARR, health score, segment AS OF the run time (not current values)
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.customerContext = void 0;
10
+ exports.toContextSnapshot = toContextSnapshot;
11
+ exports.captureCustomerContext = captureCustomerContext;
12
+ exports.getContextAsOf = getContextAsOf;
13
+ exports.calculateArrChange = calculateArrChange;
14
+ exports.calculateHealthTrend = calculateHealthTrend;
15
+ const client_1 = require("../core/client");
16
+ // ============================================================================
17
+ // CUSTOMER CONTEXT API
18
+ // ============================================================================
19
+ /**
20
+ * Customer context API client for time-series metrics
21
+ */
22
+ exports.customerContext = {
23
+ /**
24
+ * Create a customer account
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const account = await customerContext.createAccount({
29
+ * name: 'Acme Corp',
30
+ * externalId: 'sf_001234',
31
+ * externalSource: 'salesforce',
32
+ * segment: 'enterprise',
33
+ * });
34
+ * ```
35
+ */
36
+ async createAccount(input) {
37
+ return (0, client_1.apiRequestWithData)('/customers', {
38
+ method: 'POST',
39
+ body: input,
40
+ });
41
+ },
42
+ /**
43
+ * Get a customer account by ID
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const account = await customerContext.getAccount('cust_abc123');
48
+ * ```
49
+ */
50
+ async getAccount(customerId) {
51
+ return (0, client_1.apiRequestWithData)(`/customers/${customerId}`);
52
+ },
53
+ /**
54
+ * Get a customer account by external ID
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const account = await customerContext.getAccountByExternalId(
59
+ * 'sf_001234',
60
+ * 'salesforce'
61
+ * );
62
+ * ```
63
+ */
64
+ async getAccountByExternalId(externalId, source) {
65
+ try {
66
+ return await (0, client_1.apiRequestWithData)(`/customers/external/${source}/${externalId}`);
67
+ }
68
+ catch (error) {
69
+ if (error?.statusCode === 404) {
70
+ return null;
71
+ }
72
+ throw error;
73
+ }
74
+ },
75
+ /**
76
+ * Capture a metrics snapshot for a customer
77
+ * This creates a point-in-time record of the customer's metrics
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Capture current metrics
82
+ * const snapshot = await customerContext.captureSnapshot('cust_abc123', {
83
+ * arr: 120000,
84
+ * healthScore: 85,
85
+ * nps: 45,
86
+ * segment: 'enterprise',
87
+ * });
88
+ *
89
+ * // Use this snapshot in a run
90
+ * const run = await runs.create({
91
+ * agentId: 'agent_123',
92
+ * customerContext: {
93
+ * customerId: 'cust_abc123',
94
+ * arr: snapshot.arr,
95
+ * healthScore: snapshot.healthScore,
96
+ * capturedAt: snapshot.capturedAt,
97
+ * },
98
+ * // ...
99
+ * });
100
+ * ```
101
+ */
102
+ async captureSnapshot(customerId, metrics) {
103
+ return (0, client_1.apiRequestWithData)(`/customers/${customerId}/snapshots`, {
104
+ method: 'POST',
105
+ body: {
106
+ ...metrics,
107
+ capturedAt: new Date().toISOString(),
108
+ },
109
+ });
110
+ },
111
+ /**
112
+ * Get metrics snapshots for a customer (time-series)
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // Get last 30 days of snapshots
117
+ * const snapshots = await customerContext.getSnapshots('cust_abc123', {
118
+ * from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(),
119
+ * });
120
+ * ```
121
+ */
122
+ async getSnapshots(customerId, options = {}) {
123
+ const params = new URLSearchParams();
124
+ if (options.from)
125
+ params.set('from', options.from);
126
+ if (options.to)
127
+ params.set('to', options.to);
128
+ if (options.limit)
129
+ params.set('limit', String(options.limit));
130
+ return (0, client_1.apiRequestWithData)(`/customers/${customerId}/snapshots?${params.toString()}`);
131
+ },
132
+ /**
133
+ * Get the most recent snapshot for a customer
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const latest = await customerContext.getLatestSnapshot('cust_abc123');
138
+ * ```
139
+ */
140
+ async getLatestSnapshot(customerId) {
141
+ try {
142
+ return await (0, client_1.apiRequestWithData)(`/customers/${customerId}/snapshots/latest`);
143
+ }
144
+ catch (error) {
145
+ if (error?.statusCode === 404) {
146
+ return null;
147
+ }
148
+ throw error;
149
+ }
150
+ },
151
+ /**
152
+ * Get snapshot closest to a specific timestamp
153
+ * Useful for retroactive analysis
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * // Get metrics as of a specific date
158
+ * const snapshot = await customerContext.getSnapshotAsOf(
159
+ * 'cust_abc123',
160
+ * '2024-01-15T10:00:00Z'
161
+ * );
162
+ * ```
163
+ */
164
+ async getSnapshotAsOf(customerId, timestamp) {
165
+ const ts = new Date(timestamp).toISOString();
166
+ try {
167
+ return await (0, client_1.apiRequestWithData)(`/customers/${customerId}/snapshots/as-of?timestamp=${encodeURIComponent(ts)}`);
168
+ }
169
+ catch (error) {
170
+ if (error?.statusCode === 404) {
171
+ return null;
172
+ }
173
+ throw error;
174
+ }
175
+ },
176
+ };
177
+ // ============================================================================
178
+ // HELPER FUNCTIONS
179
+ // ============================================================================
180
+ /**
181
+ * Create a CustomerContextSnapshot from a metrics snapshot
182
+ */
183
+ function toContextSnapshot(snapshot) {
184
+ return {
185
+ customerId: snapshot.customerAccountId,
186
+ arr: snapshot.arr,
187
+ healthScore: snapshot.healthScore,
188
+ segment: snapshot.segment,
189
+ capturedAt: snapshot.capturedAt,
190
+ };
191
+ }
192
+ /**
193
+ * Capture metrics and create context snapshot in one call
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const context = await captureCustomerContext('cust_abc123', {
198
+ * arr: 100000,
199
+ * healthScore: 90,
200
+ * segment: 'enterprise',
201
+ * });
202
+ *
203
+ * // Use in run
204
+ * const run = await runs.create({
205
+ * agentId: 'agent_123',
206
+ * customerContext: context,
207
+ * // ...
208
+ * });
209
+ * ```
210
+ */
211
+ async function captureCustomerContext(customerId, metrics) {
212
+ const snapshot = await exports.customerContext.captureSnapshot(customerId, metrics);
213
+ return toContextSnapshot(snapshot);
214
+ }
215
+ /**
216
+ * Get customer context as of a specific time
217
+ */
218
+ async function getContextAsOf(customerId, timestamp) {
219
+ const snapshot = await exports.customerContext.getSnapshotAsOf(customerId, timestamp);
220
+ return snapshot ? toContextSnapshot(snapshot) : null;
221
+ }
222
+ /**
223
+ * Calculate ARR change between two snapshots
224
+ */
225
+ function calculateArrChange(older, newer) {
226
+ const oldArr = older.arr || 0;
227
+ const newArr = newer.arr || 0;
228
+ const absolute = newArr - oldArr;
229
+ const percentage = oldArr > 0 ? (absolute / oldArr) * 100 : 0;
230
+ return {
231
+ absolute,
232
+ percentage,
233
+ direction: absolute > 0 ? 'increase' : absolute < 0 ? 'decrease' : 'stable',
234
+ };
235
+ }
236
+ /**
237
+ * Calculate health score trend
238
+ */
239
+ function calculateHealthTrend(snapshots) {
240
+ const scores = snapshots
241
+ .filter((s) => s.healthScore !== undefined && s.healthScore !== null)
242
+ .map((s) => s.healthScore);
243
+ if (scores.length === 0) {
244
+ return {
245
+ currentScore: null,
246
+ avgScore: null,
247
+ trend: 'stable',
248
+ volatility: 'low',
249
+ };
250
+ }
251
+ const currentScore = scores[0];
252
+ const avgScore = scores.reduce((a, b) => a + b, 0) / scores.length;
253
+ // Calculate trend (simple linear regression direction)
254
+ let trend = 'stable';
255
+ if (scores.length >= 2) {
256
+ const recentAvg = scores.slice(0, Math.ceil(scores.length / 2)).reduce((a, b) => a + b, 0) / Math.ceil(scores.length / 2);
257
+ const olderAvg = scores.slice(Math.ceil(scores.length / 2)).reduce((a, b) => a + b, 0) / Math.floor(scores.length / 2);
258
+ if (recentAvg - olderAvg > 5)
259
+ trend = 'improving';
260
+ else if (olderAvg - recentAvg > 5)
261
+ trend = 'declining';
262
+ }
263
+ // Calculate volatility (standard deviation)
264
+ const variance = scores.reduce((acc, s) => acc + Math.pow(s - avgScore, 2), 0) / scores.length;
265
+ const stdDev = Math.sqrt(variance);
266
+ const volatility = stdDev < 5 ? 'low' : stdDev < 15 ? 'medium' : 'high';
267
+ return {
268
+ currentScore,
269
+ avgScore,
270
+ trend,
271
+ volatility,
272
+ };
273
+ }
274
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbnRlZ3JhdGlvbnMvY3VzdG9tZXItY29udGV4dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7O0dBS0c7OztBQTJQSCw4Q0FVQztBQXFCRCx3REFVQztBQUtELHdDQU1DO0FBS0QsZ0RBa0JDO0FBS0Qsb0RBNENDO0FBclhELDJDQUFnRTtBQWtDaEUsK0VBQStFO0FBQy9FLHVCQUF1QjtBQUN2QiwrRUFBK0U7QUFFL0U7O0dBRUc7QUFDVSxRQUFBLGVBQWUsR0FBRztJQUM3Qjs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxLQUFLLENBQUMsYUFBYSxDQUFDLEtBUW5CO1FBQ0MsT0FBTyxJQUFBLDJCQUFrQixFQUFrQixZQUFZLEVBQUU7WUFDdkQsTUFBTSxFQUFFLE1BQU07WUFDZCxJQUFJLEVBQUUsS0FBSztTQUNaLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLFVBQVUsQ0FBQyxVQUFrQjtRQUNqQyxPQUFPLElBQUEsMkJBQWtCLEVBQWtCLGNBQWMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNILEtBQUssQ0FBQyxzQkFBc0IsQ0FDMUIsVUFBa0IsRUFDbEIsTUFBeUM7UUFFekMsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLElBQUEsMkJBQWtCLEVBQzdCLHVCQUF1QixNQUFNLElBQUksVUFBVSxFQUFFLENBQzlDLENBQUM7UUFDSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUssS0FBYSxFQUFFLFVBQVUsS0FBSyxHQUFHLEVBQUUsQ0FBQztnQkFDdkMsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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RSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDdkgsSUFBSSxTQUFTLEdBQUcsUUFBUSxHQUFHLENBQUM7WUFBRSxLQUFLLEdBQUcsV0FBVyxDQUFDO2FBQzdDLElBQUksUUFBUSxHQUFHLFNBQVMsR0FBRyxDQUFDO1lBQUUsS0FBSyxHQUFHLFdBQVcsQ0FBQztJQUN6RCxDQUFDO0lBRUQsNENBQTRDO0lBQzVDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsUUFBUSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDL0YsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNuQyxNQUFNLFVBQVUsR0FBRyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBRXhFLE9BQU87UUFDTCxZQUFZO1FBQ1osUUFBUTtRQUNSLEtBQUs7UUFDTCxVQUFVO0tBQ1gsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoaW5rSGl2ZSBTREsgdjMuMCAtIEN1c3RvbWVyIENvbnRleHRcbiAqXG4gKiBUaW1lLXNlcmllcyBjdXN0b21lciBtZXRyaWNzIHNuYXBzaG90c1xuICogQ2FwdHVyZXMgQVJSLCBoZWFsdGggc2NvcmUsIHNlZ21lbnQgQVMgT0YgdGhlIHJ1biB0aW1lIChub3QgY3VycmVudCB2YWx1ZXMpXG4gKi9cblxuaW1wb3J0IHsgYXBpUmVxdWVzdCwgYXBpUmVxdWVzdFdpdGhEYXRhIH0gZnJvbSAnLi4vY29yZS9jbGllbnQnO1xuaW1wb3J0IHR5cGUgeyBDdXN0b21lckNvbnRleHRTbmFwc2hvdCB9IGZyb20gJy4uL2NvcmUvdHlwZXMnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBDVVNUT01FUiBBQ0NPVU5UIFRZUEVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tZXJBY2NvdW50IHtcbiAgaWQ6IHN0cmluZztcbiAgY29tcGFueUlkOiBzdHJpbmc7XG4gIGV4dGVybmFsSWQ/OiBzdHJpbmc7XG4gIGV4dGVybmFsU291cmNlPzogJ3NhbGVzZm9yY2UnIHwgJ2h1YnNwb3QnIHwgJ3plbmRlc2snIHwgJ2ludGVyY29tJyB8ICdjdXN0b20nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGRvbWFpbj86IHN0cmluZztcbiAgc2VnbWVudD86IHN0cmluZztcbiAgaW5kdXN0cnk/OiBzdHJpbmc7XG4gIGVtcGxveWVlQ291bnQ/OiBudW1iZXI7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICB1cGRhdGVkQXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDdXN0b21lck1ldHJpY3NTbmFwc2hvdCB7XG4gIGlkOiBzdHJpbmc7XG4gIGN1c3RvbWVyQWNjb3VudElkOiBzdHJpbmc7XG4gIGFycj86IG51bWJlcjtcbiAgaGVhbHRoU2NvcmU/OiBudW1iZXI7XG4gIG5wcz86IG51bWJlcjtcbiAgc2VnbWVudD86IHN0cmluZztcbiAgY2h1cm5SaXNrPzogJ2xvdycgfCAnbWVkaXVtJyB8ICdoaWdoJztcbiAgY2FwdHVyZWRBdDogc3RyaW5nO1xuICBzb3VyY2U/OiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBDVVNUT01FUiBDT05URVhUIEFQSVxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEN1c3RvbWVyIGNvbnRleHQgQVBJIGNsaWVudCBmb3IgdGltZS1zZXJpZXMgbWV0cmljc1xuICovXG5leHBvcnQgY29uc3QgY3VzdG9tZXJDb250ZXh0ID0ge1xuICAvKipcbiAgICogQ3JlYXRlIGEgY3VzdG9tZXIgYWNjb3VudFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGFjY291bnQgPSBhd2FpdCBjdXN0b21lckNvbnRleHQuY3JlYXRlQWNjb3VudCh7XG4gICAqICAgbmFtZTogJ0FjbWUgQ29ycCcsXG4gICAqICAgZXh0ZXJuYWxJZDogJ3NmXzAwMTIzNCcsXG4gICAqICAgZXh0ZXJuYWxTb3VyY2U6ICdzYWxlc2ZvcmNlJyxcbiAgICogICBzZWdtZW50OiAnZW50ZXJwcmlzZScsXG4gICAqIH0pO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGNyZWF0ZUFjY291bnQoaW5wdXQ6IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgZXh0ZXJuYWxJZD86IHN0cmluZztcbiAgICBleHRlcm5hbFNvdXJjZT86IEN1c3RvbWVyQWNjb3VudFsnZXh0ZXJuYWxTb3VyY2UnXTtcbiAgICBkb21haW4/OiBzdHJpbmc7XG4gICAgc2VnbWVudD86IHN0cmluZztcbiAgICBpbmR1c3RyeT86IHN0cmluZztcbiAgICBlbXBsb3llZUNvdW50PzogbnVtYmVyO1xuICB9KTogUHJvbWlzZTxDdXN0b21lckFjY291bnQ+IHtcbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEN1c3RvbWVyQWNjb3VudD4oJy9jdXN0b21lcnMnLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGJvZHk6IGlucHV0LFxuICAgIH0pO1xuICB9LFxuXG4gIC8qKlxuICAgKiBHZXQgYSBjdXN0b21lciBhY2NvdW50IGJ5IElEXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgYWNjb3VudCA9IGF3YWl0IGN1c3RvbWVyQ29udGV4dC5nZXRBY2NvdW50KCdjdXN0X2FiYzEyMycpO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldEFjY291bnQoY3VzdG9tZXJJZDogc3RyaW5nKTogUHJvbWlzZTxDdXN0b21lckFjY291bnQ+IHtcbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEN1c3RvbWVyQWNjb3VudD4oYC9jdXN0b21lcnMvJHtjdXN0b21lcklkfWApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBHZXQgYSBjdXN0b21lciBhY2NvdW50IGJ5IGV4dGVybmFsIElEXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgYWNjb3VudCA9IGF3YWl0IGN1c3RvbWVyQ29udGV4dC5nZXRBY2NvdW50QnlFeHRlcm5hbElkKFxuICAgKiAgICdzZl8wMDEyMzQnLFxuICAgKiAgICdzYWxlc2ZvcmNlJ1xuICAgKiApO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldEFjY291bnRCeUV4dGVybmFsSWQoXG4gICAgZXh0ZXJuYWxJZDogc3RyaW5nLFxuICAgIHNvdXJjZTogQ3VzdG9tZXJBY2NvdW50WydleHRlcm5hbFNvdXJjZSddXG4gICk6IFByb21pc2U8Q3VzdG9tZXJBY2NvdW50IHwgbnVsbD4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgYXBpUmVxdWVzdFdpdGhEYXRhPEN1c3RvbWVyQWNjb3VudD4oXG4gICAgICAgIGAvY3VzdG9tZXJzL2V4dGVybmFsLyR7c291cmNlfS8ke2V4dGVybmFsSWR9YFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKChlcnJvciBhcyBhbnkpPy5zdGF0dXNDb2RlID09PSA0MDQpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIENhcHR1cmUgYSBtZXRyaWNzIHNuYXBzaG90IGZvciBhIGN1c3RvbWVyXG4gICAqIFRoaXMgY3JlYXRlcyBhIHBvaW50LWluLXRpbWUgcmVjb3JkIG9mIHRoZSBjdXN0b21lcidzIG1ldHJpY3NcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBDYXB0dXJlIGN1cnJlbnQgbWV0cmljc1xuICAgKiBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGN1c3RvbWVyQ29udGV4dC5jYXB0dXJlU25hcHNob3QoJ2N1c3RfYWJjMTIzJywge1xuICAgKiAgIGFycjogMTIwMDAwLFxuICAgKiAgIGhlYWx0aFNjb3JlOiA4NSxcbiAgICogICBucHM6IDQ1LFxuICAgKiAgIHNlZ21lbnQ6ICdlbnRlcnByaXNlJyxcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIFVzZSB0aGlzIHNuYXBzaG90IGluIGEgcnVuXG4gICAqIGNvbnN0IHJ1biA9IGF3YWl0IHJ1bnMuY3JlYXRlKHtcbiAgICogICBhZ2VudElkOiAnYWdlbnRfMTIzJyxcbiAgICogICBjdXN0b21lckNvbnRleHQ6IHtcbiAgICogICAgIGN1c3RvbWVySWQ6ICdjdXN0X2FiYzEyMycsXG4gICAqICAgICBhcnI6IHNuYXBzaG90LmFycixcbiAgICogICAgIGhlYWx0aFNjb3JlOiBzbmFwc2hvdC5oZWFsdGhTY29yZSxcbiAgICogICAgIGNhcHR1cmVkQXQ6IHNuYXBzaG90LmNhcHR1cmVkQXQsXG4gICAqICAgfSxcbiAgICogICAvLyAuLi5cbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgY2FwdHVyZVNuYXBzaG90KFxuICAgIGN1c3RvbWVySWQ6IHN0cmluZyxcbiAgICBtZXRyaWNzOiB7XG4gICAgICBhcnI/OiBudW1iZXI7XG4gICAgICBoZWFsdGhTY29yZT86IG51bWJlcjtcbiAgICAgIG5wcz86IG51bWJlcjtcbiAgICAgIHNlZ21lbnQ/OiBzdHJpbmc7XG4gICAgICBjaHVyblJpc2s/OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnO1xuICAgICAgc291cmNlPzogc3RyaW5nO1xuICAgIH1cbiAgKTogUHJvbWlzZTxDdXN0b21lck1ldHJpY3NTbmFwc2hvdD4ge1xuICAgIHJldHVybiBhcGlSZXF1ZXN0V2l0aERhdGE8Q3VzdG9tZXJNZXRyaWNzU25hcHNob3Q+KFxuICAgICAgYC9jdXN0b21lcnMvJHtjdXN0b21lcklkfS9zbmFwc2hvdHNgLFxuICAgICAge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgYm9keToge1xuICAgICAgICAgIC4uLm1ldHJpY3MsXG4gICAgICAgICAgY2FwdHVyZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICB9LFxuICAgICAgfVxuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEdldCBtZXRyaWNzIHNuYXBzaG90cyBmb3IgYSBjdXN0b21lciAodGltZS1zZXJpZXMpXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gR2V0IGxhc3QgMzAgZGF5cyBvZiBzbmFwc2hvdHNcbiAgICogY29uc3Qgc25hcHNob3RzID0gYXdhaXQgY3VzdG9tZXJDb250ZXh0LmdldFNuYXBzaG90cygnY3VzdF9hYmMxMjMnLCB7XG4gICAqICAgZnJvbTogbmV3IERhdGUoRGF0ZS5ub3coKSAtIDMwICogMjQgKiA2MCAqIDYwICogMTAwMCkudG9JU09TdHJpbmcoKSxcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0U25hcHNob3RzKFxuICAgIGN1c3RvbWVySWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7XG4gICAgICBmcm9tPzogc3RyaW5nO1xuICAgICAgdG8/OiBzdHJpbmc7XG4gICAgICBsaW1pdD86IG51bWJlcjtcbiAgICB9ID0ge31cbiAgKTogUHJvbWlzZTxDdXN0b21lck1ldHJpY3NTbmFwc2hvdFtdPiB7XG4gICAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcygpO1xuICAgIGlmIChvcHRpb25zLmZyb20pIHBhcmFtcy5zZXQoJ2Zyb20nLCBvcHRpb25zLmZyb20pO1xuICAgIGlmIChvcHRpb25zLnRvKSBwYXJhbXMuc2V0KCd0bycsIG9wdGlvbnMudG8pO1xuICAgIGlmIChvcHRpb25zLmxpbWl0KSBwYXJhbXMuc2V0KCdsaW1pdCcsIFN0cmluZyhvcHRpb25zLmxpbWl0KSk7XG5cbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEN1c3RvbWVyTWV0cmljc1NuYXBzaG90W10+KFxuICAgICAgYC9jdXN0b21lcnMvJHtjdXN0b21lcklkfS9zbmFwc2hvdHM/JHtwYXJhbXMudG9TdHJpbmcoKX1gXG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogR2V0IHRoZSBtb3N0IHJlY2VudCBzbmFwc2hvdCBmb3IgYSBjdXN0b21lclxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IGxhdGVzdCA9IGF3YWl0IGN1c3RvbWVyQ29udGV4dC5nZXRMYXRlc3RTbmFwc2hvdCgnY3VzdF9hYmMxMjMnKTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBnZXRMYXRlc3RTbmFwc2hvdChcbiAgICBjdXN0b21lcklkOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxDdXN0b21lck1ldHJpY3NTbmFwc2hvdCB8IG51bGw+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IGFwaVJlcXVlc3RXaXRoRGF0YTxDdXN0b21lck1ldHJpY3NTbmFwc2hvdD4oXG4gICAgICAgIGAvY3VzdG9tZXJzLyR7Y3VzdG9tZXJJZH0vc25hcHNob3RzL2xhdGVzdGBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgYW55KT8uc3RhdHVzQ29kZSA9PT0gNDA0KSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBHZXQgc25hcHNob3QgY2xvc2VzdCB0byBhIHNwZWNpZmljIHRpbWVzdGFtcFxuICAgKiBVc2VmdWwgZm9yIHJldHJvYWN0aXZlIGFuYWx5c2lzXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gR2V0IG1ldHJpY3MgYXMgb2YgYSBzcGVjaWZpYyBkYXRlXG4gICAqIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgY3VzdG9tZXJDb250ZXh0LmdldFNuYXBzaG90QXNPZihcbiAgICogICAnY3VzdF9hYmMxMjMnLFxuICAgKiAgICcyMDI0LTAxLTE1VDEwOjAwOjAwWidcbiAgICogKTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBnZXRTbmFwc2hvdEFzT2YoXG4gICAgY3VzdG9tZXJJZDogc3RyaW5nLFxuICAgIHRpbWVzdGFtcDogc3RyaW5nIHwgRGF0ZVxuICApOiBQcm9taXNlPEN1c3RvbWVyTWV0cmljc1NuYXBzaG90IHwgbnVsbD4ge1xuICAgIGNvbnN0IHRzID0gbmV3IERhdGUodGltZXN0YW1wKS50b0lTT1N0cmluZygpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgYXBpUmVxdWVzdFdpdGhEYXRhPEN1c3RvbWVyTWV0cmljc1NuYXBzaG90PihcbiAgICAgICAgYC9jdXN0b21lcnMvJHtjdXN0b21lcklkfS9zbmFwc2hvdHMvYXMtb2Y/dGltZXN0YW1wPSR7ZW5jb2RlVVJJQ29tcG9uZW50KHRzKX1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoKGVycm9yIGFzIGFueSk/LnN0YXR1c0NvZGUgPT09IDQwNCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfSxcbn07XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBDcmVhdGUgYSBDdXN0b21lckNvbnRleHRTbmFwc2hvdCBmcm9tIGEgbWV0cmljcyBzbmFwc2hvdFxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9Db250ZXh0U25hcHNob3QoXG4gIHNuYXBzaG90OiBDdXN0b21lck1ldHJpY3NTbmFwc2hvdFxuKTogQ3VzdG9tZXJDb250ZXh0U25hcHNob3Qge1xuICByZXR1cm4ge1xuICAgIGN1c3RvbWVySWQ6IHNuYXBzaG90LmN1c3RvbWVyQWNjb3VudElkLFxuICAgIGFycjogc25hcHNob3QuYXJyLFxuICAgIGhlYWx0aFNjb3JlOiBzbmFwc2hvdC5oZWFsdGhTY29yZSxcbiAgICBzZWdtZW50OiBzbmFwc2hvdC5zZWdtZW50LFxuICAgIGNhcHR1cmVkQXQ6IHNuYXBzaG90LmNhcHR1cmVkQXQsXG4gIH07XG59XG5cbi8qKlxuICogQ2FwdHVyZSBtZXRyaWNzIGFuZCBjcmVhdGUgY29udGV4dCBzbmFwc2hvdCBpbiBvbmUgY2FsbFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBjb250ZXh0ID0gYXdhaXQgY2FwdHVyZUN1c3RvbWVyQ29udGV4dCgnY3VzdF9hYmMxMjMnLCB7XG4gKiAgIGFycjogMTAwMDAwLFxuICogICBoZWFsdGhTY29yZTogOTAsXG4gKiAgIHNlZ21lbnQ6ICdlbnRlcnByaXNlJyxcbiAqIH0pO1xuICpcbiAqIC8vIFVzZSBpbiBydW5cbiAqIGNvbnN0IHJ1biA9IGF3YWl0IHJ1bnMuY3JlYXRlKHtcbiAqICAgYWdlbnRJZDogJ2FnZW50XzEyMycsXG4gKiAgIGN1c3RvbWVyQ29udGV4dDogY29udGV4dCxcbiAqICAgLy8gLi4uXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2FwdHVyZUN1c3RvbWVyQ29udGV4dChcbiAgY3VzdG9tZXJJZDogc3RyaW5nLFxuICBtZXRyaWNzOiB7XG4gICAgYXJyPzogbnVtYmVyO1xuICAgIGhlYWx0aFNjb3JlPzogbnVtYmVyO1xuICAgIHNlZ21lbnQ/OiBzdHJpbmc7XG4gIH1cbik6IFByb21pc2U8Q3VzdG9tZXJDb250ZXh0U25hcHNob3Q+IHtcbiAgY29uc3Qgc25hcHNob3QgPSBhd2FpdCBjdXN0b21lckNvbnRleHQuY2FwdHVyZVNuYXBzaG90KGN1c3RvbWVySWQsIG1ldHJpY3MpO1xuICByZXR1cm4gdG9Db250ZXh0U25hcHNob3Qoc25hcHNob3QpO1xufVxuXG4vKipcbiAqIEdldCBjdXN0b21lciBjb250ZXh0IGFzIG9mIGEgc3BlY2lmaWMgdGltZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0Q29udGV4dEFzT2YoXG4gIGN1c3RvbWVySWQ6IHN0cmluZyxcbiAgdGltZXN0YW1wOiBzdHJpbmcgfCBEYXRlXG4pOiBQcm9taXNlPEN1c3RvbWVyQ29udGV4dFNuYXBzaG90IHwgbnVsbD4ge1xuICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGN1c3RvbWVyQ29udGV4dC5nZXRTbmFwc2hvdEFzT2YoY3VzdG9tZXJJZCwgdGltZXN0YW1wKTtcbiAgcmV0dXJuIHNuYXBzaG90ID8gdG9Db250ZXh0U25hcHNob3Qoc25hcHNob3QpIDogbnVsbDtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGUgQVJSIGNoYW5nZSBiZXR3ZWVuIHR3byBzbmFwc2hvdHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZUFyckNoYW5nZShcbiAgb2xkZXI6IEN1c3RvbWVyTWV0cmljc1NuYXBzaG90LFxuICBuZXdlcjogQ3VzdG9tZXJNZXRyaWNzU25hcHNob3Rcbik6IHtcbiAgYWJzb2x1dGU6IG51bWJlcjtcbiAgcGVyY2VudGFnZTogbnVtYmVyO1xuICBkaXJlY3Rpb246ICdpbmNyZWFzZScgfCAnZGVjcmVhc2UnIHwgJ3N0YWJsZSc7XG59IHtcbiAgY29uc3Qgb2xkQXJyID0gb2xkZXIuYXJyIHx8IDA7XG4gIGNvbnN0IG5ld0FyciA9IG5ld2VyLmFyciB8fCAwO1xuICBjb25zdCBhYnNvbHV0ZSA9IG5ld0FyciAtIG9sZEFycjtcbiAgY29uc3QgcGVyY2VudGFnZSA9IG9sZEFyciA+IDAgPyAoYWJzb2x1dGUgLyBvbGRBcnIpICogMTAwIDogMDtcblxuICByZXR1cm4ge1xuICAgIGFic29sdXRlLFxuICAgIHBlcmNlbnRhZ2UsXG4gICAgZGlyZWN0aW9uOiBhYnNvbHV0ZSA+IDAgPyAnaW5jcmVhc2UnIDogYWJzb2x1dGUgPCAwID8gJ2RlY3JlYXNlJyA6ICdzdGFibGUnLFxuICB9O1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBoZWFsdGggc2NvcmUgdHJlbmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZUhlYWx0aFRyZW5kKFxuICBzbmFwc2hvdHM6IEN1c3RvbWVyTWV0cmljc1NuYXBzaG90W11cbik6IHtcbiAgY3VycmVudFNjb3JlOiBudW1iZXIgfCBudWxsO1xuICBhdmdTY29yZTogbnVtYmVyIHwgbnVsbDtcbiAgdHJlbmQ6ICdpbXByb3ZpbmcnIHwgJ2RlY2xpbmluZycgfCAnc3RhYmxlJztcbiAgdm9sYXRpbGl0eTogJ2xvdycgfCAnbWVkaXVtJyB8ICdoaWdoJztcbn0ge1xuICBjb25zdCBzY29yZXMgPSBzbmFwc2hvdHNcbiAgICAuZmlsdGVyKChzKSA9PiBzLmhlYWx0aFNjb3JlICE9PSB1bmRlZmluZWQgJiYgcy5oZWFsdGhTY29yZSAhPT0gbnVsbClcbiAgICAubWFwKChzKSA9PiBzLmhlYWx0aFNjb3JlISk7XG5cbiAgaWYgKHNjb3Jlcy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4ge1xuICAgICAgY3VycmVudFNjb3JlOiBudWxsLFxuICAgICAgYXZnU2NvcmU6IG51bGwsXG4gICAgICB0cmVuZDogJ3N0YWJsZScsXG4gICAgICB2b2xhdGlsaXR5OiAnbG93JyxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgY3VycmVudFNjb3JlID0gc2NvcmVzWzBdO1xuICBjb25zdCBhdmdTY29yZSA9IHNjb3Jlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHNjb3Jlcy5sZW5ndGg7XG5cbiAgLy8gQ2FsY3VsYXRlIHRyZW5kIChzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gZGlyZWN0aW9uKVxuICBsZXQgdHJlbmQ6ICdpbXByb3ZpbmcnIHwgJ2RlY2xpbmluZycgfCAnc3RhYmxlJyA9ICdzdGFibGUnO1xuICBpZiAoc2NvcmVzLmxlbmd0aCA+PSAyKSB7XG4gICAgY29uc3QgcmVjZW50QXZnID0gc2NvcmVzLnNsaWNlKDAsIE1hdGguY2VpbChzY29yZXMubGVuZ3RoIC8gMikpLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gTWF0aC5jZWlsKHNjb3Jlcy5sZW5ndGggLyAyKTtcbiAgICBjb25zdCBvbGRlckF2ZyA9IHNjb3Jlcy5zbGljZShNYXRoLmNlaWwoc2NvcmVzLmxlbmd0aCAvIDIpKS5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIE1hdGguZmxvb3Ioc2NvcmVzLmxlbmd0aCAvIDIpO1xuICAgIGlmIChyZWNlbnRBdmcgLSBvbGRlckF2ZyA+IDUpIHRyZW5kID0gJ2ltcHJvdmluZyc7XG4gICAgZWxzZSBpZiAob2xkZXJBdmcgLSByZWNlbnRBdmcgPiA1KSB0cmVuZCA9ICdkZWNsaW5pbmcnO1xuICB9XG5cbiAgLy8gQ2FsY3VsYXRlIHZvbGF0aWxpdHkgKHN0YW5kYXJkIGRldmlhdGlvbilcbiAgY29uc3QgdmFyaWFuY2UgPSBzY29yZXMucmVkdWNlKChhY2MsIHMpID0+IGFjYyArIE1hdGgucG93KHMgLSBhdmdTY29yZSwgMiksIDApIC8gc2NvcmVzLmxlbmd0aDtcbiAgY29uc3Qgc3RkRGV2ID0gTWF0aC5zcXJ0KHZhcmlhbmNlKTtcbiAgY29uc3Qgdm9sYXRpbGl0eSA9IHN0ZERldiA8IDUgPyAnbG93JyA6IHN0ZERldiA8IDE1ID8gJ21lZGl1bScgOiAnaGlnaCc7XG5cbiAgcmV0dXJuIHtcbiAgICBjdXJyZW50U2NvcmUsXG4gICAgYXZnU2NvcmUsXG4gICAgdHJlbmQsXG4gICAgdm9sYXRpbGl0eSxcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,217 @@
1
+ /**
2
+ * ThinkHive SDK v3.0 - Ticket Linking
3
+ *
4
+ * Deterministic linking between runs and support tickets
5
+ * 7 link methods with explicit confidence scores
6
+ */
7
+ import type { LinkMethod } from '../core/types';
8
+ /**
9
+ * Generate a Zendesk marker to embed in agent responses
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const runId = 'run_abc123';
14
+ * const marker = generateZendeskMarker(runId);
15
+ * // Returns: '[THID:run_abc123]'
16
+ *
17
+ * // Append to your agent response:
18
+ * const response = `I've found your order. ${marker}`;
19
+ * ```
20
+ */
21
+ export declare function generateZendeskMarker(runId: string): string;
22
+ /**
23
+ * Parse a Zendesk marker from text
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const text = 'Thank you for contacting us. [THID:run_abc123]';
28
+ * const runId = parseZendeskMarker(text);
29
+ * // Returns: 'run_abc123'
30
+ * ```
31
+ */
32
+ export declare function parseZendeskMarker(text: string): string | null;
33
+ /**
34
+ * Check if text contains a Zendesk marker
35
+ */
36
+ export declare function hasZendeskMarker(text: string): boolean;
37
+ /**
38
+ * Remove Zendesk marker from text (for clean display)
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const text = 'Thank you! [THID:run_abc123]';
43
+ * const clean = removeZendeskMarker(text);
44
+ * // Returns: 'Thank you!'
45
+ * ```
46
+ */
47
+ export declare function removeZendeskMarker(text: string): string;
48
+ /**
49
+ * Confidence scores for each link method
50
+ * Based on deterministic linking principles from v3 spec
51
+ */
52
+ export declare const LINK_METHOD_CONFIDENCE: Record<LinkMethod, number>;
53
+ /**
54
+ * Link evidence structure
55
+ */
56
+ export interface LinkEvidence {
57
+ method: LinkMethod;
58
+ confidence: number;
59
+ timestamp: string;
60
+ details: {
61
+ runId?: string;
62
+ ticketId?: string;
63
+ externalTicketId?: string;
64
+ platform?: string;
65
+ sessionId?: string;
66
+ email?: string;
67
+ timeWindowMinutes?: number;
68
+ customFieldName?: string;
69
+ customFieldValue?: string;
70
+ };
71
+ }
72
+ /**
73
+ * Create link input
74
+ */
75
+ export interface CreateLinkInput {
76
+ runId: string;
77
+ ticketId?: string;
78
+ externalTicketId?: string;
79
+ platform?: 'zendesk' | 'intercom' | 'salesforce' | 'freshdesk';
80
+ method: LinkMethod;
81
+ evidence?: Partial<LinkEvidence['details']>;
82
+ }
83
+ /**
84
+ * Link response
85
+ */
86
+ export interface LinkResponse {
87
+ id: string;
88
+ runId: string;
89
+ ticketId?: string;
90
+ externalTicketId?: string;
91
+ platform?: string;
92
+ method: LinkMethod;
93
+ confidence: number;
94
+ evidence: LinkEvidence;
95
+ createdAt: string;
96
+ }
97
+ /**
98
+ * Linking API client
99
+ */
100
+ export declare const linking: {
101
+ /**
102
+ * Create a link between a run and a ticket
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // SDK explicit linking (highest confidence)
107
+ * const link = await linking.create({
108
+ * runId: 'run_abc123',
109
+ * ticketId: 'ticket_xyz',
110
+ * method: 'sdk_explicit',
111
+ * });
112
+ *
113
+ * // Zendesk marker linking
114
+ * const link = await linking.create({
115
+ * runId: 'run_abc123',
116
+ * externalTicketId: '12345',
117
+ * platform: 'zendesk',
118
+ * method: 'zendesk_marker',
119
+ * });
120
+ * ```
121
+ */
122
+ create(input: CreateLinkInput): Promise<LinkResponse>;
123
+ /**
124
+ * Get links for a run
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const links = await linking.getForRun('run_abc123');
129
+ * ```
130
+ */
131
+ getForRun(runId: string): Promise<LinkResponse[]>;
132
+ /**
133
+ * Get links for a ticket
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const links = await linking.getForTicket('ticket_xyz');
138
+ * ```
139
+ */
140
+ getForTicket(ticketId: string): Promise<LinkResponse[]>;
141
+ /**
142
+ * Verify a link (confirm or reject)
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * await linking.verify('link_abc123', {
147
+ * verified: true,
148
+ * notes: 'Confirmed by support agent',
149
+ * });
150
+ * ```
151
+ */
152
+ verify(linkId: string, options: {
153
+ verified: boolean;
154
+ notes?: string;
155
+ }): Promise<{
156
+ linkId: string;
157
+ verified: boolean;
158
+ message: string;
159
+ }>;
160
+ /**
161
+ * Delete a link
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * await linking.delete('link_abc123');
166
+ * ```
167
+ */
168
+ delete(linkId: string): Promise<void>;
169
+ /**
170
+ * Auto-link runs to tickets based on available evidence
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const results = await linking.autoLink('run_abc123');
175
+ * for (const link of results.created) {
176
+ * console.log(`Linked to ${link.ticketId} via ${link.method}`);
177
+ * }
178
+ * ```
179
+ */
180
+ autoLink(runId: string): Promise<{
181
+ runId: string;
182
+ created: LinkResponse[];
183
+ candidates: Array<{
184
+ ticketId: string;
185
+ method: LinkMethod;
186
+ confidence: number;
187
+ reason: string;
188
+ }>;
189
+ }>;
190
+ };
191
+ /**
192
+ * Create SDK explicit link (convenience function)
193
+ */
194
+ export declare function linkRunToTicket(runId: string, ticketId: string): Promise<LinkResponse>;
195
+ /**
196
+ * Create Zendesk link via marker
197
+ */
198
+ export declare function linkRunToZendeskTicket(runId: string, zendeskTicketId: string): Promise<LinkResponse>;
199
+ /**
200
+ * Get the best link method for a given scenario
201
+ */
202
+ export declare function getBestLinkMethod(available: {
203
+ hasTicketId: boolean;
204
+ hasMarker: boolean;
205
+ hasCustomField: boolean;
206
+ hasMiddlewareStamp: boolean;
207
+ hasSessionId: boolean;
208
+ hasEmail: boolean;
209
+ }): LinkMethod | null;
210
+ /**
211
+ * Format link confidence for display
212
+ */
213
+ export declare function formatLinkConfidence(confidence: number): string;
214
+ /**
215
+ * Get confidence level label
216
+ */
217
+ export declare function getConfidenceLevel(confidence: number): 'definitive' | 'high' | 'medium' | 'low';