Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/core/lib/v3/flowlogger/FlowLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,15 @@ export class FlowLogger {
parentEvents: [],
};

loggerContext.enterWith(ctx);
try {
loggerContext.enterWith(ctx);
} catch {
// Some runtimes (e.g. Cloudflare Workers) do not implement enterWith()
// because it mutates context across concurrent requests, which is unsafe
// in that environment. Fall through: the context is still returned and
// callers that need ALS can use loggerContext.run() via runWithLogging()
// or withContext().
}
return ctx;
}

Expand Down
28 changes: 28 additions & 0 deletions packages/core/tests/unit/flowlogger-capturing-llm.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { AsyncLocalStorage } from "node:async_hooks";
import { describe, expect, it } from "vitest";
import { FlowLogger } from "../../lib/v3/flowlogger/FlowLogger.js";
import { EventEmitterWithWildcardSupport } from "../../lib/v3/flowlogger/EventEmitter.js";

describe("flow logger llm logging", () => {
it("no-ops direct llm logging calls when no flow context is active", () => {
Expand Down Expand Up @@ -47,4 +49,30 @@ describe("flow logger llm logging", () => {
text: "done",
});
});

it("FlowLogger.init() does not throw when enterWith() is not implemented (e.g. Cloudflare Workers)", () => {
// Simulate a runtime that omits enterWith() from AsyncLocalStorage.
const originalEnterWith = AsyncLocalStorage.prototype.enterWith;
Object.defineProperty(AsyncLocalStorage.prototype, "enterWith", {
value: undefined,
configurable: true,
writable: true,
});

try {
const bus = new EventEmitterWithWildcardSupport();
let ctx: ReturnType<typeof FlowLogger.init> | undefined;
expect(() => {
ctx = FlowLogger.init("session-cloudflare", bus);
}).not.toThrow();
// The returned context must still be valid even without ALS support.
expect(ctx).toMatchObject({ sessionId: "session-cloudflare" });
} finally {
Object.defineProperty(AsyncLocalStorage.prototype, "enterWith", {
value: originalEnterWith,
configurable: true,
writable: true,
});
}
});
});
Loading