Skip to content

Commit bf16775

Browse files
committed
Ensure lone handlers are handled correctly
1 parent ea874b9 commit bf16775

2 files changed

Lines changed: 18 additions & 12 deletions

File tree

packages/core/src/tracing/langchain/utils.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -552,10 +552,7 @@ function isCallbackManager(value: unknown): value is {
552552
}
553553

554554
function isSentryHandler(handler: unknown): boolean {
555-
return (
556-
typeof handler === 'object' &&
557-
(handler as Record<string, unknown>)?.name === 'SentryCallbackHandler'
558-
);
555+
return typeof handler === 'object' && (handler as Record<string, unknown>)?.name === 'SentryCallbackHandler';
559556
}
560557

561558
function containsSentryHandler(handlers: unknown[]): boolean {
@@ -571,17 +568,21 @@ export function _INTERNAL_mergeLangChainCallbackHandler(existing: unknown, sentr
571568
return [sentryHandler];
572569
}
573570

574-
if (Array.isArray(existing) && !containsSentryHandler(existing)) {
575-
return [...existing, sentryHandler];
576-
}
577-
578-
if (isCallbackManager(existing) && !containsSentryHandler(existing.handlers ?? [])) {
571+
// CallbackManager: copy and register the handler so inheritable chains are preserved.
572+
if (isCallbackManager(existing)) {
573+
if (containsSentryHandler(existing.handlers ?? [])) {
574+
return existing;
575+
}
579576
const copied = existing.copy() as {
580577
addHandler: (handler: unknown, inherit?: boolean) => void;
581578
};
582579
copied.addHandler(sentryHandler, true);
583580
return copied;
584581
}
585582

586-
return existing;
583+
const handlers = Array.isArray(existing) ? existing : [existing];
584+
if (containsSentryHandler(handlers)) {
585+
return existing;
586+
}
587+
return [...handlers, sentryHandler];
587588
}

packages/core/test/lib/tracing/langchain-utils.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,13 @@ describe('_INTERNAL_mergeLangChainCallbackHandler', () => {
325325
expect(manager.addHandler).not.toHaveBeenCalled();
326326
});
327327

328-
it('returns the value unchanged when it is neither an array nor a CallbackManager', () => {
328+
it('wraps a lone callback object into an array with the sentry handler', () => {
329329
const opaque = { name: 'NotAManager' };
330-
expect(_INTERNAL_mergeLangChainCallbackHandler(opaque, sentryHandler)).toBe(opaque);
330+
expect(_INTERNAL_mergeLangChainCallbackHandler(opaque, sentryHandler)).toStrictEqual([opaque, sentryHandler]);
331+
});
332+
333+
it('returns unchanged when the lone callback object is already a sentry handler', () => {
334+
const existing = { name: 'SentryCallbackHandler' };
335+
expect(_INTERNAL_mergeLangChainCallbackHandler(existing, sentryHandler)).toBe(existing);
331336
});
332337
});

0 commit comments

Comments
 (0)