Skip to content

Commit

Permalink
Refactor to remove circular dep
Browse files Browse the repository at this point in the history
  • Loading branch information
jacoblee93 committed Dec 10, 2024
1 parent 9b44574 commit 193de5b
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 21 deletions.
4 changes: 2 additions & 2 deletions langchain-core/src/callbacks/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1273,10 +1273,10 @@ export class CallbackManager
handler = contextVarValue;
} else if (createIfNotInContext) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handler = new (handlerClass as any)();
handler = new (handlerClass as any)({});
}
if (handler !== undefined) {
if (!callbackManager?.handlers.some((h) => h.name === handler.name)) {
if (!callbackManager?.handlers.some((h) => h.name === handler!.name)) {
callbackManager?.addHandler(handler, inheritable);
}
}
Expand Down
24 changes: 18 additions & 6 deletions langchain-core/src/singletons/async_local_storage/context.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { isRunTree, RunTree } from "langsmith/run_trees";
import { BaseCallbackHandler } from "../../callbacks/base.js";
import {
_CONTEXT_VARIABLES_KEY,
AsyncLocalStorageProviderSingleton,
} from "./index.js";
import { BaseCallbackHandler } from "../../callbacks/base.js";
getGlobalAsyncLocalStorageInstance,
} from "./globals.js";

/**
* Set a context variable. Context variables are scoped to any
Expand Down Expand Up @@ -57,7 +57,14 @@ import { BaseCallbackHandler } from "../../callbacks/base.js";
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function setContextVariable<T>(name: PropertyKey, value: T): void {
const runTree = AsyncLocalStorageProviderSingleton.getInstance().getStore();
// Avoid using global singleton due to circuluar dependency issues
const asyncLocalStorageInstance = getGlobalAsyncLocalStorageInstance();
if (asyncLocalStorageInstance === undefined) {
throw new Error(
`Internal error: Global shared async local storage instance has not been initialized.`
);
}
const runTree = asyncLocalStorageInstance.getStore();
const contextVars = { ...runTree?.[_CONTEXT_VARIABLES_KEY] };
contextVars[name] = value;
let newValue = {};
Expand All @@ -66,7 +73,7 @@ export function setContextVariable<T>(name: PropertyKey, value: T): void {
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(newValue as any)[_CONTEXT_VARIABLES_KEY] = contextVars;
AsyncLocalStorageProviderSingleton.getInstance().enterWith(newValue);
asyncLocalStorageInstance.enterWith(newValue);
}

/**
Expand Down Expand Up @@ -120,7 +127,12 @@ export function setContextVariable<T>(name: PropertyKey, value: T): void {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getContextVariable<T = any>(name: PropertyKey): T | undefined {
const runTree = AsyncLocalStorageProviderSingleton.getInstance().getStore();
// Avoid using global singleton due to circuluar dependency issues
const asyncLocalStorageInstance = getGlobalAsyncLocalStorageInstance();
if (asyncLocalStorageInstance === undefined) {
return undefined;
}
const runTree = asyncLocalStorageInstance.getStore();
return runTree?.[_CONTEXT_VARIABLES_KEY]?.[name];
}

Expand Down
6 changes: 5 additions & 1 deletion langchain-core/src/singletons/async_local_storage/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ export interface AsyncLocalStorageInterface {

export const TRACING_ALS_KEY = Symbol.for("ls:tracing_async_local_storage");

export const _CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables");

export const setGlobalAsyncLocalStorageInstance = (
instance: AsyncLocalStorageInterface
) => {
(globalThis as any)[TRACING_ALS_KEY] = instance;
};

export const getGlobalAsyncLocalStorageInstance = () => {
export const getGlobalAsyncLocalStorageInstance = ():
| AsyncLocalStorageInterface
| undefined => {
return (globalThis as any)[TRACING_ALS_KEY];
};
3 changes: 1 addition & 2 deletions langchain-core/src/singletons/async_local_storage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AsyncLocalStorageInterface,
getGlobalAsyncLocalStorageInstance,
setGlobalAsyncLocalStorageInstance,
_CONTEXT_VARIABLES_KEY,
} from "./globals.js";
import { CallbackManager } from "../../callbacks/manager.js";
import { LangChainTracer } from "../../tracers/tracer_langchain.js";
Expand All @@ -26,8 +27,6 @@ const mockAsyncLocalStorage = new MockAsyncLocalStorage();

const LC_CHILD_KEY = Symbol.for("lc:child_config");

export const _CONTEXT_VARIABLES_KEY = Symbol.for("lc:context_variables");

class AsyncLocalStorageProvider {
getInstance(): AsyncLocalStorageInterface {
return getGlobalAsyncLocalStorageInstance() ?? mockAsyncLocalStorage;
Expand Down
14 changes: 6 additions & 8 deletions langchain-core/src/singletons/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,18 @@ export async function consumeCallback<T>(
if (wait === true) {
// Clear config since callbacks are not part of the root run
// Avoid using global singleton due to circuluar dependency issues
if (getGlobalAsyncLocalStorageInstance() !== undefined) {
await getGlobalAsyncLocalStorageInstance().run(undefined, async () =>
promiseFn()
);
const asyncLocalStorageInstance = getGlobalAsyncLocalStorageInstance();
if (asyncLocalStorageInstance !== undefined) {
await asyncLocalStorageInstance.run(undefined, async () => promiseFn());
} else {
await promiseFn();
}
} else {
queue = getQueue();
void queue.add(async () => {
if (getGlobalAsyncLocalStorageInstance() !== undefined) {
await getGlobalAsyncLocalStorageInstance().run(undefined, async () =>
promiseFn()
);
const asyncLocalStorageInstance = getGlobalAsyncLocalStorageInstance();
if (asyncLocalStorageInstance !== undefined) {
await asyncLocalStorageInstance.run(undefined, async () => promiseFn());
} else {
await promiseFn();
}
Expand Down
2 changes: 0 additions & 2 deletions langchain-core/src/singletons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
import {
type AsyncLocalStorageInterface,
AsyncLocalStorageProviderSingleton,
_CONTEXT_VARIABLES_KEY,
MockAsyncLocalStorage,
} from "./async_local_storage/index.js";

export {
type AsyncLocalStorageInterface,
AsyncLocalStorageProviderSingleton,
_CONTEXT_VARIABLES_KEY,
MockAsyncLocalStorage,
};

0 comments on commit 193de5b

Please sign in to comment.