@telemetry-dev/eve 0.1.0 → 0.1.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.d.mts CHANGED
@@ -5,7 +5,7 @@ import { InstrumentationDefinition, InstrumentationEvents, InstrumentationRuntim
5
5
 
6
6
  //#region src/config.d.ts
7
7
  /** Options accepted by every @telemetry-dev/eve entry point. */
8
- type TelemetryDevEveOptions = Omit<TelemetryOptions, "registerGlobal">;
8
+ type TelemetryDevEveOptions = Omit<TelemetryOptions, "registerGlobal" | "sdkName">;
9
9
  //#endregion
10
10
  //#region src/client.d.ts
11
11
  interface WrapEveClientOptions extends TelemetryDevEveOptions {
package/dist/index.mjs CHANGED
@@ -14,6 +14,7 @@ function ensureInit(options = {}, overrides) {
14
14
  initialized = true;
15
15
  init({
16
16
  ...options,
17
+ sdkName: "@telemetry-dev/eve",
17
18
  registerGlobal: true,
18
19
  spanFilter: options.spanFilter ?? ((span) => span.instrumentationScope.name !== "workflow")
19
20
  }, overrides);
@@ -21,16 +22,16 @@ function ensureInit(options = {}, overrides) {
21
22
  //#endregion
22
23
  //#region src/client.ts
23
24
  function asRecord$1(value) {
24
- if (value === null || typeof value !== "object") return void 0;
25
+ if (value === null || Array.isArray(value) || !(value instanceof Object)) return void 0;
25
26
  return value;
26
27
  }
27
28
  function stringField$1(record, key) {
28
29
  const value = record?.[key];
29
- return typeof value === "string" && value.length > 0 ? value : void 0;
30
+ return value?.constructor === String && value.length > 0 ? value : void 0;
30
31
  }
31
32
  function numberField$1(record, key) {
32
33
  const value = record?.[key];
33
- return typeof value === "number" ? value : void 0;
34
+ return value?.constructor === Number ? value : void 0;
34
35
  }
35
36
  function eventData$1(event) {
36
37
  if (!("data" in event)) return {};
@@ -55,8 +56,8 @@ function inputForSpan(payload) {
55
56
  return payload.message ?? payload.inputResponses;
56
57
  }
57
58
  function bindOrReturn(target, prop) {
58
- const value = Reflect.get(target, prop, target);
59
- return typeof value === "function" ? value.bind(target) : value;
59
+ const value = target[prop];
60
+ return value instanceof Function ? value.bind(target) : value;
60
61
  }
61
62
  function addLifecycleEvent(span, event) {
62
63
  const data = eventData$1(event);
@@ -105,7 +106,7 @@ async function* instrumentedStream(response, span, start, payload) {
105
106
  finishReason,
106
107
  output,
107
108
  timeToFirstChunkMs,
108
- error
109
+ error: error instanceof Error ? error : error === void 0 ? void 0 : /* @__PURE__ */ new Error("error")
109
110
  });
110
111
  };
111
112
  try {
@@ -138,7 +139,7 @@ async function* instrumentedStream(response, span, start, payload) {
138
139
  if (payload.signal?.aborted) {
139
140
  error = failureError("cancelled", "cancelled");
140
141
  finishReason ??= "cancelled";
141
- } else error = caught;
142
+ } else error = caught instanceof Error ? caught : new Error(String(caught));
142
143
  throw caught;
143
144
  } finally {
144
145
  finish();
@@ -148,29 +149,29 @@ function wrapSession(session, options) {
148
149
  return new Proxy(session, { get(target, prop) {
149
150
  if (prop === "send") {
150
151
  const wrappedSend = async (input) => {
151
- const payload = typeof input === "string" ? { message: input } : input;
152
+ const turnPayload = input instanceof String || input?.constructor === String ? { message: String(input) } : input;
152
153
  const span = startSpan(options.spanName ?? "invoke_agent", {
153
154
  type: "agent",
154
155
  agentName: options.agentName,
155
- input: inputForSpan(payload)
156
+ input: inputForSpan(turnPayload)
156
157
  });
157
158
  const start = performance.now();
158
159
  let response;
159
160
  try {
160
161
  response = await target.send(input);
161
162
  } catch (error) {
162
- if (payload.signal?.aborted) span.end({
163
+ if (turnPayload.signal?.aborted) span.end({
163
164
  error: failureError("cancelled", "cancelled"),
164
165
  finishReason: "cancelled"
165
166
  });
166
- else span.end({ error });
167
+ else span.end({ error: error instanceof Error ? error : new Error(String(error)) });
167
168
  throw error;
168
169
  }
169
170
  span.span.setAttribute("gen_ai.conversation.id", response.sessionId);
170
171
  return new MessageResponse({
171
172
  continuationToken: response.continuationToken,
172
173
  sessionId: response.sessionId,
173
- createStream: () => instrumentedStream(response, span, start, payload)
174
+ createStream: () => instrumentedStream(response, span, start, turnPayload)
174
175
  });
175
176
  };
176
177
  return wrappedSend;
@@ -189,7 +190,7 @@ function wrapEveClient(client, options = {}, overrides) {
189
190
  //#endregion
190
191
  //#region src/hook.ts
191
192
  function asRecord(value) {
192
- if (value === null || typeof value !== "object") return void 0;
193
+ if (value === null || Array.isArray(value) || !(value instanceof Object)) return void 0;
193
194
  return value;
194
195
  }
195
196
  function eventData(event) {
@@ -198,11 +199,11 @@ function eventData(event) {
198
199
  }
199
200
  function stringField(record, key) {
200
201
  const value = record?.[key];
201
- return typeof value === "string" && value.length > 0 ? value : void 0;
202
+ return value?.constructor === String && value.length > 0 ? value : void 0;
202
203
  }
203
204
  function numberField(record, key) {
204
205
  const value = record?.[key];
205
- return typeof value === "number" ? value : void 0;
206
+ return value?.constructor === Number ? value : void 0;
206
207
  }
207
208
  function jsonField(record, key) {
208
209
  const value = record?.[key];
@@ -340,7 +341,11 @@ function logEvent(event, ctx) {
340
341
  ...attrs,
341
342
  "error.code": stringField(childData, "code"),
342
343
  "eve.error.details": jsonField(childData, "details")
343
- }, child);
344
+ }, {
345
+ ...child,
346
+ data: childData,
347
+ type: childType
348
+ });
344
349
  return;
345
350
  }
346
351
  if (childType === "turn.failed") {
@@ -348,14 +353,22 @@ function logEvent(event, ctx) {
348
353
  ...attrs,
349
354
  "error.code": stringField(childData, "code"),
350
355
  "eve.error.details": jsonField(childData, "details")
351
- }, child);
356
+ }, {
357
+ ...child,
358
+ data: childData,
359
+ type: childType
360
+ });
352
361
  return;
353
362
  }
354
363
  if (childType === "session.failed") emit(event, ctx, "error", `Subagent session failed: ${stringField(childData, "message") ?? ""}`, {
355
364
  ...attrs,
356
365
  "error.code": stringField(childData, "code"),
357
366
  "eve.error.details": jsonField(childData, "details")
358
- }, child);
367
+ }, {
368
+ ...child,
369
+ data: childData,
370
+ type: childType
371
+ });
359
372
  return;
360
373
  }
361
374
  case "subagent.called": {
@@ -415,13 +428,13 @@ function telemetryDevHook(options = {}, overrides) {
415
428
  ensureInit(options, overrides);
416
429
  logEvent(event, ctx);
417
430
  } catch (error) {
418
- reportError$1(options.onError, error);
431
+ reportError$1(options.onError, error instanceof Error ? error : new Error(String(error)));
419
432
  }
420
433
  } } };
421
434
  }
422
435
  //#endregion
423
436
  //#region src/instrumentation.ts
424
- const envServiceName = () => typeof process !== "undefined" ? process.env.OTEL_SERVICE_NAME : void 0;
437
+ const envServiceName = () => globalThis.process !== void 0 ? process.env.OTEL_SERVICE_NAME : void 0;
425
438
  function reportError(onError, error) {
426
439
  try {
427
440
  onError?.(error);
@@ -439,20 +452,23 @@ function telemetryDevInstrumentation(options = {}, overrides) {
439
452
  serviceName: sdkOptions.serviceName ?? envServiceName() ?? agentName
440
453
  }, overrides);
441
454
  } catch (error) {
442
- reportError(sdkOptions.onError, error);
455
+ reportError(sdkOptions.onError, error instanceof Error ? error : new Error(String(error)));
443
456
  }
444
457
  },
445
458
  events: { "step.started"(input) {
446
459
  const ctx = { ...runtimeContext };
447
460
  const userId = input.session.auth.initiator?.principalId ?? input.session.auth.current?.principalId;
448
- if (userId) ctx["user.id"] = userId;
461
+ const runtimeContextWithUser = userId ? {
462
+ ...ctx,
463
+ "user.id": userId
464
+ } : ctx;
449
465
  try {
450
466
  const userResult = stepStarted?.(input);
451
- if (userResult?.runtimeContext) Object.assign(ctx, userResult.runtimeContext);
467
+ if (userResult?.runtimeContext) Object.assign(runtimeContextWithUser, userResult.runtimeContext);
452
468
  } catch (error) {
453
- reportError(sdkOptions.onError, error);
469
+ reportError(sdkOptions.onError, error instanceof Error ? error : new Error(String(error)));
454
470
  }
455
- return Object.keys(ctx).length > 0 ? { runtimeContext: ctx } : void 0;
471
+ return Object.keys(runtimeContextWithUser).length > 0 ? { runtimeContext: runtimeContextWithUser } : void 0;
456
472
  } }
457
473
  };
