From langchain-pack
Collects LangChain diagnostics: environment info, @langchain deps, LLM traces via callbacks, error logs for bug reports and LangSmith. Use for troubleshooting failures.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin langchain-packThis skill is limited to using the following tools:
!`node --version 2>/dev/null || echo 'N/A'`
Diagnoses and fixes common LangChain errors like import failures, auth issues, output parsing, chain inputs, and version mismatches in Python and JavaScript.
Generates Langfuse debug bundle with env versions, SDK details, redacted config, API health checks, and logs for support tickets and troubleshooting.
Fetches and analyzes LangSmith traces to debug LangChain and LangGraph agents. Use for agent errors, tool calls, memory operations, and performance review.
Share bugs, ideas, or general feedback.
!node --version 2>/dev/null || echo 'N/A'
!python3 --version 2>/dev/null || echo 'N/A'
Collect comprehensive diagnostic information for LangChain issues: environment info, dependency versions, chain execution traces, and minimal reproduction scripts.
import { execSync } from "child_process";
import * as fs from "fs";
function collectEnvironment() {
const env: Record<string, string> = {};
env.nodeVersion = process.version;
env.platform = `${process.platform} ${process.arch}`;
// Get @langchain/* versions
try {
const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
for (const [name, version] of Object.entries(deps)) {
if (name.startsWith("@langchain") || name === "langchain") {
env[name] = version as string;
}
}
} catch {}
// Check env vars (redacted)
env.OPENAI_API_KEY = process.env.OPENAI_API_KEY ? "set (redacted)" : "NOT SET";
env.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY ? "set (redacted)" : "NOT SET";
env.LANGSMITH_TRACING = process.env.LANGSMITH_TRACING ?? "NOT SET";
return env;
}
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
interface TraceEvent {
timestamp: string;
event: string;
data: Record<string, any>;
}
class DebugTraceHandler extends BaseCallbackHandler {
name = "DebugTraceHandler";
events: TraceEvent[] = [];
private log(event: string, data: Record<string, any>) {
this.events.push({
timestamp: new Date().toISOString(),
event,
data,
});
}
handleLLMStart(llm: any, prompts: string[]) {
this.log("llm_start", {
model: llm?.id?.[2] ?? "unknown",
promptCount: prompts.length,
firstPromptLength: prompts[0]?.length ?? 0,
});
}
handleLLMEnd(output: any) {
this.log("llm_end", {
generations: output.generations?.length ?? 0,
tokenUsage: output.llmOutput?.tokenUsage ?? null,
});
}
handleLLMError(error: Error) {
this.log("llm_error", {
name: error.name,
message: error.message,
stack: error.stack?.split("\n").slice(0, 5).join("\n"),
});
}
handleToolStart(_tool: any, input: string) {
this.log("tool_start", { input: input.slice(0, 200) });
}
handleToolEnd(output: string) {
this.log("tool_end", { output: output.slice(0, 200) });
}
handleToolError(error: Error) {
this.log("tool_error", { name: error.name, message: error.message });
}
toJSON() {
return JSON.stringify(this.events, null, 2);
}
}
import * as fs from "fs";
async function generateDebugBundle(
chain: any,
testInput: Record<string, any>,
outputPath = "debug_bundle.json",
) {
const tracer = new DebugTraceHandler();
const env = collectEnvironment();
let result: any = null;
let error: any = null;
try {
result = await chain.invoke(testInput, { callbacks: [tracer] });
} catch (e: any) {
error = {
name: e.name,
message: e.message,
stack: e.stack?.split("\n").slice(0, 10).join("\n"),
};
}
const bundle = {
generatedAt: new Date().toISOString(),
environment: env,
input: testInput,
result: result ? "(success)" : null,
error,
traceEvents: tracer.events,
eventCount: tracer.events.length,
};
fs.writeFileSync(outputPath, JSON.stringify(bundle, null, 2));
console.log(`Debug bundle written to ${outputPath}`);
console.log(` Events captured: ${tracer.events.length}`);
console.log(` Status: ${error ? "FAILED" : "SUCCESS"}`);
return bundle;
}
// Usage:
// await generateDebugBundle(myChain, { input: "test query" });
// Save as minimal_repro.ts
// Run: npx tsx minimal_repro.ts
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
const model = new ChatOpenAI({ model: "gpt-4o-mini" });
const prompt = ChatPromptTemplate.fromTemplate("{input}");
const chain = prompt.pipe(model).pipe(new StringOutputParser());
try {
const result = await chain.invoke({ input: "Hello" });
console.log("SUCCESS:", result);
} catch (error) {
console.error("FAILED:", error);
}
# Export traces from LangSmith for a specific project
# pip install langsmith
python3 -c "
from langsmith import Client
import json
client = Client()
runs = list(client.list_runs(
project_name='my-project',
execution_order=1,
limit=10,
error=True, # only failed runs
))
for run in runs:
print(json.dumps({
'id': str(run.id),
'name': run.name,
'status': run.status,
'error': run.error,
'start': str(run.start_time),
'latency': str(run.end_time - run.start_time) if run.end_time else None,
'tokens': run.total_tokens,
}, indent=2))
"
Include in your GitHub issue:
| Issue | Cause | Fix |
|---|---|---|
| Callback not capturing events | Not passed to invoke | Use { callbacks: [tracer] } as second arg |
| API key in bundle | Missing redaction | Filter env vars before export |
| Large trace file | Long-running chain | Filter events by time range |
Use langchain-common-errors for quick fixes or escalate with the debug bundle.