mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-01 15:47:41 +08:00
fix(ai-builder): Include langsmith threadId on traces in code-builder (no-changelog) (#27424)
This commit is contained in:
+42
-1
@@ -76,7 +76,7 @@ function createMockBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom callback handler that captures chain end outputs.
|
||||
* Custom callback handler that captures chain end outputs and chain start metadata.
|
||||
* We use a class-based handler to ensure proper integration with
|
||||
* LangChain's CallbackManager.
|
||||
*/
|
||||
@@ -84,6 +84,20 @@ class ChainEndTracker extends BaseCallbackHandler {
|
||||
name = 'chain-end-tracker';
|
||||
|
||||
chainEndOutputs: Array<Record<string, unknown>> = [];
|
||||
chainStartMetadata: Array<Record<string, unknown>> = [];
|
||||
|
||||
async handleChainStart(
|
||||
_chain: unknown,
|
||||
_inputs: unknown,
|
||||
_runId: string,
|
||||
_parentRunId?: string,
|
||||
_tags?: string[],
|
||||
metadata?: Record<string, unknown>,
|
||||
): Promise<void> {
|
||||
if (metadata) {
|
||||
this.chainStartMetadata.push(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
async handleChainEnd(outputs: Record<string, unknown>): Promise<void> {
|
||||
this.chainEndOutputs.push(outputs);
|
||||
@@ -205,6 +219,33 @@ describe('CodeBuilderAgent tracing', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should include ls_thread_id from runMetadata in handleChainStart metadata', async () => {
|
||||
const tracker = new ChainEndTracker();
|
||||
|
||||
const agent = new CodeBuilderAgent({
|
||||
llm: createMockLlm(),
|
||||
nodeTypes: [],
|
||||
callbacks: [tracker],
|
||||
enableTextEditor: false,
|
||||
runMetadata: { ls_thread_id: 'workflow-test-wf-user-test-user' },
|
||||
});
|
||||
|
||||
const chunks = [];
|
||||
for await (const chunk of agent.chat(
|
||||
{ id: 'msg-4', message: 'Create a simple workflow' },
|
||||
'user-1',
|
||||
)) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
// The parent chain start should include ls_thread_id from runMetadata
|
||||
const parentStartMetadata = tracker.chainStartMetadata.find((m) => 'ls_thread_id' in m);
|
||||
expect(parentStartMetadata).toBeDefined();
|
||||
expect(parentStartMetadata).toMatchObject({
|
||||
ls_thread_id: 'workflow-test-wf-user-test-user',
|
||||
});
|
||||
});
|
||||
|
||||
it('should set output to null when no workflow is produced', async () => {
|
||||
// Make parse fail on all attempts so no workflow is generated
|
||||
parseWorkflowCodeToBuilder.mockImplementation(() => {
|
||||
|
||||
@@ -340,6 +340,9 @@ export class WorkflowBuilderAgent {
|
||||
userId: string | undefined,
|
||||
abortSignal: AbortSignal | undefined,
|
||||
) {
|
||||
const workflowId = payload.workflowContext?.currentWorkflow?.id;
|
||||
const threadId = SessionManagerService.generateThreadId(workflowId, userId);
|
||||
|
||||
const codeWorkflowBuilder = new CodeWorkflowBuilder({
|
||||
llm: this.stageLLMs.builder,
|
||||
nodeTypes: this.parsedNodeTypes,
|
||||
@@ -351,7 +354,8 @@ export class WorkflowBuilderAgent {
|
||||
runMetadata: {
|
||||
...this.runMetadata,
|
||||
userMessageId: payload.id,
|
||||
workflowId: payload.workflowContext?.currentWorkflow?.id,
|
||||
workflowId,
|
||||
ls_thread_id: threadId,
|
||||
},
|
||||
onTelemetryEvent: this.onTelemetryEvent,
|
||||
generatePinData: payload.featureFlags?.pinData ?? true,
|
||||
|
||||
Reference in New Issue
Block a user