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
6 changes: 0 additions & 6 deletions plugin/langchain/lib/graph/CompiledStateGraphObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,10 @@ export class CompiledStateGraphObject implements EggObject {
this._obj = await this.build();
const graph = this._obj as CompiledStateGraph<any, any>;

const originalInvoke = graph.invoke;
const originalStream = graph.stream;
const langGraphTraceObj = await EggContainerFactory.getOrCreateEggObjectFromName('langGraphTracer');
const tracer = langGraphTraceObj.obj as LangGraphTracer;
tracer.setName(this.graphName);


graph.invoke = (input: any, config?: any) =>
this.wrapGraphMethod(originalInvoke.bind(graph), input, config);

graph.stream = (input: any, config?: any) =>
this.wrapGraphMethod(originalStream.bind(graph), input, config);

Expand Down
25 changes: 25 additions & 0 deletions plugin/langchain/test/llm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,30 @@ describe('plugin/langchain/test/llm.test.ts', () => {
app.expectLog(/Executing FooNode thread_id is 1/);
app.expectLog(/traceId=test-trace-id/);
});

it('should persistRun be triggered when graph.invoke is called', async () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { LangGraphTracer } = require('../lib/tracing/LangGraphTracer');

const persistRunCalls: any[] = [];
const originalPersistRun = LangGraphTracer.prototype.persistRun;
mm(LangGraphTracer.prototype, 'persistRun', function(this: any, run: any) {
persistRunCalls.push(run);
return originalPersistRun.call(this, run);
});

app.mockLog();
mm(Tracer.prototype, 'traceId', 'test-persist-run-trace-id');

await app.httpRequest().get('/llm/graph');

assert(persistRunCalls.length > 0, 'persistRun should be called at least once');

const hasCorrectTraceId = persistRunCalls.some(run => run.trace_id === 'test-persist-run-trace-id');
assert(hasCorrectTraceId, 'persistRun should receive correct trace_id from invoke call');
Comment on lines +85 to +104
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find plugin/langchain -type f \( -name "*LangGraphTracer*" -o -name "*.ts" -o -name "*.js" \) | head -20

Repository: eggjs/tegg

Length of output: 1098


🏁 Script executed:

rg -l "class LangGraphTracer|persistRun" plugin/langchain --type ts --type js

Repository: eggjs/tegg

Length of output: 135


🏁 Script executed:

cat -n plugin/langchain/test/llm.test.ts | head -120

Repository: eggjs/tegg

Length of output: 4329


🏁 Script executed:

cat -n plugin/langchain/lib/tracing/LangGraphTracer.ts

Repository: eggjs/tegg

Length of output: 852


🏁 Script executed:

find plugin/langchain/test/fixtures -name "*Controller*" -o -name "*Graph*" | xargs grep -l "graph" 2>/dev/null

Repository: eggjs/tegg

Length of output: 222


🏁 Script executed:

cat -n plugin/langchain/test/fixtures/apps/langchain/app/modules/bar/controller/AppController.ts

Repository: eggjs/tegg

Length of output: 1980


🏁 Script executed:

rg -n "invoke|persistRun" plugin/langchain/lib/graph --type ts -A 2 -B 2

Repository: eggjs/tegg

Length of output: 36


🏁 Script executed:

rg "BaseTracer" plugin/langchain -A 5 -B 5 --type ts

Repository: eggjs/tegg

Length of output: 1107


Add explicit wait for persistRun invocation before asserting.

Since persistRun returns Promise<void>, the graph engine may invoke it without awaiting, creating a race condition between the HTTP response completing and persistRun calls being recorded. Add a polling mechanism with timeout before line 101 to ensure persistRunCalls are populated.

Suggested fix
      await app.httpRequest().get('/llm/graph');

+     await new Promise<void>((resolve, reject) => {
+       const start = Date.now();
+       const timer = setInterval(() => {
+         if (persistRunCalls.length > 0) {
+           clearInterval(timer);
+           resolve();
+           return;
+         }
+         if (Date.now() - start > 1000) {
+           clearInterval(timer);
+           reject(new Error('persistRun should be called at least once'));
+         }
+       }, 10);
+     });
+
      assert(persistRunCalls.length > 0, 'persistRun should be called at least once');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should persistRun be triggered when graph.invoke is called', async () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { LangGraphTracer } = require('../lib/tracing/LangGraphTracer');
const persistRunCalls: any[] = [];
const originalPersistRun = LangGraphTracer.prototype.persistRun;
mm(LangGraphTracer.prototype, 'persistRun', function(this: any, run: any) {
persistRunCalls.push(run);
return originalPersistRun.call(this, run);
});
app.mockLog();
mm(Tracer.prototype, 'traceId', 'test-persist-run-trace-id');
await app.httpRequest().get('/llm/graph');
assert(persistRunCalls.length > 0, 'persistRun should be called at least once');
const hasCorrectTraceId = persistRunCalls.some(run => run.trace_id === 'test-persist-run-trace-id');
assert(hasCorrectTraceId, 'persistRun should receive correct trace_id from invoke call');
it('should persistRun be triggered when graph.invoke is called', async () => {
// eslint-disable-next-line `@typescript-eslint/no-var-requires`
const { LangGraphTracer } = require('../lib/tracing/LangGraphTracer');
const persistRunCalls: any[] = [];
const originalPersistRun = LangGraphTracer.prototype.persistRun;
mm(LangGraphTracer.prototype, 'persistRun', function(this: any, run: any) {
persistRunCalls.push(run);
return originalPersistRun.call(this, run);
});
app.mockLog();
mm(Tracer.prototype, 'traceId', 'test-persist-run-trace-id');
await app.httpRequest().get('/llm/graph');
await new Promise<void>((resolve, reject) => {
const start = Date.now();
const timer = setInterval(() => {
if (persistRunCalls.length > 0) {
clearInterval(timer);
resolve();
return;
}
if (Date.now() - start > 1000) {
clearInterval(timer);
reject(new Error('persistRun should be called at least once'));
}
}, 10);
});
assert(persistRunCalls.length > 0, 'persistRun should be called at least once');
const hasCorrectTraceId = persistRunCalls.some(run => run.trace_id === 'test-persist-run-trace-id');
assert(hasCorrectTraceId, 'persistRun should receive correct trace_id from invoke call');
🤖 Prompt for AI Agents
In `@plugin/langchain/test/llm.test.ts` around lines 85 - 104, The test has a race
where persistRun (LangGraphTracer.prototype.persistRun) may be invoked
asynchronously, so before asserting on persistRunCalls you should poll/wait
until persistRunCalls is non-empty (or timeout) to ensure the call was recorded;
implement a short async polling loop (e.g., await a small delay repeatedly up to
a timeout) after the HTTP request and before the assert that checks
persistRunCalls.length, failing the test if the timeout elapses, then continue
to assert the trace_id as before.


app.expectLog(/agent_run/);
app.expectLog(/traceId=test-persist-run-trace-id/);
});
}
});