@tloncorp/openclaw 0.6.0 → 0.6.1
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/dist/index.js +559 -17
- package/dist/index.js.map +1 -1
- package/dist/src/channel.js +12 -0
- package/dist/src/channel.js.map +1 -1
- package/dist/src/diagnostic-subscriptions.js +49 -0
- package/dist/src/diagnostic-subscriptions.js.map +1 -0
- package/dist/src/monitor/index.js +275 -41
- package/dist/src/monitor/index.js.map +1 -1
- package/dist/src/monitor/session-routing.js +261 -0
- package/dist/src/monitor/session-routing.js.map +1 -0
- package/dist/src/session-route.js +44 -0
- package/dist/src/session-route.js.map +1 -0
- package/dist/src/telemetry.js +749 -22
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/version.generated.js +2 -2
- package/dist/src/version.js +134 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +3 -29
package/dist/src/telemetry.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import { PostHog } from 'posthog-node';
|
|
2
|
-
import { sharedMap } from './shared-state.js';
|
|
2
|
+
import { sharedMap, sharedSlot } from './shared-state.js';
|
|
3
|
+
import { getTlonVersionIdentity } from './version.js';
|
|
3
4
|
const TLON_TELEMETRY_EVENT_NAME = 'TlonBot Reply Handled';
|
|
5
|
+
const TLON_GATEWAY_CONNECTED_EVENT = 'TlonBot Gateway Connected';
|
|
6
|
+
const TLON_OUTBOUND_ROUTED_EVENT = 'TlonBot Outbound Routed';
|
|
7
|
+
const TLON_SESSION_LIFECYCLE_EVENT = 'TlonBot Session Lifecycle';
|
|
8
|
+
const TLON_SESSION_WATCHDOG_EVENT = 'TlonBot Session Watchdog';
|
|
9
|
+
const TLON_SESSION_RECOVERY_EVENT = 'TlonBot Session Recovery';
|
|
10
|
+
const TLON_HARNESS_ERROR_EVENT = 'TlonBot Harness Error';
|
|
11
|
+
const TLON_PLUGIN_ERROR_EVENT = 'TlonBot Plugin Error';
|
|
12
|
+
const TLON_TELEMETRY_ERROR_EVENT = 'TlonBot Telemetry Error';
|
|
4
13
|
const TLON_HEARTBEAT_NUDGE_EVENT = 'TlonBot Heartbeat Nudge Sent';
|
|
5
14
|
const TLON_HEARTBEAT_REENGAGED_EVENT = 'TlonBot Heartbeat Nudge Reengaged';
|
|
6
15
|
const TLON_TELEMETRY_LOG_SOURCE = 'openclawPlugin';
|
|
7
16
|
const TOOL_TRACE_TTL_MS = 60 * 60 * 1000;
|
|
8
17
|
const MAX_TOOL_CALLS_PER_SESSION = 200;
|
|
18
|
+
const REPLY_TRACE_TTL_MS = 60 * 60 * 1000;
|
|
19
|
+
const MAX_ACTIVE_REPLY_TRACES = 50;
|
|
20
|
+
const SESSION_CONTEXT_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
21
|
+
const MAX_SESSION_CONTEXTS = 5_000;
|
|
9
22
|
const toolCallsBySession = sharedMap('telemetry.toolCallsBySession');
|
|
23
|
+
const sessionContextsBySessionKey = sharedMap('telemetry.sessionContextsBySessionKey');
|
|
10
24
|
function cleanupToolCalls(now = Date.now()) {
|
|
11
25
|
for (const [sessionKey, trace] of toolCallsBySession) {
|
|
12
26
|
if (now - trace.updatedAt > TOOL_TRACE_TTL_MS) {
|
|
@@ -59,16 +73,141 @@ function collectToolUsageSince(sessionKey, cursor) {
|
|
|
59
73
|
errorCount: calls.filter((call) => call.error).length,
|
|
60
74
|
};
|
|
61
75
|
}
|
|
76
|
+
function cleanupSessionContexts(now = Date.now()) {
|
|
77
|
+
for (const [sessionKey, context] of sessionContextsBySessionKey) {
|
|
78
|
+
if (now - context.updatedAt > SESSION_CONTEXT_TTL_MS) {
|
|
79
|
+
sessionContextsBySessionKey.delete(sessionKey);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
while (sessionContextsBySessionKey.size > MAX_SESSION_CONTEXTS) {
|
|
83
|
+
const oldestKey = [...sessionContextsBySessionKey.entries()].sort((a, b) => a[1].updatedAt - b[1].updatedAt)[0]?.[0];
|
|
84
|
+
if (!oldestKey) {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
sessionContextsBySessionKey.delete(oldestKey);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function rememberTlonSessionContext(params) {
|
|
91
|
+
const sessionKey = params.sessionKey.trim();
|
|
92
|
+
if (!sessionKey) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
cleanupSessionContexts(now);
|
|
97
|
+
const existing = sessionContextsBySessionKey.get(sessionKey);
|
|
98
|
+
sessionContextsBySessionKey.set(sessionKey, {
|
|
99
|
+
sessionKey,
|
|
100
|
+
sessionId: optionalString(params.sessionId) ?? existing?.sessionId ?? null,
|
|
101
|
+
runId: optionalString(params.runId) ?? existing?.runId ?? null,
|
|
102
|
+
ownerShip: params.ownerShip,
|
|
103
|
+
botShip: params.botShip,
|
|
104
|
+
accountId: params.accountId ?? null,
|
|
105
|
+
agentId: params.agentId ?? null,
|
|
106
|
+
destinationKind: params.destinationKind,
|
|
107
|
+
updatedAt: now,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function lookupTlonSessionContext(sessionKey) {
|
|
111
|
+
const normalized = sessionKey?.trim();
|
|
112
|
+
if (!normalized) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
cleanupSessionContexts();
|
|
116
|
+
const context = sessionContextsBySessionKey.get(normalized);
|
|
117
|
+
if (!context) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
context.updatedAt = Date.now();
|
|
121
|
+
sessionContextsBySessionKey.set(normalized, context);
|
|
122
|
+
return context;
|
|
123
|
+
}
|
|
124
|
+
function updateTlonSessionContextSessionId(context, sessionId) {
|
|
125
|
+
const normalizedSessionId = optionalString(sessionId);
|
|
126
|
+
if (!normalizedSessionId || context.sessionId === normalizedSessionId) {
|
|
127
|
+
return context;
|
|
128
|
+
}
|
|
129
|
+
const updated = {
|
|
130
|
+
...context,
|
|
131
|
+
sessionId: normalizedSessionId,
|
|
132
|
+
updatedAt: Date.now(),
|
|
133
|
+
};
|
|
134
|
+
sessionContextsBySessionKey.set(updated.sessionKey, updated);
|
|
135
|
+
return updated;
|
|
136
|
+
}
|
|
137
|
+
function updateTlonSessionContextRuntime(context, params) {
|
|
138
|
+
const normalizedSessionId = optionalString(params.sessionId);
|
|
139
|
+
const normalizedRunId = optionalString(params.runId);
|
|
140
|
+
const normalizedAgentId = optionalString(params.agentId);
|
|
141
|
+
if ((!normalizedSessionId || context.sessionId === normalizedSessionId) &&
|
|
142
|
+
(!normalizedRunId || context.runId === normalizedRunId) &&
|
|
143
|
+
(!normalizedAgentId || context.agentId === normalizedAgentId)) {
|
|
144
|
+
return context;
|
|
145
|
+
}
|
|
146
|
+
const updated = {
|
|
147
|
+
...context,
|
|
148
|
+
sessionId: normalizedSessionId ?? context.sessionId,
|
|
149
|
+
runId: normalizedRunId ?? context.runId,
|
|
150
|
+
agentId: normalizedAgentId ?? context.agentId,
|
|
151
|
+
updatedAt: Date.now(),
|
|
152
|
+
};
|
|
153
|
+
sessionContextsBySessionKey.set(updated.sessionKey, updated);
|
|
154
|
+
return updated;
|
|
155
|
+
}
|
|
156
|
+
function countDispatchFailures(counts, kind) {
|
|
157
|
+
const value = counts?.[kind];
|
|
158
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
159
|
+
? Math.max(0, value)
|
|
160
|
+
: 0;
|
|
161
|
+
}
|
|
162
|
+
function classifyError(error) {
|
|
163
|
+
if (!error) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
if (error instanceof Error) {
|
|
167
|
+
return error.name || 'Error';
|
|
168
|
+
}
|
|
169
|
+
if (typeof error === 'object' && error !== null) {
|
|
170
|
+
const code = error.code;
|
|
171
|
+
if (typeof code === 'string' && code.trim()) {
|
|
172
|
+
return code.trim().slice(0, 80);
|
|
173
|
+
}
|
|
174
|
+
const name = error.name;
|
|
175
|
+
if (typeof name === 'string' && name.trim()) {
|
|
176
|
+
return name.trim().slice(0, 80);
|
|
177
|
+
}
|
|
178
|
+
return 'object';
|
|
179
|
+
}
|
|
180
|
+
return typeof error;
|
|
181
|
+
}
|
|
62
182
|
function resolveReplyOutcome(params) {
|
|
63
183
|
if (params.deliveredMessageCount > 0) {
|
|
64
184
|
return 'responded';
|
|
65
185
|
}
|
|
66
|
-
|
|
186
|
+
const failedReplyCount = countDispatchFailures(params.failedCounts, 'tool') +
|
|
187
|
+
countDispatchFailures(params.failedCounts, 'block') +
|
|
188
|
+
countDispatchFailures(params.failedCounts, 'final');
|
|
189
|
+
return params.dispatchError || params.sendError || failedReplyCount > 0
|
|
190
|
+
? 'error'
|
|
191
|
+
: 'no_reply';
|
|
192
|
+
}
|
|
193
|
+
function resolveDeliverySkipReason(params) {
|
|
194
|
+
if (params.outcome !== 'no_reply') {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
if (params.deliverySkipReason) {
|
|
198
|
+
return params.deliverySkipReason;
|
|
199
|
+
}
|
|
200
|
+
if (params.sourceReplyDeliveryMode === 'message_tool_only') {
|
|
201
|
+
return 'source_reply_delivery_mode_message_tool_only';
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
67
204
|
}
|
|
68
205
|
class PostHogTlonTelemetry {
|
|
69
206
|
client;
|
|
70
207
|
runtime;
|
|
208
|
+
versionIdentity = getTlonVersionIdentity();
|
|
71
209
|
identifiedOwners = new Set();
|
|
210
|
+
activeReplyTraces = new Map();
|
|
72
211
|
missingOwnerWarningLogged = false;
|
|
73
212
|
constructor(params) {
|
|
74
213
|
this.runtime = params.runtime;
|
|
@@ -81,23 +220,109 @@ class PostHogTlonTelemetry {
|
|
|
81
220
|
disableRemoteConfig: true,
|
|
82
221
|
});
|
|
83
222
|
}
|
|
223
|
+
properties(props) {
|
|
224
|
+
return {
|
|
225
|
+
logSource: TLON_TELEMETRY_LOG_SOURCE,
|
|
226
|
+
...this.versionIdentity,
|
|
227
|
+
...props,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
captureGatewayConnected(event) {
|
|
231
|
+
const ownerShip = event.ownerShip ?? '';
|
|
232
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
this.client.capture({
|
|
236
|
+
distinctId: ownerShip,
|
|
237
|
+
event: TLON_GATEWAY_CONNECTED_EVENT,
|
|
238
|
+
properties: this.properties({
|
|
239
|
+
botShip: event.botShip,
|
|
240
|
+
ownerShip: event.ownerShip,
|
|
241
|
+
tlonSkillVersion: event.tlonSkillVersion,
|
|
242
|
+
accountId: event.accountId,
|
|
243
|
+
configured: event.configured,
|
|
244
|
+
watchedChannelCount: event.watchedChannelCount,
|
|
245
|
+
dmAllowlistCount: event.dmAllowlistCount,
|
|
246
|
+
defaultAuthorizedShipsCount: event.defaultAuthorizedShipsCount,
|
|
247
|
+
pendingApprovalCount: event.pendingApprovalCount,
|
|
248
|
+
autoDiscoverChannels: event.autoDiscoverChannels,
|
|
249
|
+
ownerListenEnabled: event.ownerListenEnabled,
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
}
|
|
84
253
|
startReply(params) {
|
|
254
|
+
const normalizedParams = {
|
|
255
|
+
...params,
|
|
256
|
+
sessionId: optionalString(params.sessionId),
|
|
257
|
+
runId: params.runId ?? null,
|
|
258
|
+
accountId: params.accountId ?? null,
|
|
259
|
+
agentId: params.agentId ?? null,
|
|
260
|
+
destinationKind: params.destinationKind ?? params.chatType,
|
|
261
|
+
};
|
|
85
262
|
const toolTraceCursor = createToolTraceCursor(params.sessionKey);
|
|
263
|
+
rememberTlonSessionContext({
|
|
264
|
+
sessionKey: normalizedParams.sessionKey,
|
|
265
|
+
sessionId: normalizedParams.sessionId,
|
|
266
|
+
runId: normalizedParams.runId,
|
|
267
|
+
ownerShip: normalizedParams.ownerShip,
|
|
268
|
+
botShip: normalizedParams.botShip,
|
|
269
|
+
accountId: normalizedParams.accountId,
|
|
270
|
+
agentId: normalizedParams.agentId,
|
|
271
|
+
destinationKind: normalizedParams.destinationKind,
|
|
272
|
+
});
|
|
273
|
+
this.pruneActiveReplyTraces();
|
|
274
|
+
const token = Symbol(normalizedParams.sessionKey);
|
|
275
|
+
const trace = {
|
|
276
|
+
params: normalizedParams,
|
|
277
|
+
startedAt: Date.now(),
|
|
278
|
+
toolTraceCursor,
|
|
279
|
+
timeout: setTimeout(() => {
|
|
280
|
+
this.captureAbandonedReplyTrace(token, 'stale');
|
|
281
|
+
}, REPLY_TRACE_TTL_MS),
|
|
282
|
+
};
|
|
283
|
+
trace.timeout.unref?.();
|
|
284
|
+
this.activeReplyTraces.set(token, trace);
|
|
285
|
+
this.pruneActiveReplyTraces();
|
|
86
286
|
return {
|
|
87
287
|
capture: async (result) => {
|
|
288
|
+
const activeTrace = this.activeReplyTraces.get(token);
|
|
289
|
+
if (!activeTrace) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.activeReplyTraces.delete(token);
|
|
293
|
+
clearTimeout(activeTrace.timeout);
|
|
88
294
|
// Yield once so after_tool_call hooks for the just-finished reply have time to run.
|
|
89
295
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
296
|
+
const failedToolCount = countDispatchFailures(result.failedCounts, 'tool');
|
|
297
|
+
const failedBlockCount = countDispatchFailures(result.failedCounts, 'block');
|
|
298
|
+
const failedFinalCount = countDispatchFailures(result.failedCounts, 'final');
|
|
299
|
+
const sendErrorCount = Math.max(0, result.sendErrorCount ?? 0);
|
|
300
|
+
const sessionContext = lookupTlonSessionContext(activeTrace.params.sessionKey);
|
|
301
|
+
const outcome = resolveReplyOutcome({
|
|
302
|
+
deliveredMessageCount: result.deliveredMessageCount,
|
|
303
|
+
sendError: sendErrorCount > 0,
|
|
304
|
+
failedCounts: result.failedCounts,
|
|
305
|
+
dispatchError: result.dispatchError,
|
|
306
|
+
});
|
|
307
|
+
const sourceReplyDeliveryMode = result.sourceReplyDeliveryMode ?? null;
|
|
90
308
|
this.captureReplyOutcome({
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
309
|
+
sessionKey: activeTrace.params.sessionKey,
|
|
310
|
+
sessionId: sessionContext?.sessionId ?? activeTrace.params.sessionId,
|
|
311
|
+
runId: activeTrace.params.runId,
|
|
312
|
+
accountId: activeTrace.params.accountId,
|
|
313
|
+
agentId: activeTrace.params.agentId,
|
|
314
|
+
ownerShip: activeTrace.params.ownerShip,
|
|
315
|
+
botShip: activeTrace.params.botShip,
|
|
316
|
+
outcome,
|
|
317
|
+
chatType: activeTrace.params.chatType,
|
|
318
|
+
destinationKind: activeTrace.params.destinationKind,
|
|
319
|
+
isThreadReply: activeTrace.params.isThreadReply,
|
|
320
|
+
senderRole: activeTrace.params.senderRole,
|
|
321
|
+
attachmentCount: activeTrace.params.attachmentCount,
|
|
322
|
+
sendAttemptCount: Math.max(0, result.sendAttemptCount ?? 0),
|
|
323
|
+
sendError: sendErrorCount > 0,
|
|
324
|
+
sendErrorCount,
|
|
325
|
+
sendErrorKind: result.sendErrorKind ?? null,
|
|
101
326
|
deliveredMessageCount: result.deliveredMessageCount,
|
|
102
327
|
replyCharCount: result.replyCharCount,
|
|
103
328
|
replyWordCount: result.replyWordCount,
|
|
@@ -106,14 +331,92 @@ class PostHogTlonTelemetry {
|
|
|
106
331
|
queuedFinal: result.queuedFinal,
|
|
107
332
|
queuedFinalCount: result.queuedFinalCount,
|
|
108
333
|
queuedBlockCount: result.queuedBlockCount,
|
|
334
|
+
failedToolCount,
|
|
335
|
+
failedBlockCount,
|
|
336
|
+
failedFinalCount,
|
|
337
|
+
failedReplyCount: failedToolCount + failedBlockCount + failedFinalCount,
|
|
338
|
+
deliverySkipReason: resolveDeliverySkipReason({
|
|
339
|
+
outcome,
|
|
340
|
+
deliverySkipReason: result.deliverySkipReason,
|
|
341
|
+
sourceReplyDeliveryMode,
|
|
342
|
+
}),
|
|
343
|
+
sourceReplyDeliveryMode,
|
|
344
|
+
beforeAgentRunBlocked: result.beforeAgentRunBlocked === true,
|
|
345
|
+
dispatchError: Boolean(result.dispatchError),
|
|
346
|
+
dispatchErrorKind: classifyError(result.dispatchError),
|
|
347
|
+
abandonedReason: null,
|
|
109
348
|
provider: result.provider,
|
|
110
349
|
model: result.model,
|
|
111
350
|
thinkLevel: result.thinkLevel,
|
|
112
|
-
toolUsage: collectToolUsageSince(params.sessionKey, toolTraceCursor),
|
|
351
|
+
toolUsage: collectToolUsageSince(activeTrace.params.sessionKey, activeTrace.toolTraceCursor),
|
|
113
352
|
});
|
|
114
353
|
},
|
|
115
354
|
};
|
|
116
355
|
}
|
|
356
|
+
captureAbandonedReplyTrace(token, reason) {
|
|
357
|
+
const trace = this.activeReplyTraces.get(token);
|
|
358
|
+
if (!trace) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
this.activeReplyTraces.delete(token);
|
|
362
|
+
clearTimeout(trace.timeout);
|
|
363
|
+
const sessionContext = lookupTlonSessionContext(trace.params.sessionKey);
|
|
364
|
+
this.captureReplyOutcome({
|
|
365
|
+
sessionKey: trace.params.sessionKey,
|
|
366
|
+
sessionId: sessionContext?.sessionId ?? trace.params.sessionId,
|
|
367
|
+
runId: trace.params.runId,
|
|
368
|
+
accountId: trace.params.accountId,
|
|
369
|
+
agentId: trace.params.agentId,
|
|
370
|
+
ownerShip: trace.params.ownerShip,
|
|
371
|
+
botShip: trace.params.botShip,
|
|
372
|
+
outcome: 'abandoned',
|
|
373
|
+
chatType: trace.params.chatType,
|
|
374
|
+
destinationKind: trace.params.destinationKind,
|
|
375
|
+
isThreadReply: trace.params.isThreadReply,
|
|
376
|
+
senderRole: trace.params.senderRole,
|
|
377
|
+
attachmentCount: trace.params.attachmentCount,
|
|
378
|
+
sendAttemptCount: 0,
|
|
379
|
+
sendError: false,
|
|
380
|
+
sendErrorCount: 0,
|
|
381
|
+
sendErrorKind: null,
|
|
382
|
+
deliveredMessageCount: 0,
|
|
383
|
+
replyCharCount: 0,
|
|
384
|
+
replyWordCount: 0,
|
|
385
|
+
replyMediaCount: 0,
|
|
386
|
+
dispatchDurationMs: Date.now() - trace.startedAt,
|
|
387
|
+
queuedFinal: false,
|
|
388
|
+
queuedFinalCount: 0,
|
|
389
|
+
queuedBlockCount: 0,
|
|
390
|
+
failedToolCount: 0,
|
|
391
|
+
failedBlockCount: 0,
|
|
392
|
+
failedFinalCount: 0,
|
|
393
|
+
failedReplyCount: 0,
|
|
394
|
+
deliverySkipReason: null,
|
|
395
|
+
sourceReplyDeliveryMode: null,
|
|
396
|
+
beforeAgentRunBlocked: false,
|
|
397
|
+
dispatchError: false,
|
|
398
|
+
dispatchErrorKind: null,
|
|
399
|
+
abandonedReason: reason,
|
|
400
|
+
provider: null,
|
|
401
|
+
model: null,
|
|
402
|
+
thinkLevel: null,
|
|
403
|
+
toolUsage: collectToolUsageSince(trace.params.sessionKey, trace.toolTraceCursor),
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
pruneActiveReplyTraces(now = Date.now()) {
|
|
407
|
+
for (const [token, trace] of this.activeReplyTraces) {
|
|
408
|
+
if (now - trace.startedAt > REPLY_TRACE_TTL_MS) {
|
|
409
|
+
this.captureAbandonedReplyTrace(token, 'stale');
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
while (this.activeReplyTraces.size > MAX_ACTIVE_REPLY_TRACES) {
|
|
413
|
+
const oldest = [...this.activeReplyTraces.entries()].sort((a, b) => a[1].startedAt - b[1].startedAt)[0];
|
|
414
|
+
if (!oldest) {
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
this.captureAbandonedReplyTrace(oldest[0], 'max_traces');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
117
420
|
captureReplyOutcome(event) {
|
|
118
421
|
const ownerShip = event.ownerShip ?? '';
|
|
119
422
|
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
@@ -122,16 +425,25 @@ class PostHogTlonTelemetry {
|
|
|
122
425
|
this.client.capture({
|
|
123
426
|
distinctId: ownerShip,
|
|
124
427
|
event: TLON_TELEMETRY_EVENT_NAME,
|
|
125
|
-
properties: {
|
|
126
|
-
|
|
428
|
+
properties: this.properties({
|
|
429
|
+
sessionKey: event.sessionKey,
|
|
430
|
+
sessionId: event.sessionId,
|
|
431
|
+
runId: event.runId,
|
|
432
|
+
accountId: event.accountId,
|
|
433
|
+
agentId: event.agentId,
|
|
127
434
|
botShip: event.botShip,
|
|
128
435
|
ownerShip: event.ownerShip,
|
|
129
436
|
outcome: event.outcome,
|
|
130
437
|
chatType: event.chatType,
|
|
438
|
+
destinationKind: event.destinationKind,
|
|
131
439
|
isThreadReply: event.isThreadReply,
|
|
132
440
|
senderRole: event.senderRole,
|
|
133
441
|
attachmentCount: event.attachmentCount,
|
|
134
442
|
hasAttachments: event.attachmentCount > 0,
|
|
443
|
+
sendAttemptCount: event.sendAttemptCount,
|
|
444
|
+
sendError: event.sendError,
|
|
445
|
+
sendErrorCount: event.sendErrorCount,
|
|
446
|
+
sendErrorKind: event.sendErrorKind,
|
|
135
447
|
deliveredMessageCount: event.deliveredMessageCount,
|
|
136
448
|
replyCharCount: event.replyCharCount,
|
|
137
449
|
replyWordCount: event.replyWordCount,
|
|
@@ -140,6 +452,16 @@ class PostHogTlonTelemetry {
|
|
|
140
452
|
queuedFinal: event.queuedFinal,
|
|
141
453
|
queuedFinalCount: event.queuedFinalCount,
|
|
142
454
|
queuedBlockCount: event.queuedBlockCount,
|
|
455
|
+
failedToolCount: event.failedToolCount,
|
|
456
|
+
failedBlockCount: event.failedBlockCount,
|
|
457
|
+
failedFinalCount: event.failedFinalCount,
|
|
458
|
+
failedReplyCount: event.failedReplyCount,
|
|
459
|
+
deliverySkipReason: event.deliverySkipReason,
|
|
460
|
+
sourceReplyDeliveryMode: event.sourceReplyDeliveryMode,
|
|
461
|
+
beforeAgentRunBlocked: event.beforeAgentRunBlocked,
|
|
462
|
+
dispatchError: event.dispatchError,
|
|
463
|
+
dispatchErrorKind: event.dispatchErrorKind,
|
|
464
|
+
abandonedReason: event.abandonedReason,
|
|
143
465
|
provider: event.provider,
|
|
144
466
|
model: event.model,
|
|
145
467
|
thinkLevel: event.thinkLevel,
|
|
@@ -152,7 +474,188 @@ class PostHogTlonTelemetry {
|
|
|
152
474
|
durationMs: call.durationMs,
|
|
153
475
|
error: call.error,
|
|
154
476
|
})),
|
|
155
|
-
},
|
|
477
|
+
}),
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
captureSessionLifecycle(event) {
|
|
481
|
+
const ownerShip = event.ownerShip ?? '';
|
|
482
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
this.client.capture({
|
|
486
|
+
distinctId: ownerShip,
|
|
487
|
+
event: TLON_SESSION_LIFECYCLE_EVENT,
|
|
488
|
+
properties: this.properties({
|
|
489
|
+
botShip: event.botShip,
|
|
490
|
+
ownerShip: event.ownerShip,
|
|
491
|
+
accountId: event.accountId,
|
|
492
|
+
agentId: event.agentId,
|
|
493
|
+
sessionKey: event.sessionKey,
|
|
494
|
+
sessionId: event.sessionId,
|
|
495
|
+
lifecycleEvent: event.lifecycleEvent,
|
|
496
|
+
destinationKind: event.destinationKind,
|
|
497
|
+
reason: event.reason,
|
|
498
|
+
messageCount: event.messageCount,
|
|
499
|
+
durationMs: event.durationMs,
|
|
500
|
+
transcriptArchived: event.transcriptArchived,
|
|
501
|
+
hasNextSession: event.hasNextSession,
|
|
502
|
+
}),
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
captureSessionWatchdog(event) {
|
|
506
|
+
const ownerShip = event.ownerShip ?? '';
|
|
507
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
this.client.capture({
|
|
511
|
+
distinctId: ownerShip,
|
|
512
|
+
event: TLON_SESSION_WATCHDOG_EVENT,
|
|
513
|
+
properties: this.properties({
|
|
514
|
+
botShip: event.botShip,
|
|
515
|
+
ownerShip: event.ownerShip,
|
|
516
|
+
accountId: event.accountId,
|
|
517
|
+
agentId: event.agentId,
|
|
518
|
+
sessionKey: event.sessionKey,
|
|
519
|
+
sessionId: event.sessionId,
|
|
520
|
+
diagnosticType: event.diagnosticType,
|
|
521
|
+
destinationKind: event.destinationKind,
|
|
522
|
+
state: event.state,
|
|
523
|
+
ageMs: event.ageMs,
|
|
524
|
+
queueDepth: event.queueDepth,
|
|
525
|
+
reason: event.reason,
|
|
526
|
+
classification: event.classification,
|
|
527
|
+
activeWorkKind: event.activeWorkKind,
|
|
528
|
+
lastProgressAgeMs: event.lastProgressAgeMs,
|
|
529
|
+
lastProgressReason: event.lastProgressReason,
|
|
530
|
+
activeToolName: event.activeToolName,
|
|
531
|
+
activeToolAgeMs: event.activeToolAgeMs,
|
|
532
|
+
terminalProgressStale: event.terminalProgressStale,
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
captureSessionRecovery(event) {
|
|
537
|
+
const ownerShip = event.ownerShip ?? '';
|
|
538
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
this.client.capture({
|
|
542
|
+
distinctId: ownerShip,
|
|
543
|
+
event: TLON_SESSION_RECOVERY_EVENT,
|
|
544
|
+
properties: this.properties({
|
|
545
|
+
botShip: event.botShip,
|
|
546
|
+
ownerShip: event.ownerShip,
|
|
547
|
+
accountId: event.accountId,
|
|
548
|
+
agentId: event.agentId,
|
|
549
|
+
sessionKey: event.sessionKey,
|
|
550
|
+
sessionId: event.sessionId,
|
|
551
|
+
diagnosticType: event.diagnosticType,
|
|
552
|
+
destinationKind: event.destinationKind,
|
|
553
|
+
state: event.state,
|
|
554
|
+
stateGeneration: event.stateGeneration,
|
|
555
|
+
ageMs: event.ageMs,
|
|
556
|
+
queueDepth: event.queueDepth,
|
|
557
|
+
reason: event.reason,
|
|
558
|
+
activeWorkKind: event.activeWorkKind,
|
|
559
|
+
allowActiveAbort: event.allowActiveAbort,
|
|
560
|
+
status: event.status,
|
|
561
|
+
action: event.action,
|
|
562
|
+
outcomeReason: event.outcomeReason,
|
|
563
|
+
released: event.released,
|
|
564
|
+
stale: event.stale,
|
|
565
|
+
}),
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
captureOutboundRoute(event) {
|
|
569
|
+
const ownerShip = event.ownerShip ?? '';
|
|
570
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
this.client.capture({
|
|
574
|
+
distinctId: ownerShip,
|
|
575
|
+
event: TLON_OUTBOUND_ROUTED_EVENT,
|
|
576
|
+
properties: this.properties({
|
|
577
|
+
botShip: event.botShip,
|
|
578
|
+
ownerShip: event.ownerShip,
|
|
579
|
+
resolvedChannel: event.resolvedChannel,
|
|
580
|
+
routedToTlon: event.routedToTlon,
|
|
581
|
+
targetKind: event.targetKind,
|
|
582
|
+
}),
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
captureHarnessError(event) {
|
|
586
|
+
const ownerShip = event.ownerShip ?? '';
|
|
587
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
this.client.capture({
|
|
591
|
+
distinctId: ownerShip,
|
|
592
|
+
event: TLON_HARNESS_ERROR_EVENT,
|
|
593
|
+
properties: this.properties({
|
|
594
|
+
harness: event.harness,
|
|
595
|
+
harnessEventType: event.harnessEventType,
|
|
596
|
+
errorScope: event.errorScope,
|
|
597
|
+
sessionKey: event.sessionKey,
|
|
598
|
+
sessionId: event.sessionId,
|
|
599
|
+
runId: event.runId,
|
|
600
|
+
accountId: event.accountId,
|
|
601
|
+
agentId: event.agentId,
|
|
602
|
+
ownerShip: event.ownerShip,
|
|
603
|
+
botShip: event.botShip,
|
|
604
|
+
destinationKind: event.destinationKind,
|
|
605
|
+
provider: event.provider,
|
|
606
|
+
model: event.model,
|
|
607
|
+
toolName: event.toolName,
|
|
608
|
+
phase: event.phase,
|
|
609
|
+
outcome: event.outcome,
|
|
610
|
+
errorCategory: event.errorCategory,
|
|
611
|
+
failureKind: event.failureKind,
|
|
612
|
+
durationMs: event.durationMs,
|
|
613
|
+
errorText: event.errorText,
|
|
614
|
+
}),
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
capturePluginError(event) {
|
|
618
|
+
const ownerShip = event.ownerShip ?? '';
|
|
619
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
this.client.capture({
|
|
623
|
+
distinctId: ownerShip,
|
|
624
|
+
event: TLON_PLUGIN_ERROR_EVENT,
|
|
625
|
+
properties: this.properties({
|
|
626
|
+
harness: event.harness,
|
|
627
|
+
pluginErrorSource: event.pluginErrorSource,
|
|
628
|
+
accountId: event.accountId,
|
|
629
|
+
ownerShip: event.ownerShip,
|
|
630
|
+
botShip: event.botShip,
|
|
631
|
+
errorKind: event.errorKind,
|
|
632
|
+
errorText: event.errorText,
|
|
633
|
+
attempt: event.attempt,
|
|
634
|
+
}),
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
captureTelemetryError(event) {
|
|
638
|
+
const ownerShip = event.ownerShip ?? '';
|
|
639
|
+
if (!this.ensureIdentified(ownerShip, event.botShip)) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
this.client.capture({
|
|
643
|
+
distinctId: ownerShip,
|
|
644
|
+
event: TLON_TELEMETRY_ERROR_EVENT,
|
|
645
|
+
properties: this.properties({
|
|
646
|
+
harness: event.harness,
|
|
647
|
+
telemetrySource: event.telemetrySource,
|
|
648
|
+
sourceEventName: event.sourceEventName,
|
|
649
|
+
sessionKey: event.sessionKey,
|
|
650
|
+
sessionId: event.sessionId,
|
|
651
|
+
runId: event.runId,
|
|
652
|
+
accountId: event.accountId,
|
|
653
|
+
agentId: event.agentId,
|
|
654
|
+
ownerShip: event.ownerShip,
|
|
655
|
+
botShip: event.botShip,
|
|
656
|
+
errorKind: event.errorKind,
|
|
657
|
+
errorText: event.errorText,
|
|
658
|
+
}),
|
|
156
659
|
});
|
|
157
660
|
}
|
|
158
661
|
ensureIdentified(ownerShip, botShip) {
|
|
@@ -169,6 +672,7 @@ class PostHogTlonTelemetry {
|
|
|
169
672
|
distinctId: ownerShip,
|
|
170
673
|
properties: {
|
|
171
674
|
logSource: TLON_TELEMETRY_LOG_SOURCE,
|
|
675
|
+
...this.versionIdentity,
|
|
172
676
|
tlonOwnerShip: ownerShip,
|
|
173
677
|
tlonBotShip: botShip,
|
|
174
678
|
},
|
|
@@ -183,8 +687,7 @@ class PostHogTlonTelemetry {
|
|
|
183
687
|
this.client.capture({
|
|
184
688
|
distinctId: event.ownerShip,
|
|
185
689
|
event: TLON_HEARTBEAT_NUDGE_EVENT,
|
|
186
|
-
properties: {
|
|
187
|
-
logSource: TLON_TELEMETRY_LOG_SOURCE,
|
|
690
|
+
properties: this.properties({
|
|
188
691
|
botShip: event.botShip,
|
|
189
692
|
ownerShip: event.ownerShip,
|
|
190
693
|
trigger: 'heartbeat',
|
|
@@ -195,7 +698,7 @@ class PostHogTlonTelemetry {
|
|
|
195
698
|
accountId: event.accountId,
|
|
196
699
|
messageId: event.messageId,
|
|
197
700
|
nudgeSentAtMs: event.nudgeSentAtMs,
|
|
198
|
-
},
|
|
701
|
+
}),
|
|
199
702
|
});
|
|
200
703
|
}
|
|
201
704
|
captureHeartbeatReengagement(event) {
|
|
@@ -205,8 +708,7 @@ class PostHogTlonTelemetry {
|
|
|
205
708
|
this.client.capture({
|
|
206
709
|
distinctId: event.ownerShip,
|
|
207
710
|
event: TLON_HEARTBEAT_REENGAGED_EVENT,
|
|
208
|
-
properties: {
|
|
209
|
-
logSource: TLON_TELEMETRY_LOG_SOURCE,
|
|
711
|
+
properties: this.properties({
|
|
210
712
|
botShip: event.botShip,
|
|
211
713
|
ownerShip: event.ownerShip,
|
|
212
714
|
nudgeStage: event.nudgeStage,
|
|
@@ -215,10 +717,13 @@ class PostHogTlonTelemetry {
|
|
|
215
717
|
reengagementDelayMs: event.reengagementDelayMs,
|
|
216
718
|
channel: event.channel,
|
|
217
719
|
accountId: event.accountId,
|
|
218
|
-
},
|
|
720
|
+
}),
|
|
219
721
|
});
|
|
220
722
|
}
|
|
221
723
|
async close() {
|
|
724
|
+
for (const token of [...this.activeReplyTraces.keys()]) {
|
|
725
|
+
this.captureAbandonedReplyTrace(token, 'telemetry_close');
|
|
726
|
+
}
|
|
222
727
|
try {
|
|
223
728
|
await this.client.flush();
|
|
224
729
|
}
|
|
@@ -248,8 +753,230 @@ export function createTlonTelemetry(params) {
|
|
|
248
753
|
runtime: params.runtime,
|
|
249
754
|
});
|
|
250
755
|
}
|
|
756
|
+
const outboundRouteReporterSlot = sharedSlot('telemetry.outboundRouteReporter');
|
|
757
|
+
const sessionTelemetryReporterSlot = sharedSlot('telemetry.sessionTelemetryReporter');
|
|
758
|
+
const errorTelemetryReporterSlot = sharedSlot('telemetry.errorTelemetryReporter');
|
|
759
|
+
export function setOutboundRouteReporter(reporter) {
|
|
760
|
+
outboundRouteReporterSlot.set(reporter);
|
|
761
|
+
}
|
|
762
|
+
export function reportOutboundRoute(event) {
|
|
763
|
+
outboundRouteReporterSlot.get()?.(event);
|
|
764
|
+
}
|
|
765
|
+
export function setSessionTelemetryReporter(reporter) {
|
|
766
|
+
sessionTelemetryReporterSlot.set(reporter);
|
|
767
|
+
}
|
|
768
|
+
export function setErrorTelemetryReporter(reporter) {
|
|
769
|
+
errorTelemetryReporterSlot.set(reporter);
|
|
770
|
+
}
|
|
771
|
+
function optionalString(value) {
|
|
772
|
+
const normalized = value?.trim();
|
|
773
|
+
return normalized ? normalized : null;
|
|
774
|
+
}
|
|
775
|
+
function optionalErrorText(value) {
|
|
776
|
+
return typeof value === 'string' && value.trim() ? value : null;
|
|
777
|
+
}
|
|
778
|
+
function optionalNumber(value) {
|
|
779
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
780
|
+
}
|
|
781
|
+
export function formatTlonTelemetryErrorText(error) {
|
|
782
|
+
if (error instanceof Error) {
|
|
783
|
+
return error.stack || error.message || String(error);
|
|
784
|
+
}
|
|
785
|
+
if (typeof error === 'string') {
|
|
786
|
+
return error;
|
|
787
|
+
}
|
|
788
|
+
if (error === null) {
|
|
789
|
+
return 'null';
|
|
790
|
+
}
|
|
791
|
+
if (error === undefined) {
|
|
792
|
+
return 'undefined';
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
const json = JSON.stringify(error);
|
|
796
|
+
if (json) {
|
|
797
|
+
return json;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
catch {
|
|
801
|
+
// Fall through to String(error).
|
|
802
|
+
}
|
|
803
|
+
return String(error);
|
|
804
|
+
}
|
|
805
|
+
export function reportSessionTurnCreated(event) {
|
|
806
|
+
const context = lookupTlonSessionContext(event.sessionKey);
|
|
807
|
+
if (!context) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
updateTlonSessionContextRuntime(context, {
|
|
811
|
+
sessionId: event.sessionId,
|
|
812
|
+
runId: event.runId,
|
|
813
|
+
agentId: event.agentId,
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
export function reportHarnessError(event) {
|
|
817
|
+
const rememberedContext = lookupTlonSessionContext(event.sessionKey);
|
|
818
|
+
const context = rememberedContext
|
|
819
|
+
? updateTlonSessionContextRuntime(rememberedContext, {
|
|
820
|
+
sessionId: event.sessionId,
|
|
821
|
+
runId: event.runId,
|
|
822
|
+
agentId: event.agentId,
|
|
823
|
+
})
|
|
824
|
+
: null;
|
|
825
|
+
if (!context && event.sessionKey) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
errorTelemetryReporterSlot.get()?.({
|
|
829
|
+
kind: 'harness',
|
|
830
|
+
event: {
|
|
831
|
+
harness: 'openclaw',
|
|
832
|
+
harnessEventType: event.harnessEventType,
|
|
833
|
+
errorScope: event.errorScope,
|
|
834
|
+
sessionKey: context?.sessionKey ?? null,
|
|
835
|
+
sessionId: context?.sessionId ?? optionalString(event.sessionId),
|
|
836
|
+
runId: optionalString(event.runId) ?? context?.runId ?? null,
|
|
837
|
+
accountId: context?.accountId ?? optionalString(event.accountId),
|
|
838
|
+
agentId: optionalString(event.agentId) ?? context?.agentId ?? null,
|
|
839
|
+
ownerShip: context?.ownerShip ?? optionalString(event.ownerShip),
|
|
840
|
+
botShip: context?.botShip ?? optionalString(event.botShip) ?? '',
|
|
841
|
+
destinationKind: context?.destinationKind ?? event.destinationKind ?? null,
|
|
842
|
+
provider: optionalString(event.provider),
|
|
843
|
+
model: optionalString(event.model),
|
|
844
|
+
toolName: optionalString(event.toolName),
|
|
845
|
+
phase: optionalString(event.phase),
|
|
846
|
+
outcome: optionalString(event.outcome),
|
|
847
|
+
errorCategory: optionalString(event.errorCategory),
|
|
848
|
+
failureKind: optionalString(event.failureKind),
|
|
849
|
+
durationMs: optionalNumber(event.durationMs),
|
|
850
|
+
errorText: optionalErrorText(event.errorText),
|
|
851
|
+
},
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
export function reportPluginError(event) {
|
|
855
|
+
errorTelemetryReporterSlot.get()?.({
|
|
856
|
+
kind: 'plugin',
|
|
857
|
+
event,
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
export function reportTelemetryError(event) {
|
|
861
|
+
const rememberedContext = lookupTlonSessionContext(event.sessionKey);
|
|
862
|
+
const context = rememberedContext
|
|
863
|
+
? updateTlonSessionContextRuntime(rememberedContext, {
|
|
864
|
+
sessionId: event.sessionId,
|
|
865
|
+
runId: event.runId,
|
|
866
|
+
agentId: event.agentId,
|
|
867
|
+
})
|
|
868
|
+
: null;
|
|
869
|
+
errorTelemetryReporterSlot.get()?.({
|
|
870
|
+
kind: 'telemetry',
|
|
871
|
+
event: {
|
|
872
|
+
...event,
|
|
873
|
+
sessionKey: context?.sessionKey ?? optionalString(event.sessionKey),
|
|
874
|
+
sessionId: context?.sessionId ?? optionalString(event.sessionId),
|
|
875
|
+
runId: optionalString(event.runId) ?? context?.runId ?? null,
|
|
876
|
+
agentId: optionalString(event.agentId) ?? context?.agentId ?? null,
|
|
877
|
+
accountId: event.accountId ?? context?.accountId ?? null,
|
|
878
|
+
ownerShip: event.ownerShip ?? context?.ownerShip ?? null,
|
|
879
|
+
botShip: event.botShip ?? context?.botShip ?? null,
|
|
880
|
+
sourceEventName: optionalString(event.sourceEventName),
|
|
881
|
+
errorKind: optionalString(event.errorKind),
|
|
882
|
+
},
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
export function reportSessionLifecycle(event) {
|
|
886
|
+
const rememberedContext = lookupTlonSessionContext(event.sessionKey);
|
|
887
|
+
const context = rememberedContext
|
|
888
|
+
? updateTlonSessionContextSessionId(rememberedContext, event.sessionId)
|
|
889
|
+
: null;
|
|
890
|
+
if (!context) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
sessionTelemetryReporterSlot.get()?.({
|
|
894
|
+
kind: 'lifecycle',
|
|
895
|
+
event: {
|
|
896
|
+
lifecycleEvent: event.lifecycleEvent,
|
|
897
|
+
sessionKey: context.sessionKey,
|
|
898
|
+
sessionId: context.sessionId,
|
|
899
|
+
accountId: context.accountId,
|
|
900
|
+
agentId: optionalString(event.agentId) ?? context.agentId,
|
|
901
|
+
ownerShip: context.ownerShip,
|
|
902
|
+
botShip: context.botShip,
|
|
903
|
+
destinationKind: context.destinationKind,
|
|
904
|
+
reason: optionalString(event.reason),
|
|
905
|
+
messageCount: optionalNumber(event.messageCount),
|
|
906
|
+
durationMs: optionalNumber(event.durationMs),
|
|
907
|
+
transcriptArchived: typeof event.transcriptArchived === 'boolean'
|
|
908
|
+
? event.transcriptArchived
|
|
909
|
+
: null,
|
|
910
|
+
hasNextSession: event.hasNextSession === true,
|
|
911
|
+
},
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
export function reportSessionDiagnostic(event) {
|
|
915
|
+
const rememberedContext = lookupTlonSessionContext(event.sessionKey);
|
|
916
|
+
const context = rememberedContext
|
|
917
|
+
? updateTlonSessionContextSessionId(rememberedContext, event.sessionId)
|
|
918
|
+
: null;
|
|
919
|
+
if (!context) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (event.type === 'session.stalled' || event.type === 'session.stuck') {
|
|
923
|
+
sessionTelemetryReporterSlot.get()?.({
|
|
924
|
+
kind: 'watchdog',
|
|
925
|
+
event: {
|
|
926
|
+
diagnosticType: event.type,
|
|
927
|
+
sessionKey: context.sessionKey,
|
|
928
|
+
sessionId: context.sessionId,
|
|
929
|
+
accountId: context.accountId,
|
|
930
|
+
agentId: context.agentId,
|
|
931
|
+
ownerShip: context.ownerShip,
|
|
932
|
+
botShip: context.botShip,
|
|
933
|
+
destinationKind: context.destinationKind,
|
|
934
|
+
state: event.state,
|
|
935
|
+
ageMs: event.ageMs,
|
|
936
|
+
queueDepth: optionalNumber(event.queueDepth),
|
|
937
|
+
reason: optionalString(event.reason),
|
|
938
|
+
classification: event.classification,
|
|
939
|
+
activeWorkKind: optionalString(event.activeWorkKind),
|
|
940
|
+
lastProgressAgeMs: optionalNumber(event.lastProgressAgeMs),
|
|
941
|
+
lastProgressReason: optionalString(event.lastProgressReason),
|
|
942
|
+
activeToolName: optionalString(event.activeToolName),
|
|
943
|
+
activeToolAgeMs: optionalNumber(event.activeToolAgeMs),
|
|
944
|
+
terminalProgressStale: event.terminalProgressStale === true,
|
|
945
|
+
},
|
|
946
|
+
});
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const recoveryEvent = event;
|
|
950
|
+
sessionTelemetryReporterSlot.get()?.({
|
|
951
|
+
kind: 'recovery',
|
|
952
|
+
event: {
|
|
953
|
+
diagnosticType: recoveryEvent.type,
|
|
954
|
+
sessionKey: context.sessionKey,
|
|
955
|
+
sessionId: context.sessionId,
|
|
956
|
+
accountId: context.accountId,
|
|
957
|
+
agentId: context.agentId,
|
|
958
|
+
ownerShip: context.ownerShip,
|
|
959
|
+
botShip: context.botShip,
|
|
960
|
+
destinationKind: context.destinationKind,
|
|
961
|
+
state: recoveryEvent.state,
|
|
962
|
+
stateGeneration: optionalNumber(recoveryEvent.stateGeneration),
|
|
963
|
+
ageMs: recoveryEvent.ageMs,
|
|
964
|
+
queueDepth: optionalNumber(recoveryEvent.queueDepth),
|
|
965
|
+
reason: optionalString(recoveryEvent.reason),
|
|
966
|
+
activeWorkKind: optionalString(recoveryEvent.activeWorkKind),
|
|
967
|
+
allowActiveAbort: recoveryEvent.allowActiveAbort === true,
|
|
968
|
+
status: optionalString(recoveryEvent.status),
|
|
969
|
+
action: optionalString(recoveryEvent.action),
|
|
970
|
+
outcomeReason: optionalString(recoveryEvent.outcomeReason),
|
|
971
|
+
released: optionalNumber(recoveryEvent.released),
|
|
972
|
+
stale: recoveryEvent.stale === true,
|
|
973
|
+
},
|
|
974
|
+
});
|
|
975
|
+
}
|
|
251
976
|
export const _testing = {
|
|
252
977
|
clearToolCalls: () => toolCallsBySession.clear(),
|
|
978
|
+
clearSessionContexts: () => sessionContextsBySessionKey.clear(),
|
|
979
|
+
getReplyTraceTtlMs: () => REPLY_TRACE_TTL_MS,
|
|
253
980
|
getToolTraceTtlMs: () => TOOL_TRACE_TTL_MS,
|
|
254
981
|
};
|
|
255
982
|
//# sourceMappingURL=telemetry.js.map
|