458
474
  if (functionId !== void 0) return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telemetry-dev/eve",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Eve (Vercel agent framework) telemetry integration for telemetry.dev.",
5
5
  "keywords": [
6
6
  "agents",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@opentelemetry/api": "^1.9.1",
40
- "@telemetry-dev/sdk": "^0.1.0"
40
+ "@telemetry-dev/sdk": "^0.1.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@opentelemetry/sdk-logs": "^0.218.0",
package/src/client.ts CHANGED
@@ -24,24 +24,33 @@ export interface WrapEveClientOptions extends TelemetryDevEveOptions {
24
24
  spanName?: string;
25
25
  }
26
26
 
27
- function asRecord(value: unknown): Record<string, unknown> | undefined {
28
- if (value === null || typeof value !== "object") return undefined;
29
- return value as Record<string, unknown>;
27
+ type EventRecord = { [key: string]: EventValue };
28
+ type EventValue =
29
+ | string
30
+ | number
31
+ | boolean
32
+ | null
33
+ | undefined
34
+ | readonly EventValue[]
35
+ | EventRecord;
36
+ function asRecord(value: EventValue): EventRecord | undefined {
37
+ if (value === null || Array.isArray(value) || !(value instanceof Object)) return undefined;
38
+ return value as EventRecord;
30
39
  }
31
40
 
32
- function stringField(record: Record<string, unknown> | undefined, key: string): string | undefined {
41
+ function stringField(record: EventRecord | undefined, key: string): string | undefined {
33
42
  const value = record?.[key];
34
- return typeof value === "string" && value.length > 0 ? value : undefined;
43
+ return value?.constructor === String && value.length > 0 ? value : undefined;
35
44
  }
36
45
 
37
- function numberField(record: Record<string, unknown> | undefined, key: string): number | undefined {
46
+ function numberField(record: EventRecord | undefined, key: string): number | undefined {
38
47
  const value = record?.[key];
39
- return typeof value === "number" ? value : undefined;
48
+ return value?.constructor === Number ? value : undefined;
40
49
  }
41
50
 
42
- function eventData(event: HandleMessageStreamEvent): Record<string, unknown> {
51
+ function eventData(event: HandleMessageStreamEvent): EventRecord {
43
52
  if (!("data" in event)) return {};
44
- return asRecord(event.data) ?? {};
53
+ return asRecord(event.data as EventValue) ?? {};
45
54
  }
46
55
 
47
56
  function eventAttributes(
@@ -66,13 +75,13 @@ function failureError(code: string | undefined, message: string | undefined): Er
66
75
  return error;
67
76
  }
68
77
 
69
- function inputForSpan<TOutput>(payload: SendTurnPayload<TOutput>): unknown {
78
+ function inputForSpan<TOutput>(payload: SendTurnPayload<TOutput>) {
70
79
  return payload.message ?? payload.inputResponses;
71
80
  }
72
81
 
73
- function bindOrReturn<T extends object>(target: T, prop: string | symbol): unknown {
74
- const value = Reflect.get(target, prop, target);
75
- return typeof value === "function" ? value.bind(target) : value;
82
+ function bindOrReturn<T extends object>(target: T, prop: string | symbol) {
83
+ const value = target[prop as keyof T];
84
+ return value instanceof Function ? value.bind(target) : value;
76
85
  }
77
86
 
78
87
  function addLifecycleEvent(span: SpanHandle, event: HandleMessageStreamEvent): void {
@@ -141,7 +150,7 @@ async function* instrumentedStream<TOutput>(
141
150
  finishReason,
142
151
  output,
143
152
  timeToFirstChunkMs,
144
- error,
153
+ error: error instanceof Error ? error : error === undefined ? undefined : new Error("error"),
145
154
  });
146
155
  };
147
156
 
@@ -204,7 +213,7 @@ async function* instrumentedStream<TOutput>(
204
213
  error = failureError("cancelled", "cancelled");
205
214
  finishReason ??= "cancelled";
206
215
  } else {
207
- error = caught;
216
+ error = caught instanceof Error ? caught : new Error(String(caught));
208
217
  }
209
218
  throw caught;
210
219
  } finally {
@@ -219,25 +228,28 @@ function wrapSession(session: ClientSession, options: WrapEveClientOptions): Cli
219
228
  const wrappedSend: ClientSession["send"] = async <TOutput = unknown>(
220
229
  input: SendTurnInput<TOutput>,
221
230
  ) => {
222
- const payload: SendTurnPayload<TOutput> =
223
- typeof input === "string" ? { message: input } : input;
231
+ const payload =
232
+ input instanceof String || input?.constructor === String
233
+ ? { message: String(input) }
234
+ : input;
235
+ const turnPayload = payload as SendTurnPayload<TOutput>;
224
236
  const span = startSpan(options.spanName ?? "invoke_agent", {
225
237
  type: "agent",
226
238
  agentName: options.agentName,
227
- input: inputForSpan(payload),
239
+ input: inputForSpan(turnPayload),
228
240
  });
229
241
  const start = performance.now();
230
242
  let response: MessageResponse<TOutput>;
231
243
  try {
232
244
  response = await target.send(input);
233
245
  } catch (error) {
234
- if (payload.signal?.aborted) {
246
+ if (turnPayload.signal?.aborted) {
235
247
  span.end({
236
248
  error: failureError("cancelled", "cancelled"),
237
249
  finishReason: "cancelled",
238
250
  });
239
251
  } else {
240
- span.end({ error });
252
+ span.end({ error: error instanceof Error ? error : new Error(String(error)) });
241
253
  }
242
254
  throw error;
243
255
  }
@@ -248,7 +260,7 @@ function wrapSession(session: ClientSession, options: WrapEveClientOptions): Cli
248
260
  return new MessageResponse<TOutput>({
249
261
  continuationToken: response.continuationToken,
250
262
  sessionId: response.sessionId,
251
- createStream: () => instrumentedStream(response, span, start, payload),
263
+ createStream: () => instrumentedStream(response, span, start, turnPayload),
252
264
  });
253
265
  };
254
266
  return wrappedSend;
@@ -265,7 +277,6 @@ export function wrapEveClient<C extends Client>(
265
277
  ): C {
266
278
  const { agentName: _agentName, spanName: _spanName, ...sdkOptions } = options;
267
279
  ensureInit(sdkOptions, overrides);
268
-
269
280
  return new Proxy(client, {
270
281
  get(target, prop) {
271
282
  if (prop === "session") {
package/src/config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { init, shutdown, type ClientOverrides, type TelemetryOptions } from "@telemetry-dev/sdk";
2
2
 
3
3
  /** Options accepted by every @telemetry-dev/eve entry point. */
4
- export type TelemetryDevEveOptions = Omit<TelemetryOptions, "registerGlobal">;
4
+ export type TelemetryDevEveOptions = Omit<TelemetryOptions, "registerGlobal" | "sdkName">;
5
5
 
6
6
  export type { ClientOverrides };
7
7
 
@@ -23,6 +23,7 @@ export function ensureInit(
23
23
  init(
24
24
  {
25
25
  ...options,
26
+ sdkName: "@telemetry-dev/eve",
26
27
  registerGlobal: true,
27
28
  spanFilter: options.spanFilter ?? ((span) => span.instrumentationScope.name !== "workflow"),
28
29
  },
package/src/hook.ts CHANGED
@@ -4,29 +4,30 @@ import type { HookContext, HookDefinition } from "eve/hooks";
4
4
 
5
5
  import { ensureInit, type ClientOverrides, type TelemetryDevEveOptions } from "./config.ts";
6
6
 
7
- type Attrs = Record<string, unknown>;
7
+ type Attrs = { [key: string]: Value };
8
+ type Value = string | number | boolean | null | undefined | readonly Value[] | Attrs;
8
9
 
9
- function asRecord(value: unknown): Record<string, unknown> | undefined {
10
- if (value === null || typeof value !== "object") return undefined;
11
- return value as Record<string, unknown>;
10
+ function asRecord(value: Value): Attrs | undefined {
11
+ if (value === null || Array.isArray(value) || !(value instanceof Object)) return undefined;
12
+ return value as Attrs;
12
13
  }
13
14
 
14
- function eventData(event: HandleMessageStreamEvent): Record<string, unknown> {
15
+ function eventData(event: HandleMessageStreamEvent): Attrs {
15
16
  if (!("data" in event)) return {};
16
- return asRecord(event.data) ?? {};
17
+ return asRecord(event.data as Value) ?? {};
17
18
  }
18
19
 
19
- function stringField(record: Record<string, unknown> | undefined, key: string): string | undefined {
20
+ function stringField(record: Attrs | undefined, key: string): string | undefined {
20
21
  const value = record?.[key];
21
- return typeof value === "string" && value.length > 0 ? value : undefined;
22
+ return value?.constructor === String && value.length > 0 ? value : undefined;
22
23
  }
23
24
 
24
- function numberField(record: Record<string, unknown> | undefined, key: string): number | undefined {
25
+ function numberField(record: Attrs | undefined, key: string): number | undefined {
25
26
  const value = record?.[key];
26
- return typeof value === "number" ? value : undefined;
27
+ return value?.constructor === Number ? value : undefined;
27
28
  }
28
29
 
29
- function jsonField(record: Record<string, unknown> | undefined, key: string): string | undefined {
30
+ function jsonField(record: Attrs | undefined, key: string): string | undefined {
30
31
  const value = record?.[key];
31
32
  if (value === undefined) return undefined;
32
33
  try {
@@ -36,7 +37,7 @@ function jsonField(record: Record<string, unknown> | undefined, key: string): st
36
37
  }
37
38
  }
38
39
 
39
- function baseAttributes(event: HandleMessageStreamEvent, ctx: HookContext): Attrs {
40
+ function baseAttributes(event: HandleMessageStreamEvent, ctx: HookContext) {
40
41
  const data = eventData(event);
41
42
  return {
42
43
  "gen_ai.conversation.id": ctx.session.id,
@@ -48,7 +49,7 @@ function baseAttributes(event: HandleMessageStreamEvent, ctx: HookContext): Attr
48
49
  };
49
50
  }
50
51
 
51
- function toolAttrs(result: unknown): Attrs {
52
+ function toolAttrs(result: Value) {
52
53
  const record = asRecord(result);
53
54
  const subagentName = stringField(record, "subagentName");
54
55
  return {
@@ -59,7 +60,7 @@ function toolAttrs(result: unknown): Attrs {
59
60
  "eve.subagent.name": subagentName,
60
61
  };
61
62
  }
62
- function reportError(onError: ((error: unknown) => void) | undefined, error: unknown): void {
63
+ function reportError(onError: ((error: Error) => void) | undefined, error: Error): void {
63
64
  try {
64
65
  onError?.(error);
65
66
  } catch {
@@ -84,7 +85,7 @@ function emit(
84
85
  });
85
86
  }
86
87
 
87
- function stepCompletedMessage(data: Record<string, unknown>): string {
88
+ function stepCompletedMessage(data: Attrs): string {
88
89
  const finishReason = stringField(data, "finishReason") ?? "unknown";
89
90
  const usage = asRecord(data.usage);
90
91
  const inputTokens = numberField(usage, "inputTokens");
@@ -186,7 +187,7 @@ function logEvent(event: HandleMessageStreamEvent, ctx: HookContext): void {
186
187
  });
187
188
  return;
188
189
  case "subagent.event": {
189
- const child = asRecord(data.event);
190
+ const child = asRecord(data.event as Value);
190
191
  const childData = asRecord(child?.data);
191
192
  const childType = stringField(child, "type");
192
193
  const attrs = {
@@ -204,7 +205,11 @@ function logEvent(event: HandleMessageStreamEvent, ctx: HookContext): void {
204
205
  "error.code": stringField(childData, "code"),
205
206
  "eve.error.details": jsonField(childData, "details"),
206
207
  },
207
- child as unknown as HandleMessageStreamEvent,
208
+ {
209
+ ...child,
210
+ data: childData,
211
+ type: childType,
212
+ } as HandleMessageStreamEvent,
208
213
  );
209
214
  return;
210
215
  }
@@ -219,7 +224,11 @@ function logEvent(event: HandleMessageStreamEvent, ctx: HookContext): void {
219
224
  "error.code": stringField(childData, "code"),
220
225
  "eve.error.details": jsonField(childData, "details"),
221
226
  },
222
- child as unknown as HandleMessageStreamEvent,
227
+ {
228
+ ...child,
229
+ data: childData,
230
+ type: childType,
231
+ } as HandleMessageStreamEvent,
223
232
  );
224
233
  return;
225
234
  }
@@ -234,7 +243,11 @@ function logEvent(event: HandleMessageStreamEvent, ctx: HookContext): void {
234
243
  "error.code": stringField(childData, "code"),
235
244
  "eve.error.details": jsonField(childData, "details"),
236
245
  },
237
- child as unknown as HandleMessageStreamEvent,
246
+ {
247
+ ...child,
248
+ data: childData,
249
+ type: childType,
250
+ } as HandleMessageStreamEvent,
238
251
  );
239
252
  }
240
253
  return;
@@ -305,7 +318,7 @@ export function telemetryDevHook(
305
318
  ensureInit(options, overrides);
306
319
  logEvent(event, ctx);
307
320
  } catch (error) {
308
- reportError(options.onError, error);
321
+ reportError(options.onError, error instanceof Error ? error : new Error(String(error)));
309
322
  }
310
323
  },
311
324
  },
@@ -20,8 +20,8 @@ export interface TelemetryDevInstrumentationOptions extends TelemetryDevEveOptio
20
20
  }
21
21
 
22
22
  const envServiceName = (): string | undefined =>
23
- typeof process !== "undefined" ? process.env.OTEL_SERVICE_NAME : undefined;
24
- function reportError(onError: ((error: unknown) => void) | undefined, error: unknown): void {
23
+ globalThis.process !== undefined ? process.env.OTEL_SERVICE_NAME : undefined;
24
+ function reportError(onError: ((error: Error) => void) | undefined, error: Error): void {
25
25
  try {
26
26
  onError?.(error);
27
27
  } catch {
@@ -49,27 +49,30 @@ export function telemetryDevInstrumentation(
49
49
  overrides,
50
50
  );
51
51
  } catch (error) {
52
- reportError(sdkOptions.onError, error);
52
+ reportError(sdkOptions.onError, error instanceof Error ? error : new Error(String(error)));
53
53
  }
54
54
  },
55
55
  events: {
56
56
  "step.started"(input) {
57
- const ctx: Record<string, unknown> = { ...runtimeContext };
57
+ const ctx = { ...runtimeContext } satisfies InstrumentationRuntimeContext;
58
58
  const userId =
59
59
  input.session.auth.initiator?.principalId ?? input.session.auth.current?.principalId;
60
- if (userId) ctx["user.id"] = userId;
60
+ const runtimeContextWithUser = userId ? { ...ctx, "user.id": userId } : ctx;
61
61
 
62
62
  try {
63
63
  const userResult = stepStarted?.(input);
64
64
  if (userResult?.runtimeContext) {
65
- Object.assign(ctx, userResult.runtimeContext);
65
+ Object.assign(runtimeContextWithUser, userResult.runtimeContext);
66
66
  }
67
67
  } catch (error) {
68
- reportError(sdkOptions.onError, error);
68
+ reportError(
69
+ sdkOptions.onError,
70
+ error instanceof Error ? error : new Error(String(error)),
71
+ );
69
72
  }
70
73
 
71
- return Object.keys(ctx).length > 0
72
- ? { runtimeContext: ctx as InstrumentationRuntimeContext }
74
+ return Object.keys(runtimeContextWithUser).length > 0
75
+ ? { runtimeContext: runtimeContextWithUser }
73
76
  : undefined;
74
77
  },
75
78
  },