diff --git a/.changeset/langgraph-sdk-instrumentation.md b/.changeset/langgraph-sdk-instrumentation.md new file mode 100644 index 000000000..a9fde7b8a --- /dev/null +++ b/.changeset/langgraph-sdk-instrumentation.md @@ -0,0 +1,5 @@ +--- +"braintrust": minor +--- + +feat: Add `@langchain/langgraph-sdk` instrumentation diff --git a/e2e/config/pr-comment-scenarios.json b/e2e/config/pr-comment-scenarios.json index 696cf0c64..351a2bcbb 100644 --- a/e2e/config/pr-comment-scenarios.json +++ b/e2e/config/pr-comment-scenarios.json @@ -778,6 +778,21 @@ } ] }, + { + "scenarioDirName": "langgraph-sdk-instrumentation", + "label": "LangGraph Platform SDK Instrumentation", + "metadataScenario": "langgraph-sdk-instrumentation", + "variants": [ + { + "variantKey": "langgraph-sdk-v1", + "label": "v1 pinned" + }, + { + "variantKey": "langgraph-sdk-v1-latest", + "label": "v1 latest" + } + ] + }, { "scenarioDirName": "elevenlabs-instrumentation", "label": "ElevenLabs Instrumentation", diff --git a/e2e/helpers/mock-braintrust-server.test.ts b/e2e/helpers/mock-braintrust-server.test.ts new file mode 100644 index 000000000..7bdd1f25d --- /dev/null +++ b/e2e/helpers/mock-braintrust-server.test.ts @@ -0,0 +1,134 @@ +import { createServer } from "node:http"; +import type { AddressInfo } from "node:net"; +import { setTimeout } from "node:timers/promises"; +import { describe, expect, it } from "vitest"; +import { startMockBraintrustServer } from "./mock-braintrust-server"; + +describe("production forwarding", () => { + it.each(["/logs3", "/otel/v1/traces"])( + "preserves write order for %s even when the initial write is slow", + async (path) => { + let releaseInitial!: () => void; + const initialGate = new Promise((resolve) => { + releaseInitial = resolve; + }); + let initialReceived!: () => void; + const initialStarted = new Promise((resolve) => { + initialReceived = resolve; + }); + const applied: number[] = []; + let stored: Record = {}; + const upstream = createServer(async (req, res) => { + let body = ""; + for await (const chunk of req) body += chunk; + const { + sequence, + rows: [row], + } = JSON.parse(body); + if (sequence === 1) { + initialReceived(); + await initialGate; + } + stored = row._is_merge ? { ...stored, ...row } : row; + applied.push(sequence); + res.end("{}"); + }); + await new Promise((resolve) => + upstream.listen(0, "127.0.0.1", resolve), + ); + const url = `http://127.0.0.1:${(upstream.address() as AddressInfo).port}`; + const server = await startMockBraintrustServer({ + prodForwarding: { + apiKey: "test-only-key", + apiUrl: url, + appUrl: url, + orgId: "org", + orgName: "org", + projectId: "project", + projectName: "tmp-luca-forwarding-test", + }, + }); + try { + for (const [index, row] of [ + { id: "span", input: "hello", metrics: { start: 1 } }, + { + id: "span", + _is_merge: true, + error: "expected failure", + metrics: { start: 1, end: 2 }, + }, + ].entries()) { + const response = await fetch(`${server.url}${path}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + api_version: 2, + sequence: index + 1, + rows: [row], + }), + }); + expect(response.ok).toBe(true); + await response.text(); + if (index === 0) await initialStarted; + } + // Give an incorrectly concurrent second request time to overtake the + // gated initial upsert. The mock should still acknowledge both promptly. + await setTimeout(50); + releaseInitial(); + await server.close(); + expect(applied).toEqual([1, 2]); + expect(stored).toMatchObject({ + input: "hello", + error: "expected failure", + metrics: { end: 2 }, + }); + } finally { + releaseInitial(); + upstream.closeAllConnections(); + await new Promise((resolve) => upstream.close(() => resolve())); + } + }, + ); + + it("reports a failed write without preventing later queued writes", async () => { + const received: number[] = []; + const upstream = createServer(async (req, res) => { + let body = ""; + for await (const chunk of req) body += chunk; + const { sequence } = JSON.parse(body); + received.push(sequence); + res.statusCode = sequence === 1 ? 500 : 200; + res.end(sequence === 1 ? "initial write failed" : "{}"); + }); + await new Promise((resolve) => + upstream.listen(0, "127.0.0.1", resolve), + ); + const url = `http://127.0.0.1:${(upstream.address() as AddressInfo).port}`; + const server = await startMockBraintrustServer({ + prodForwarding: { + apiKey: "test-only-key", + apiUrl: url, + appUrl: url, + orgId: "org", + orgName: "org", + projectId: "project", + projectName: "tmp-luca-forwarding-test", + }, + }); + try { + for (const sequence of [1, 2]) { + const response = await fetch(`${server.url}/logs3`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ sequence, api_version: 2, rows: [] }), + }); + await response.text(); + } + await expect(server.close()).rejects.toThrow("initial write failed"); + expect(received).toEqual([1, 2]); + } finally { + upstream.closeAllConnections(); + await new Promise((resolve) => upstream.close(() => resolve())); + } + }); +}); diff --git a/e2e/helpers/mock-braintrust-server.ts b/e2e/helpers/mock-braintrust-server.ts index 7f59a57ed..14a42dbc3 100644 --- a/e2e/helpers/mock-braintrust-server.ts +++ b/e2e/helpers/mock-braintrust-server.ts @@ -290,7 +290,7 @@ export async function startMockBraintrustServer( >(); let serverUrl = ""; let xactCursor = 0; - const pendingProdForwarding = new Set>(); + let prodForwardingTail = Promise.resolve(); if (prodForwarding) { projectsByName.set(prodForwarding.projectName, { @@ -402,17 +402,15 @@ export async function startMockBraintrustServer( ); } - function trackProdForwarding(context: string, promise: Promise): void { - pendingProdForwarding.add(promise); - void promise.then( - () => { - pendingProdForwarding.delete(promise); - }, - (error) => { - recordProdForwardingError(context, error); - pendingProdForwarding.delete(promise); - }, - ); + function trackProdForwarding( + context: string, + send: () => Promise, + ): void { + // A later upsert can overwrite an earlier merge. Acknowledge the local + // request promptly, but preserve ingestion order when forwarding upstream. + prodForwardingTail = prodForwardingTail.then(send).catch((error) => { + recordProdForwardingError(context, error); + }); } function requestForProdForwarding( @@ -734,8 +732,7 @@ export async function startMockBraintrustServer( persistPayload(payload); } if (prodForwarding) { - trackProdForwarding( - "POST /logs3", + trackProdForwarding("POST /logs3", () => forwardProdRequest(capturedRequest, { drainResponseBody: true, }).then(() => undefined), @@ -750,8 +747,7 @@ export async function startMockBraintrustServer( capturedRequest.path === "/otel/v1/traces" ) { if (prodForwarding) { - trackProdForwarding( - "POST /otel/v1/traces", + trackProdForwarding("POST /otel/v1/traces", () => forwardProdRequest(capturedRequest, { drainResponseBody: true, }).then(() => undefined), @@ -785,9 +781,7 @@ export async function startMockBraintrustServer( await new Promise((resolve, reject) => { server.close((error) => (error ? reject(error) : resolve())); }); - while (pendingProdForwarding.size > 0) { - await Promise.allSettled([...pendingProdForwarding]); - } + await prodForwardingTail; if (prodForwardingErrors.length > 0) { throw new Error( [ diff --git a/e2e/helpers/pr-e2e-links.test.ts b/e2e/helpers/pr-e2e-links.test.ts new file mode 100644 index 000000000..dea3090e9 --- /dev/null +++ b/e2e/helpers/pr-e2e-links.test.ts @@ -0,0 +1,59 @@ +import { execFile } from "node:child_process"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { promisify } from "node:util"; +import { fileURLToPath } from "node:url"; +import { expect, it } from "vitest"; + +it("links published runs while preserving legacy records and excluding local-only runs", async () => { + const dir = await mkdtemp(path.join(tmpdir(), "braintrust-e2e-links-")); + const configPath = path.join(dir, "config.json"); + try { + await writeFile( + configPath, + JSON.stringify([ + { + scenarioDirName: "scenario", + label: "Scenario", + metadataScenario: "scenario", + }, + ]), + ); + await writeFile( + path.join(dir, "runs.ndjson"), + [ + { testRunId: "e2e-published", forwardToProduction: true }, + { testRunId: "e2e-local-only", forwardToProduction: false }, + { testRunId: "e2e-legacy" }, + ] + .map((record) => + JSON.stringify({ scenarioDirName: "scenario", ...record }), + ) + .join("\n"), + ); + const { stdout } = await promisify(execFile)( + process.execPath, + [ + fileURLToPath( + new URL("../scripts/build-pr-e2e-links-comment.mjs", import.meta.url), + ), + "--config", + configPath, + ], + { + env: { + ...process.env, + BRAINTRUST_API_KEY: "", + BRAINTRUST_ORG_NAME: "Test", + BRAINTRUST_E2E_RUN_CONTEXT_DIR: dir, + }, + }, + ); + expect(stdout).toContain("e2e-published"); + expect(stdout).toContain("e2e-legacy"); + expect(stdout).not.toContain("e2e-local-only"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/e2e/helpers/scenario-harness.ts b/e2e/helpers/scenario-harness.ts index bd90a6dec..0816f0414 100644 --- a/e2e/helpers/scenario-harness.ts +++ b/e2e/helpers/scenario-harness.ts @@ -80,6 +80,7 @@ export interface ScenarioRunContext { } interface ScenarioRunContextRecord { + forwardToProduction?: boolean; entry: string; runner: ScenarioRunner; scenarioDirName: string; @@ -700,9 +701,13 @@ interface ScenarioHarness { export async function withScenarioHarness( body: (harness: ScenarioHarness) => Promise, + optionsForHarness: { forwardToProduction?: boolean } = {}, ): Promise { const { getProdForwarding } = await import("./prod-forwarding"); - const prodForwarding = getProdForwarding(); + const prodForwarding = + optionsForHarness.forwardToProduction === false + ? null + : getProdForwarding(); const testRunId = createTestRunId(); const server = await startMockBraintrustServer({ prodForwarding, @@ -832,6 +837,7 @@ export async function withScenarioHarness( ): Promise => { const result = await run(); await recordScenarioRunContext({ + forwardToProduction: optionsForHarness.forwardToProduction, entry: options.entry ?? defaultEntry, runner, scenarioDirName: path.basename( diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1-latest.cassette.json b/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1-latest.cassette.json new file mode 100644 index 000000000..d8b5afbe0 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1-latest.cassette.json @@ -0,0 +1,577 @@ +{ + "entries": [ + { + "callIndex": 0, + "id": "6a6568cead910943", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:48.795Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"ACzCbZ4h\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"Ur4ok\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"MiaeC\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"7x4h0\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"O3nsD\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"Ce4O\"}", + "data: {\"id\":\"chatcmpl-ELqhMhLzTGYV7OJGEry45DxPn6MfB\",\"object\":\"chat.completion.chunk\",\"created\":1788876168,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"8wOb5bLC7L\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e340f6962a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:48 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "284", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_751c2a5084b34f62b2b4ee7e41876360" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 1, + "id": "cef53ad7c82ede16", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:50.368Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"ptX2abuF\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"nyIuB\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"LvG3W\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"oUatP\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"yaB96\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"rfZu\"}", + "data: {\"id\":\"chatcmpl-ELqhNx2rcZPWEJgK9fHq9b34f4gDm\",\"object\":\"chat.completion.chunk\",\"created\":1788876169,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"HLiIKohAng\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e3c2f9762a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:50 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "390", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999990", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_4ca468e02adf48bc88b1b5385bd19394" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 2, + "id": "ca6e36e742da88e2", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:52.343Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"2ux1cD03\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"rnszV\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"SAItu\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"yDmhV\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"waFRk\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"gFLv\"}", + "data: {\"id\":\"chatcmpl-ELqhP7KcZJSpLTlX4WDEeVCVHZbY3\",\"object\":\"chat.completion.chunk\",\"created\":1788876171,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"hemzZitF4i\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e47fd8962a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:52 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "507", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_d8fdf1f755b745daa40f846bacdf769d" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 3, + "id": "8bf46d0f97bf9ead", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:53.913Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"9sn7uF3i\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"vmSqK\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"wZIbM\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"UiniP\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"P1ja5\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"qfum\"}", + "data: {\"id\":\"chatcmpl-ELqhR5OIHQatL10D6mBVqXglP9wY5\",\"object\":\"chat.completion.chunk\",\"created\":1788876173,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"jarCNewgte\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e53c8af62a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:53 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "320", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_db11d1063e9e4bcb813191081391b911" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 4, + "id": "cc9542c3d3b261c2", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:55.442Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"E5hsbJ1e\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"leBtI\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"wfuBC\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"9QBHG\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"QAoLv\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"6jh8\"}", + "data: {\"id\":\"chatcmpl-ELqhTFitorfEYbCWzZvXcJYyVvsVQ\",\"object\":\"chat.completion.chunk\",\"created\":1788876175,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"AQgtxUbb2t\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e5cdf7c62a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:55 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "367", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999990", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_e9953246ef70459892e7d37835e15f46" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 5, + "id": "6b6abc7300f83b73", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:02:56.792Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"AHZvO08m\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"DeYH5\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"3eeYw\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"e2Nrs\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"wJVGD\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"Nii1\"}", + "data: {\"id\":\"chatcmpl-ELqhUn8mnS1nKBg2merZvlujZTNji\",\"object\":\"chat.completion.chunk\",\"created\":1788876176,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"kpPLsU9T7v\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e64fd6262a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:02:56 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "367", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_10975a58ba844a66ab94e64e0ed1bf60" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 6, + "id": "ad9ac88c6990957e", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:03:00.772Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhYIMJtXdgeYDYOSyNuT86vdD4p\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"qYiZPsDO\"}", + "data: {\"id\":\"chatcmpl-ELqhYIMJtXdgeYDYOSyNuT86vdD4p\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"right\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"MQm4K\"}", + "data: {\"id\":\"chatcmpl-ELqhYIMJtXdgeYDYOSyNuT86vdD4p\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"fQYA\"}", + "data: {\"id\":\"chatcmpl-ELqhYIMJtXdgeYDYOSyNuT86vdD4p\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[],\"usage\":{\"prompt_tokens\":12,\"completion_tokens\":1,\"total_tokens\":13,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"0zpj17GI10\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e7f5ed6369b-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:03:00 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "189", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999992", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_1703edb3d72940cba5abc40a4e1d8293" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 7, + "id": "520d6b55680aaa6e", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:03:00.890Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqhYai9s9PrxQrgoxvFGDB0XTQIM\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"z05qK1NR\"}", + "data: {\"id\":\"chatcmpl-ELqhYai9s9PrxQrgoxvFGDB0XTQIM\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"left\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"sIdOwj\"}", + "data: {\"id\":\"chatcmpl-ELqhYai9s9PrxQrgoxvFGDB0XTQIM\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"Moc4\"}", + "data: {\"id\":\"chatcmpl-ELqhYai9s9PrxQrgoxvFGDB0XTQIM\",\"object\":\"chat.completion.chunk\",\"created\":1788876180,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[],\"usage\":{\"prompt_tokens\":12,\"completion_tokens\":1,\"total_tokens\":13,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"pxHwlT2V8o\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7e7ed82f62a0-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:03:00 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "394", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999992", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_7e059ea1a52b48a4ad6430ece588fbb4" + }, + "status": 200, + "statusText": "OK" + } + } + ], + "meta": { + "createdAt": "2026-09-08T14:01:12.079Z" + } +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1.cassette.json b/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1.cassette.json new file mode 100644 index 000000000..6aec1c8c2 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__cassettes__/langgraph-sdk-v1.cassette.json @@ -0,0 +1,577 @@ +{ + "entries": [ + { + "callIndex": 0, + "id": "6a6568cead910943", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:48.011Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"9UTZ6SFA\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"Atmar\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"AQMau\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"X9k94\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"NBQpr\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"pBMV\"}", + "data: {\"id\":\"chatcmpl-ELqfPrMDhcWQtuSD0ZsbmpmFb2x56\",\"object\":\"chat.completion.chunk\",\"created\":1788876047,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"2c8vgsYclr\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b402b94da5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:47 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "319", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_6a6b425bed2b4d7194d317a564d47d82" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 1, + "id": "cef53ad7c82ede16", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:49.083Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"9mgXJKLh\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"6QdmO\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"0JOon\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"ujyaS\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"6hZJI\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"GG4j\"}", + "data: {\"id\":\"chatcmpl-ELqfQWuuHREgWiqkycJZkQrlp3XOF\",\"object\":\"chat.completion.chunk\",\"created\":1788876048,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"sBrGBiBhar\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b47cc0fda5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:48 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "306", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_aed7e2315ed34d2ca40f73d9dbaee47a" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 2, + "id": "ca6e36e742da88e2", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:51.369Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"Sp1o3tQS\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"d3X68\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"j4QFJ\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"unpKu\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"vGaia\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"aDns\"}", + "data: {\"id\":\"chatcmpl-ELqfST0Kxx9VYsFu8lzhCKcX9LkHp\",\"object\":\"chat.completion.chunk\",\"created\":1788876050,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_cbf9666c94\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"wHIyUuTcEJ\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b54abdfda5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:51 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "433", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_c15417d0f38e407da3d4c8296596807b" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 3, + "id": "8bf46d0f97bf9ead", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:52.630Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"7KGR45Ei\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"VM5UW\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"gk7aL\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"4FaPI\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"sX57R\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"VRdf\"}", + "data: {\"id\":\"chatcmpl-ELqfUjwZObbclrE4oTtGWI8XfVwY1\",\"object\":\"chat.completion.chunk\",\"created\":1788876052,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"ybuiDPtoZH\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b5cba4bda5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:52 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "383", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_9a17db25b42f44e5b3a02d01e5b747da" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 4, + "id": "cc9542c3d3b261c2", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:53.741Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"HX27ao7R\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"fD6CB\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"W1Htt\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"meHoa\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"jGVJe\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"65KM\"}", + "data: {\"id\":\"chatcmpl-ELqfVyYdijar2J7TKZuOMK7kUH5ks\",\"object\":\"chat.completion.chunk\",\"created\":1788876053,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"TjuA8mnceX\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b644d73da5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:53 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "412", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_46eb78ce9ed4497c9915326eabb46956" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 5, + "id": "6b6abc7300f83b73", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:55.023Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"WWoeWpQx\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"hello\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"6c76A\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" from\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"pbphQ\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" lang\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"wPYug\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"graph\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"ZnncV\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"JufU\"}", + "data: {\"id\":\"chatcmpl-ELqfWDfgDjvkFoxYwiP2jTBZH58g1\",\"object\":\"chat.completion.chunk\",\"created\":1788876054,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_973a2ed1e3\",\"choices\":[],\"usage\":{\"prompt_tokens\":15,\"completion_tokens\":4,\"total_tokens\":19,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"bJ5wCPHMdn\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b6b88e8da5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:54 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "485", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999987", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_50ee105d42bb4dafa5589da379efffc1" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 6, + "id": "82a1674f31ce0a44", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:58.031Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfZbcfMPDu23FX0GlbKKB7n6wJ2\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"qxcFJmLt\"}", + "data: {\"id\":\"chatcmpl-ELqfZbcfMPDu23FX0GlbKKB7n6wJ2\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"left\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"pVn4Q0\"}", + "data: {\"id\":\"chatcmpl-ELqfZbcfMPDu23FX0GlbKKB7n6wJ2\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"i1T5\"}", + "data: {\"id\":\"chatcmpl-ELqfZbcfMPDu23FX0GlbKKB7n6wJ2\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_fe1e84f9af\",\"choices\":[],\"usage\":{\"prompt_tokens\":12,\"completion_tokens\":1,\"total_tokens\":13,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"anT925RLUw\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b7fb818da5c-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:57 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "303", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999992", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_31b5528df9084d31817070857b6109e4" + }, + "status": 200, + "statusText": "OK" + } + }, + { + "callIndex": 7, + "id": "ce58a1729b37ca34", + "matchKey": "POST api.openai.com/v1/chat/completions", + "recordedAt": "2026-09-08T14:00:58.271Z", + "request": { + "body": { + "kind": "json", + "value": { + "max_tokens": 64, + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ], + "model": "gpt-4.1-nano", + "stream": true, + "stream_options": { + "include_usage": true + }, + "temperature": 0 + } + }, + "headers": {}, + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "body": { + "chunks": [ + "data: {\"id\":\"chatcmpl-ELqfZK3oKap1OB2aPOga4gCRki2uC\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\",\"refusal\":null},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"Rqrc4GW5\"}", + "data: {\"id\":\"chatcmpl-ELqfZK3oKap1OB2aPOga4gCRki2uC\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"right\"},\"logprobs\":null,\"finish_reason\":null}],\"usage\":null,\"obfuscation\":\"CQNlg\"}", + "data: {\"id\":\"chatcmpl-ELqfZK3oKap1OB2aPOga4gCRki2uC\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[{\"index\":0,\"delta\":{},\"logprobs\":null,\"finish_reason\":\"stop\"}],\"usage\":null,\"obfuscation\":\"dCpI\"}", + "data: {\"id\":\"chatcmpl-ELqfZK3oKap1OB2aPOga4gCRki2uC\",\"object\":\"chat.completion.chunk\",\"created\":1788876057,\"model\":\"gpt-4.1-nano-2025-04-14\",\"service_tier\":\"default\",\"system_fingerprint\":\"fp_a806186e36\",\"choices\":[],\"usage\":{\"prompt_tokens\":12,\"completion_tokens\":1,\"total_tokens\":13,\"prompt_tokens_details\":{\"cached_tokens\":0,\"audio_tokens\":0},\"completion_tokens_details\":{\"reasoning_tokens\":0,\"audio_tokens\":0,\"accepted_prediction_tokens\":0,\"rejected_prediction_tokens\":0}},\"obfuscation\":\"thlOkrEEc9\"}", + "data: [DONE]" + ], + "kind": "sse" + }, + "headers": { + "access-control-expose-headers": "X-Request-ID, CF-Ray, CF-Ray", + "alt-svc": "h3=\":443\"; ma=86400", + "cf-cache-status": "DYNAMIC", + "cf-ray": "a37e7b80cf3de87f-IAD", + "connection": "keep-alive", + "content-type": "text/event-stream; charset=utf-8", + "date": "Tue, 08 Sep 2026 14:00:58 GMT", + "openai-organization": "braintrust-data", + "openai-processing-ms": "264", + "openai-project": "proj_vsCSXafhhByzWOThMrJcZiw9", + "openai-version": "2020-10-01", + "server": "cloudflare", + "set-cookie": "[REDACTED]", + "strict-transport-security": "max-age=31536000; includeSubDomains; preload", + "transfer-encoding": "chunked", + "x-content-type-options": "nosniff", + "x-openai-proxy-wasm": "v0.1", + "x-ratelimit-limit-requests": "30000", + "x-ratelimit-limit-tokens": "150000000", + "x-ratelimit-remaining-requests": "29999", + "x-ratelimit-remaining-tokens": "149999990", + "x-ratelimit-reset-requests": "2ms", + "x-ratelimit-reset-tokens": "0s", + "x-request-id": "req_043b7027934c4c8fa587074e874d4d47" + }, + "status": 200, + "statusText": "OK" + } + } + ], + "meta": { + "createdAt": "2026-09-08T13:58:26.607Z" + } +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.json new file mode 100644 index 000000000..63d0aac5d --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (cjs, auto)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.txt new file mode 100644 index 000000000..9ab50d379 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-auto.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (cjs, auto) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.json new file mode 100644 index 000000000..29852985f --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (cjs, both)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.txt new file mode 100644 index 000000000..56d23bb21 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-both.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (cjs, both) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.json new file mode 100644 index 000000000..d02d9d5dc --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (cjs, wrapped)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.txt new file mode 100644 index 000000000..3c6e959c1 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-cjs-wrapped.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (cjs, wrapped) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.json new file mode 100644 index 000000000..02aef061c --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (esm, auto)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.txt new file mode 100644 index 000000000..baec4e17c --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-auto.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (esm, auto) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.json new file mode 100644 index 000000000..8171edb3b --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (esm, both)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.txt new file mode 100644 index 000000000..218bfa862 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-both.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (esm, both) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.json new file mode 100644 index 000000000..ab4a092f4 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.9.25 (esm, wrapped)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.txt new file mode 100644 index 000000000..132af2dc6 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-esm-wrapped.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.9.25 (esm, wrapped) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.9.25", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.json new file mode 100644 index 000000000..8f7024eed --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (cjs, auto)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.txt new file mode 100644 index 000000000..8dad21314 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-auto.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (cjs, auto) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.json new file mode 100644 index 000000000..4a75b2783 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (cjs, both)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.txt new file mode 100644 index 000000000..b413dfb0a --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-both.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (cjs, both) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.json new file mode 100644 index 000000000..ef70dfb92 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (cjs, wrapped)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.txt new file mode 100644 index 000000000..15059f20b --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-cjs-wrapped.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (cjs, wrapped) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "cjs", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.json new file mode 100644 index 000000000..64415f097 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (esm, auto)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.txt new file mode 100644 index 000000000..2d66dd1e2 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-auto.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (esm, auto) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "auto", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.json new file mode 100644 index 000000000..ad60001bc --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (esm, both)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.txt new file mode 100644 index 000000000..c47b0f6da --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-both.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (esm, both) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "both", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.json b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.json new file mode 100644 index 000000000..063fefd6e --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.json @@ -0,0 +1,526 @@ +{ + "span_tree": [ + { + "name": "LangGraph SDK 1.10.2 (esm, wrapped)", + "type": "task", + "children": [ + { + "name": "Uninstrumented background APIs", + "children": [], + "metadata": { + "operation": "background-apis", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Wait for final result", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "wait", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Interrupt and resume", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.interrupts": [ + { + "id": "", + "value": "Approve the model call?" + } + ], + "langgraph.thread_id": "" + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "command": { + "resume": "yes" + } + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "approval", + "langgraph.thread_id": "" + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "interrupt-resume", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream values mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages", + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "values", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream messages mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "messages" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "messages", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream updates mode", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "output": { + "content": "hello from langgraph", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "updates" + ], + "streamSubgraphs": true + }, + "metrics": { + "completion_tokens": 4, + "prompt_tokens": 15, + "time_to_first_token": 0, + "tokens": 19 + } + } + ], + "metadata": { + "operation": "updates", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Stream error", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.run_id": "", + "langgraph.thread_id": null, + "streamMode": [ + "values", + "messages" + ], + "streamSubgraphs": true + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "stream-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Cancel stream", + "children": [ + { + "name": "langgraph.runs.stream", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "interruptBefore": [ + "agent" + ], + "langgraph.assistant_id": "agent", + "langgraph.run_id": "", + "langgraph.thread_id": null + } + } + ], + "metadata": { + "operation": "cancel", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Missing assistant error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "missing-assistant", + "langgraph.thread_id": null + }, + "error": "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + } + ], + "metadata": { + "operation": "missing-assistant-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Thrown graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "thrown-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Returned graph error", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + }, + "metadata": { + "langgraph.assistant_id": "failing", + "langgraph.thread_id": null + }, + "error": "Agent failed" + } + ], + "metadata": { + "operation": "returned-error", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + }, + { + "name": "Concurrent waits", + "children": [ + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: left", + "role": "user" + } + ] + }, + "output": { + "content": "left", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + }, + { + "name": "langgraph.runs.wait", + "type": "task", + "children": [], + "input": { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + }, + "output": { + "content": "right", + "role": "assistant" + }, + "metadata": { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + }, + "metrics": { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } + } + ], + "metadata": { + "operation": "concurrent-waits", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + } + ], + "input": { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + }, + "output": { + "expected_error_cases": 4, + "status": "passed" + }, + "metadata": { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + }, + "context": { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + } + ] +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.txt b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.txt new file mode 100644 index 000000000..8af52d87f --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/__snapshots__/langgraph-sdk-v1-latest-esm-wrapped.span-tree.txt @@ -0,0 +1,419 @@ +span_tree: +└── LangGraph SDK 1.10.2 (esm, wrapped) [task] + input: { + "description": "Verify synchronous LangGraph run APIs", + "prompt": { + "messages": [ + { + "content": "Reply with exactly: hello from langgraph", + "role": "user" + } + ] + } + } + output: { + "expected_error_cases": 4, + "status": "passed" + } + metadata: { + "expected_error_cases": 4, + "instrumentation_mode": "wrapped", + "module": "esm", + "scenario": "langgraph-sdk-instrumentation", + "sdk_version": "1.10.2", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runTracedScenario", + "caller_lineno": 0 + } + ├── Uninstrumented background APIs + │ metadata: { + │ "operation": "background-apis", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + ├── Wait for final result + │ metadata: { + │ "operation": "wait", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Interrupt and resume + │ metadata: { + │ "operation": "interrupt-resume", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ ├── langgraph.runs.wait [task] + │ │ input: { + │ │ "messages": [ + │ │ { + │ │ "content": "Reply with exactly: hello from langgraph", + │ │ "role": "user" + │ │ } + │ │ ] + │ │ } + │ │ metadata: { + │ │ "langgraph.assistant_id": "approval", + │ │ "langgraph.interrupts": [ + │ │ { + │ │ "id": "", + │ │ "value": "Approve the model call?" + │ │ } + │ │ ], + │ │ "langgraph.thread_id": "" + │ │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "command": { + │ "resume": "yes" + │ } + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "approval", + │ "langgraph.thread_id": "" + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "tokens": 19 + │ } + ├── Stream values mode + │ metadata: { + │ "operation": "values", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages", + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream messages mode + │ metadata: { + │ "operation": "messages", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream updates mode + │ metadata: { + │ "operation": "updates", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "hello from langgraph", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "updates" + │ ], + │ "streamSubgraphs": true + │ } + │ metrics: { + │ "completion_tokens": 4, + │ "prompt_tokens": 15, + │ "time_to_first_token": 0, + │ "tokens": 19 + │ } + ├── Stream error + │ metadata: { + │ "operation": "stream-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null, + │ "streamMode": [ + │ "values", + │ "messages" + │ ], + │ "streamSubgraphs": true + │ } + │ error: "Agent failed" + ├── Cancel stream + │ metadata: { + │ "operation": "cancel", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.stream [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "interruptBefore": [ + │ "agent" + │ ], + │ "langgraph.assistant_id": "agent", + │ "langgraph.run_id": "", + │ "langgraph.thread_id": null + │ } + ├── Missing assistant error + │ metadata: { + │ "operation": "missing-assistant-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "missing-assistant", + │ "langgraph.thread_id": null + │ } + │ error: "HTTP 404: No assistant found for \"missing-assistant\". Make sure the assistant ID is for a valid assistant or a valid graph ID." + ├── Thrown graph error + │ metadata: { + │ "operation": "thrown-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + ├── Returned graph error + │ metadata: { + │ "operation": "returned-error", + │ "testRunId": "" + │ } + │ context: { + │ "caller_filename": "/e2e/helpers/provider-runtime.mjs", + │ "caller_functionname": "runOperation", + │ "caller_lineno": 0 + │ } + │ └── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: hello from langgraph", + │ "role": "user" + │ } + │ ] + │ } + │ metadata: { + │ "langgraph.assistant_id": "failing", + │ "langgraph.thread_id": null + │ } + │ error: "Agent failed" + └── Concurrent waits + metadata: { + "operation": "concurrent-waits", + "testRunId": "" + } + context: { + "caller_filename": "/e2e/helpers/provider-runtime.mjs", + "caller_functionname": "runOperation", + "caller_lineno": 0 + } + ├── langgraph.runs.wait [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Reply with exactly: left", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "content": "left", + │ "role": "assistant" + │ } + │ metadata: { + │ "langgraph.assistant_id": "agent", + │ "langgraph.thread_id": null + │ } + │ metrics: { + │ "completion_tokens": 1, + │ "prompt_tokens": 12, + │ "tokens": 13 + │ } + └── langgraph.runs.wait [task] + input: { + "messages": [ + { + "content": "Reply with exactly: right", + "role": "user" + } + ] + } + output: { + "content": "right", + "role": "assistant" + } + metadata: { + "langgraph.assistant_id": "agent", + "langgraph.thread_id": null + } + metrics: { + "completion_tokens": 1, + "prompt_tokens": 12, + "tokens": 13 + } diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/graph.mjs b/e2e/scenarios/langgraph-sdk-instrumentation/graph.mjs new file mode 100644 index 000000000..f3482b170 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/graph.mjs @@ -0,0 +1,46 @@ +import { ChatOpenAI } from "@langchain/openai"; +import { + END, + START, + StateGraph, + MessagesAnnotation, + interrupt, +} from "@langchain/langgraph"; + +const model = new ChatOpenAI({ + model: "gpt-4.1-nano", + temperature: 0, + maxTokens: 64, + maxRetries: 0, + configuration: { baseURL: process.env.OPENAI_BASE_URL }, +}); + +async function generate(state) { + return { messages: [await model.invoke(state.messages)] }; +} + +export const agent = new StateGraph(MessagesAnnotation) + .addNode("agent", generate) + .addEdge(START, "agent") + .addEdge("agent", END) + .compile(); + +export const approval = new StateGraph(MessagesAnnotation) + .addNode("approve", () => { + interrupt("Approve the model call?"); + return {}; + }) + .addNode("agent", generate) + .addEdge(START, "approve") + .addEdge("approve", "agent") + .addEdge("agent", END) + .compile(); + +// Exercise the real server's error serialization without a flaky provider error. +export const failing = new StateGraph(MessagesAnnotation) + .addNode("fail", () => { + throw new Error("Agent failed"); + }) + .addEdge(START, "fail") + .addEdge("fail", END) + .compile(); diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/package.json b/e2e/scenarios/langgraph-sdk-instrumentation/package.json new file mode 100644 index 000000000..650044de9 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/package.json @@ -0,0 +1,25 @@ +{ + "name": "langgraph-sdk-instrumentation-scenario", + "private": true, + "type": "module", + "braintrustScenario": { + "bump": { + "dependencies": { + "langgraph-sdk-v1-latest": { + "package": "@langchain/langgraph-sdk", + "range": "1" + } + } + } + }, + "dependencies": { + "langgraph-sdk-v1": "npm:@langchain/langgraph-sdk@1.9.25", + "langgraph-sdk-v1-latest": "npm:@langchain/langgraph-sdk@1.10.2", + "@langchain/core": "1.2.5", + "@langchain/langgraph": "1.4.12", + "@langchain/langgraph-api": "1.4.5", + "@langchain/langgraph-checkpoint": "1.1.5", + "@langchain/openai": "1.5.6", + "typescript": "5.9.3" + } +} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/pnpm-lock.yaml b/e2e/scenarios/langgraph-sdk-instrumentation/pnpm-lock.yaml new file mode 100644 index 000000000..fcedce5c5 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/pnpm-lock.yaml @@ -0,0 +1,1773 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@langchain/core': + specifier: 1.2.5 + version: 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/langgraph': + specifier: 1.4.12 + version: 1.4.12(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(zod@4.5.4) + '@langchain/langgraph-api': + specifier: 1.4.5 + version: 1.4.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(@langchain/langgraph-checkpoint@1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)))(@langchain/langgraph-sdk@1.10.2(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)))(@langchain/langgraph@1.4.12(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(zod@4.5.4))(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(typescript@5.9.3)(ws@8.21.3) + '@langchain/langgraph-checkpoint': + specifier: 1.1.5 + version: 1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)) + '@langchain/openai': + specifier: 1.5.6 + version: 1.5.6(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(ws@8.21.3) + langgraph-sdk-v1: + specifier: npm:@langchain/langgraph-sdk@1.9.25 + version: '@langchain/langgraph-sdk@1.9.25(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))' + langgraph-sdk-v1-latest: + specifier: npm:@langchain/langgraph-sdk@1.10.2 + version: '@langchain/langgraph-sdk@1.10.2(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))' + typescript: + specifier: 5.9.3 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.3.0': + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@cfworker/json-schema@4.1.1': + resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} + + '@colors/colors@1.6.0': + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + + '@colors/colors@1.6.1': + resolution: {integrity: sha512-dTmUJzXSuayBK+hZydEaXd2mhx61qWQwkwaBBY6LyEOVx/L9aQU5ac8eFNEsd9nrD1+zb9zvDCphLSe8g1F4Qw==} + engines: {node: '>=0.1.90'} + + '@commander-js/extra-typings@13.1.0': + resolution: {integrity: sha512-q5P52BYb1hwVWE6dtID7VvuJWrlfbCv4klj7BjUUOqMz4jbSZD4C9fJ9lRjL2jnBGTg+gDDlaXN51rkWcLk4fg==} + peerDependencies: + commander: ~13.1.0 + + '@dabh/diagnostics@2.0.9': + resolution: {integrity: sha512-R6siwR65Hm+3yfgP7o8DKhNvputQAwfoz9zTc3kyDudnomj2/BcLmD+uGQQPICjuFUp8ounPBU+jmKsocwVVAg==} + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@hono/node-server@2.1.1': + resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + + '@hono/node-ws@1.3.1': + resolution: {integrity: sha512-vo/MwCnpJAVHBkGzWjCJ28wF45fYHAfbPZcH2rodZODHtch2GHA94KtMfusmVycTUtsLAsaNsHhtY6P8X3RQsA==} + engines: {node: '>=18.14.1'} + peerDependencies: + '@hono/node-server': ^1.19.11 + hono: ^4.6.0 + + '@hono/zod-validator@0.7.6': + resolution: {integrity: sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw==} + peerDependencies: + hono: '>=3.9.0' + zod: ^3.25.0 || ^4.0.0 + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@langchain/core@1.2.5': + resolution: {integrity: sha512-4lXj3fTPQYGdEtOG9gWDnvmp6wpXNMo9MmWzfZxxPUxMcjulZJa93pYAZ90luFLg2YVdVuUl2tuwdD7tY5K9MA==} + engines: {node: '>=20'} + + '@langchain/langgraph-api@1.4.5': + resolution: {integrity: sha512-OEM4JMTEUl44ObxTIlyy7PRFuh5pA+8m45YJamDsmVLYqP3RMoQ7fGsKMVmc11Dyd/BW2afEOnrgQ6gdYwEBbg==} + engines: {node: ^18.19.0 || >=20.16.0} + peerDependencies: + '@langchain/core': ^1.1.48 + '@langchain/langgraph': ^1.3.6 + '@langchain/langgraph-checkpoint': ^1.1.4 + '@langchain/langgraph-sdk': ^1.9.3-rc.0 + ts-node: ^10.9.2 + typescript: ^5.5.4 + peerDependenciesMeta: + '@langchain/langgraph-sdk': + optional: true + ts-node: + optional: true + + '@langchain/langgraph-checkpoint@1.1.5': + resolution: {integrity: sha512-BwDwl5VeTOh6CVuiIPgsUgfK51vTJDMSbFcSCUfjJWsl8/DPdK/mbv+ejxJstkSk/BlSPMP4JfXWcN6jD2ea2Q==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': ^1.1.48 + + '@langchain/langgraph-sdk@1.10.2': + resolution: {integrity: sha512-86qsfdBZWu1ZgywLN8AThU/jXi9rjPDZPWcTJp4SA1A/L62ypTNoSXbvtiwZt1odokXccYTxK1XWS8tmVdvEmw==} + peerDependencies: + '@langchain/core': ^1.1.48 + react: ^18 || ^19 + react-dom: ^18 || ^19 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@langchain/langgraph-sdk@1.9.25': + resolution: {integrity: sha512-mRKW8zyQUaHox+HirRFMRrPqOvNbQI3xeXDt6kkk4PbBg77V92bsO1WzUVNrmJ81zCkvxyOrWSK8D6ioCj0a8A==} + peerDependencies: + '@langchain/core': ^1.1.48 + react: ^18 || ^19 + react-dom: ^18 || ^19 + svelte: ^4.0.0 || ^5.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + svelte: + optional: true + vue: + optional: true + + '@langchain/langgraph-sdk@1.9.31': + resolution: {integrity: sha512-y1sSdq39IPb6mOX43+JiSezVbUdA8EBEJ1gvn91GP0jrLG0EcSApeRDCjRouyDpPXZ51bQXEQhA8CiHM0mzcAw==} + peerDependencies: + '@langchain/core': ^1.1.48 + react: ^18 || ^19 + react-dom: ^18 || ^19 + svelte: ^4.0.0 || ^5.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + svelte: + optional: true + vue: + optional: true + + '@langchain/langgraph-ui@1.4.5': + resolution: {integrity: sha512-Jy2muKnulO5A2KZJIwr4aji5t23xcmaUYa0xjBgQpLsL4VUTovSy5jfEwtaHZw+V4lxN7mI9MYXd4sHuEZrR9Q==} + engines: {node: ^18.19.0 || >=20.16.0} + hasBin: true + + '@langchain/langgraph@1.4.12': + resolution: {integrity: sha512-63iH/igH5Fh5fHqmWp09YYWaDKKB9v4RCmYNJBrnQ224rFRbjebgyYW6o5RCczN5FZxIhQj+xT51rrNmG0zi5A==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': ^1.1.48 + zod: ^3.25.32 || ^4.2.0 + + '@langchain/openai@1.5.6': + resolution: {integrity: sha512-1cesvhCXw30tMYWXXQaK2gN4aDIKq266LcMSjZn7O/kue/vPnCOAxiwy54HcGQQf7m/sVKfhOn4QwVRObSeAsg==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.2.5 + + '@langchain/protocol@0.0.18': + resolution: {integrity: sha512-XW1egQtPfsGI41w2AMZNFZrUIwFSQHTjVMZs0OaTpCAvht/QLoaPN8FQcsysMVypOhupG28J29yOorrc70otBQ==} + + '@langchain/protocol@0.0.19': + resolution: {integrity: sha512-9hKcRrH7cBX6gfutdfXPoft1OCchHe4FEpALoDJMl5Qu+n/YG5ynZmyu8+8cxORlPwHBoKTxggvXz+76M1yX1Q==} + + '@so-ric/colorspace@1.1.6': + resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.3': + resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/triple-beam@1.3.5': + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} + peerDependencies: + typescript: '*' + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + autoprefixer@10.5.5: + resolution: {integrity: sha512-uiRYvQYe/nNSzBJ7OUnd2/TZVsAdob3blml44teEpee9Cc1f4rGZFewO+JT3Wo8mgFOSzNqes4FHZn/Qz8WOuw==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.11.21: + resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + browserslist@4.28.9: + resolution: {integrity: sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + + color-convert@3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} + engines: {node: '>=14.6'} + + color-name@2.1.1: + resolution: {integrity: sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==} + engines: {node: '>=12.20'} + + color-string@2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} + engines: {node: '>=18'} + + color@5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} + engines: {node: '>=18'} + + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + copy-anything@4.1.0: + resolution: {integrity: sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==} + engines: {node: '>=18'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.1: + resolution: {integrity: sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==} + engines: {node: '>=18'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + electron-to-chromium@1.5.423: + resolution: {integrity: sha512-rRZfTSY8ptHYMQxa+uIycJMFKmY1T0GIApNMXJYGehguTZa56TEEl19pKPCoBqk5Gpf7QizZn/jt7xur+DYxag==} + + enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + + enhanced-resolve@5.24.5: + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} + engines: {node: '>=10.13.0'} + + esbuild-plugin-tailwindcss@2.2.0: + resolution: {integrity: sha512-xzLRHuDZfbDAld+PlQkY028juyfMrYaMRsB4yLfvF3hKBna/cq3bWAHNKz2WQ2YbwbYwYh3B33N1oqBUoX7aww==} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + exit-hook@4.0.0: + resolution: {integrity: sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==} + engines: {node: '>=18'} + + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + + fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hono@4.13.7: + resolution: {integrity: sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==} + engines: {node: '>=16.9.0'} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-network-error@1.3.2: + resolution: {integrity: sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==} + engines: {node: '>=16'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tiktoken@1.0.21: + resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + + langsmith@0.10.2: + resolution: {integrity: sha512-9iqIcEPBMlRT+vvijcjCo4AeHlJHUZjxwbPtDdvQPpGgvo7nYxhsQ7jVd53zXkPstiPfjRhexfnIe0vLltVFmg==} + peerDependencies: + '@opentelemetry/api': '*' + '@opentelemetry/exporter-trace-otlp-proto': '*' + '@opentelemetry/sdk-trace-base': '*' + openai: '*' + ws: '>=7' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/exporter-trace-otlp-proto': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + openai: + optional: true + ws: + optional: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + logform@2.7.0: + resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.54: + resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} + engines: {node: '>=18'} + + one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + openai@6.49.0: + resolution: {integrity: sha512-aYCc0C6L864eR6WSYIwQGyXriw/nIyZx0ObvhzOEVuk0zoBDpynjSbrionWI7q65B5H8jJX0DXR9snEzM6bfPg==} + peerDependencies: + '@aws-sdk/credential-provider-node': '>=3.972.0 <4' + '@smithy/hash-node': '>=4.3.0 <5' + '@smithy/signature-v4': '>=5.4.0 <6' + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@aws-sdk/credential-provider-node': + optional: true + '@smithy/hash-node': + optional: true + '@smithy/signature-v4': + optional: true + ws: + optional: true + zod: + optional: true + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-queue@6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + + p-queue@9.3.3: + resolution: {integrity: sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==} + engines: {node: '>=20'} + + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + + p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@4.2.0: + resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules@6.0.1: + resolution: {integrity: sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==} + peerDependencies: + postcss: ^8.0.0 + + postcss-selector-parser@7.1.6: + resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + + string-hash@1.1.3: + resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + + triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + + tsx@4.23.13: + resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + update-browserslist-db@1.3.2: + resolution: {integrity: sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + winston-console-format@1.0.8: + resolution: {integrity: sha512-dq7t/E0D0QRi4XIOwu6HM1+5e//WPqylH88GVjKEhQVrzGFg34MCz+G7pMJcXFBen9C0kBsu5GYgbYsE2LDwKw==} + + winston-transport@4.9.0: + resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} + engines: {node: '>= 12.0.0'} + + winston@3.19.0: + resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} + engines: {node: '>= 12.0.0'} + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + zod@4.5.4: + resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==} + +snapshots: + + '@alloc/quick-lru@5.3.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.29.7': {} + + '@cfworker/json-schema@4.1.1': {} + + '@colors/colors@1.6.0': {} + + '@colors/colors@1.6.1': {} + + '@commander-js/extra-typings@13.1.0(commander@13.1.0)': + dependencies: + commander: 13.1.0 + + '@dabh/diagnostics@2.0.9': + dependencies: + '@so-ric/colorspace': 1.1.6 + enabled: 2.0.0 + kuler: 2.0.0 + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@hono/node-server@2.1.1(hono@4.13.7)': + dependencies: + hono: 4.13.7 + + '@hono/node-ws@1.3.1(@hono/node-server@2.1.1(hono@4.13.7))(hono@4.13.7)': + dependencies: + '@hono/node-server': 2.1.1(hono@4.13.7) + hono: 4.13.7 + ws: 8.21.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@hono/zod-validator@0.7.6(hono@4.13.7)(zod@4.5.4)': + dependencies: + hono: 4.13.7 + zod: 4.5.4 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)': + dependencies: + '@cfworker/json-schema': 4.1.1 + '@standard-schema/spec': 1.1.0 + js-tiktoken: 1.0.21 + langsmith: 0.10.2(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + mustache: 4.2.0 + p-queue: 6.6.2 + zod: 4.5.4 + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - ws + + '@langchain/langgraph-api@1.4.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(@langchain/langgraph-checkpoint@1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)))(@langchain/langgraph-sdk@1.10.2(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)))(@langchain/langgraph@1.4.12(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(zod@4.5.4))(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(typescript@5.9.3)(ws@8.21.3)': + dependencies: + '@babel/code-frame': 7.29.7 + '@hono/node-server': 2.1.1(hono@4.13.7) + '@hono/node-ws': 1.3.1(@hono/node-server@2.1.1(hono@4.13.7))(hono@4.13.7) + '@hono/zod-validator': 0.7.6(hono@4.13.7)(zod@4.5.4) + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/langgraph': 1.4.12(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(zod@4.5.4) + '@langchain/langgraph-checkpoint': 1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)) + '@langchain/langgraph-ui': 1.4.5 + '@langchain/protocol': 0.0.18 + '@types/json-schema': 7.0.15 + '@typescript/vfs': 1.6.4(typescript@5.9.3) + dedent: 1.7.2 + dotenv: 16.6.1 + exit-hook: 4.0.0 + hono: 4.13.7 + langsmith: 0.10.2(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + open: 10.2.0 + semver: 7.8.5 + stacktrace-parser: 0.1.11 + superjson: 2.2.6 + tsx: 4.23.13 + typescript: 5.9.3 + winston: 3.19.0 + winston-console-format: 1.0.8 + zod: 4.5.4 + optionalDependencies: + '@langchain/langgraph-sdk': 1.10.2(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)) + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - babel-plugin-macros + - bufferutil + - openai + - supports-color + - utf-8-validate + - ws + + '@langchain/langgraph-checkpoint@1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + + '@langchain/langgraph-sdk@1.10.2(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/protocol': 0.0.19 + '@types/json-schema': 7.0.15 + p-queue: 9.3.3 + p-retry: 7.1.1 + + '@langchain/langgraph-sdk@1.9.25(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/protocol': 0.0.18 + '@types/json-schema': 7.0.15 + p-queue: 9.3.3 + p-retry: 7.1.1 + + '@langchain/langgraph-sdk@1.9.31(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/protocol': 0.0.18 + '@types/json-schema': 7.0.15 + p-queue: 9.3.3 + p-retry: 7.1.1 + + '@langchain/langgraph-ui@1.4.5': + dependencies: + '@commander-js/extra-typings': 13.1.0(commander@13.1.0) + commander: 13.1.0 + esbuild: 0.28.2 + esbuild-plugin-tailwindcss: 2.2.0 + zod: 4.5.4 + + '@langchain/langgraph@1.4.12(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(zod@4.5.4)': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + '@langchain/langgraph-checkpoint': 1.1.5(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)) + '@langchain/langgraph-sdk': 1.9.31(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3)) + '@langchain/protocol': 0.0.18 + '@standard-schema/spec': 1.1.0 + zod: 4.5.4 + transitivePeerDependencies: + - react + - react-dom + - svelte + - vue + + '@langchain/openai@1.5.6(@langchain/core@1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3))(ws@8.21.3)': + dependencies: + '@langchain/core': 1.2.5(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3) + js-tiktoken: 1.0.21 + openai: 6.49.0(ws@8.21.3)(zod@4.5.4) + zod: 4.5.4 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - '@smithy/hash-node' + - '@smithy/signature-v4' + - ws + + '@langchain/protocol@0.0.18': {} + + '@langchain/protocol@0.0.19': {} + + '@so-ric/colorspace@1.1.6': + dependencies: + color: 5.0.3 + text-hex: 1.0.0 + + '@standard-schema/spec@1.1.0': {} + + '@tailwindcss/node@4.3.3': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.24.5 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.3 + + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/postcss@4.3.3': + dependencies: + '@alloc/quick-lru': 5.3.0 + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + postcss: 8.5.28 + tailwindcss: 4.3.3 + + '@types/json-schema@7.0.15': {} + + '@types/triple-beam@1.3.5': {} + + '@typescript/vfs@1.6.4(typescript@5.9.3)': + dependencies: + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + async@3.2.6: {} + + autoprefixer@10.5.5(postcss@8.5.28): + dependencies: + browserslist: 4.28.9 + caniuse-lite: 1.0.30001810 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.11.21: {} + + browserslist@4.28.9: + dependencies: + baseline-browser-mapping: 2.11.21 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.423 + node-releases: 2.0.54 + update-browserslist-db: 1.3.2(browserslist@4.28.9) + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + caniuse-lite@1.0.30001810: {} + + color-convert@3.1.3: + dependencies: + color-name: 2.1.1 + + color-name@2.1.1: {} + + color-string@2.1.4: + dependencies: + color-name: 2.1.1 + + color@5.0.3: + dependencies: + color-convert: 3.1.3 + color-string: 2.1.4 + + colors@1.4.0: {} + + commander@13.1.0: {} + + copy-anything@4.1.0: {} + + cssesc@3.0.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + dedent@1.7.2: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-lazy-prop@3.0.0: {} + + detect-libc@2.1.2: {} + + dotenv@16.6.1: {} + + electron-to-chromium@1.5.423: {} + + enabled@2.0.0: {} + + enhanced-resolve@5.24.5: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + esbuild-plugin-tailwindcss@2.2.0: + dependencies: + '@tailwindcss/postcss': 4.3.3 + autoprefixer: 10.5.5(postcss@8.5.28) + postcss: 8.5.28 + postcss-modules: 6.0.1(postcss@8.5.28) + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + escalade@3.2.0: {} + + eventemitter3@4.0.7: {} + + eventemitter3@5.0.4: {} + + exit-hook@4.0.0: {} + + fecha@4.2.3: {} + + fn.name@1.1.0: {} + + fraction.js@5.3.4: {} + + fsevents@2.3.3: + optional: true + + generic-names@4.0.0: + dependencies: + loader-utils: 3.3.1 + + graceful-fs@4.2.11: {} + + hono@4.13.7: {} + + icss-utils@5.1.0(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + inherits@2.0.4: {} + + is-docker@3.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-network-error@1.3.2: {} + + is-stream@2.0.1: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + jiti@2.7.0: {} + + js-tiktoken@1.0.21: + dependencies: + base64-js: 1.5.1 + + js-tokens@4.0.0: {} + + kuler@2.0.0: {} + + langsmith@0.10.2(openai@6.49.0(ws@8.21.3)(zod@4.5.4))(ws@8.21.3): + dependencies: + p-queue: 6.6.2 + optionalDependencies: + openai: 6.49.0(ws@8.21.3)(zod@4.5.4) + ws: 8.21.3 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + loader-utils@3.3.1: {} + + lodash.camelcase@4.3.0: {} + + logform@2.7.0: + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.5.0 + triple-beam: 1.4.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + ms@2.1.3: {} + + mustache@4.2.0: {} + + nanoid@3.3.18: {} + + node-releases@2.0.54: {} + + one-time@1.0.0: + dependencies: + fn.name: 1.1.0 + + open@10.2.0: + dependencies: + default-browser: 5.5.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + openai@6.49.0(ws@8.21.3)(zod@4.5.4): + optionalDependencies: + ws: 8.21.3 + zod: 4.5.4 + + p-finally@1.0.0: {} + + p-queue@6.6.2: + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + + p-queue@9.3.3: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.2 + + p-timeout@3.2.0: + dependencies: + p-finally: 1.0.0 + + p-timeout@7.0.1: {} + + picocolors@1.1.1: {} + + postcss-modules-extract-imports@3.1.0(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-modules-local-by-default@4.2.0(postcss@8.5.28): + dependencies: + icss-utils: 5.1.0(postcss@8.5.28) + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@3.2.1(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-modules-values@4.0.0(postcss@8.5.28): + dependencies: + icss-utils: 5.1.0(postcss@8.5.28) + postcss: 8.5.28 + + postcss-modules@6.0.1(postcss@8.5.28): + dependencies: + generic-names: 4.0.0 + icss-utils: 5.1.0(postcss@8.5.28) + lodash.camelcase: 4.3.0 + postcss: 8.5.28 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.28) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.28) + postcss-modules-scope: 3.2.1(postcss@8.5.28) + postcss-modules-values: 4.0.0(postcss@8.5.28) + string-hash: 1.1.3 + + postcss-selector-parser@7.1.6: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.28: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + run-applescript@7.1.0: {} + + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + semver@7.8.5: {} + + source-map-js@1.2.1: {} + + stack-trace@0.0.10: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + string-hash@1.1.3: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + superjson@2.2.6: + dependencies: + copy-anything: 4.1.0 + + tailwindcss@4.3.3: {} + + tapable@2.3.3: {} + + text-hex@1.0.0: {} + + triple-beam@1.4.1: {} + + tsx@4.23.13: + dependencies: + esbuild: 0.28.2 + optionalDependencies: + fsevents: 2.3.3 + + type-fest@0.7.1: {} + + typescript@5.9.3: {} + + update-browserslist-db@1.3.2(browserslist@4.28.9): + dependencies: + browserslist: 4.28.9 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + winston-console-format@1.0.8: + dependencies: + colors: 1.4.0 + logform: 2.7.0 + triple-beam: 1.4.1 + + winston-transport@4.9.0: + dependencies: + logform: 2.7.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + + winston@3.19.0: + dependencies: + '@colors/colors': 1.6.1 + '@dabh/diagnostics': 2.0.9 + async: 3.2.6 + is-stream: 2.0.1 + logform: 2.7.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.5.0 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.9.0 + + ws@8.21.3: {} + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + + zod@4.5.4: {} diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/scenario.mjs b/e2e/scenarios/langgraph-sdk-instrumentation/scenario.mjs new file mode 100644 index 000000000..016339a6e --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/scenario.mjs @@ -0,0 +1,248 @@ +import assert from "node:assert/strict"; +import { fork } from "node:child_process"; +import { once } from "node:events"; +import { createRequire } from "node:module"; +import * as braintrust from "braintrust"; +import { + runMain, + runOperation, + runTracedScenario, +} from "../../helpers/provider-runtime.mjs"; + +const packageName = process.env.LANGGRAPH_SDK_PACKAGE; +const { Client } = + process.env.LANGGRAPH_SDK_MODULE === "cjs" + ? createRequire(import.meta.url)(packageName) + : await import(packageName); +const input = { + messages: [ + { role: "user", content: "Reply with exactly: hello from langgraph" }, + ], +}; + +runMain(async () => { + const server = fork(new URL("./server.mjs", import.meta.url), [], { + execArgv: [], + env: { + ...process.env, + LANGSMITH_TRACING: "false", + LANGSMITH_TRACING_V2: "false", + LANGCHAIN_TRACING: "false", + LANGCHAIN_TRACING_V2: "false", + LOG_LEVEL: "error", + }, + stdio: ["ignore", "inherit", "inherit", "ipc"], + }); + const exited = once(server, "exit"); + try { + const { apiUrl } = await Promise.race([ + once(server, "message").then(([message]) => message), + exited.then(([code]) => { + throw new Error(`LangGraph server exited before startup: ${code}`); + }), + ]); + const raw = new Client({ + apiUrl, + apiKey: null, + callerOptions: { maxRetries: 0 }, + }); + const wrapped = process.env.LANGGRAPH_SDK_MODE !== "auto"; + const client = wrapped ? braintrust.wrapLangGraphSDK(raw) : raw; + if (wrapped) assert.equal(braintrust.wrapLangGraphSDK(client), client); + assert.equal(client.threads, raw.threads); + const options = { + input, + metadata: { secret: "DO_NOT_CAPTURE" }, + config: { configurable: { secret: "DO_NOT_CAPTURE" } }, + context: { secret: "DO_NOT_CAPTURE" }, + }; + const expectedUsage = {}; + await runTracedScenario({ + projectNameBase: "tmp-luca-langgraph-sdk-e2e", + rootName: `LangGraph SDK ${process.env.LANGGRAPH_SDK_VERSION} (${process.env.LANGGRAPH_SDK_MODULE}, ${process.env.LANGGRAPH_SDK_MODE})`, + metadata: { + scenario: "langgraph-sdk-instrumentation", + sdk_version: process.env.LANGGRAPH_SDK_VERSION, + module: process.env.LANGGRAPH_SDK_MODULE, + instrumentation_mode: process.env.LANGGRAPH_SDK_MODE, + expected_error_cases: 4, + }, + callback: async () => { + const root = braintrust.currentSpan(); + root.log({ + input: { + description: "Verify synchronous LangGraph run APIs", + prompt: input, + }, + }); + await runOperation( + "Uninstrumented background APIs", + "background-apis", + async () => { + const background = await client.threads.create(); + const run = await client.runs.create( + background.thread_id, + "agent", + options, + ); + await client.runs.join(background.thread_id, run.run_id); + assert.equal( + (await client.runs.get(background.thread_id, run.run_id)).status, + "success", + ); + }, + ); + + await runOperation("Wait for final result", "wait", async () => { + const state = await client.runs.wait(null, "agent", options); + assert.ok(state.messages.at(-1).content.length > 0); + expectedUsage.wait = state.messages.at(-1).usage_metadata; + }); + + await runOperation( + "Interrupt and resume", + "interrupt-resume", + async () => { + const thread = await client.threads.create(); + const interrupted = await client.runs.wait( + thread.thread_id, + "approval", + options, + ); + assert.equal( + interrupted.__interrupt__[0].value, + "Approve the model call?", + ); + const resumed = await client.runs.wait( + thread.thread_id, + "approval", + { command: { resume: "yes" } }, + ); + assert.ok(resumed.messages.at(-1).content.length > 0); + expectedUsage.resume = resumed.messages.at(-1).usage_metadata; + }, + ); + + for (const [name, streamMode] of [ + ["values", ["values", "messages", "updates"]], + ["messages", ["messages"]], + ["updates", ["updates"]], + ["stream-error", ["values", "messages"]], + ]) { + const operationName = + name === "stream-error" ? "Stream error" : `Stream ${name} mode`; + await runOperation(operationName, name, async () => { + const operationSpan = braintrust.currentSpan(); + const stream = client.runs.stream( + null, + name === "stream-error" ? "failing" : "agent", + { + ...options, + streamMode, + streamSubgraphs: true, + }, + ); + assert.equal(stream[Symbol.asyncIterator](), stream); + assert.equal(typeof stream.return, "function"); + const events = []; + for await (const event of stream) { + events.push(event); + assert.equal(braintrust.currentSpan().id, operationSpan.id); + } + assert.equal(braintrust.currentSpan().id, operationSpan.id); + if (name === "stream-error") { + assert.equal(events.at(-1).event, "error"); + } else { + const messages = events.flatMap(({ event, data }) => { + if (event === "values") return data.messages ?? []; + if (event === "updates") + return Object.values(data).flatMap( + (update) => update.messages ?? [], + ); + if (event === "messages") return [data[0]]; + if (event.startsWith("messages/")) return data; + return []; + }); + expectedUsage[name] = messages + .filter((message) => message.usage_metadata) + .at(-1).usage_metadata; + assert.ok(expectedUsage[name].total_tokens > 0); + } + }); + } + await runOperation("Cancel stream", "cancel", async () => { + const operationSpan = braintrust.currentSpan(); + // Interrupt before generation so disconnect timing cannot leave an + // in-flight model request in the cassette or affect subsequent runs. + const cancelled = client.runs.stream(null, "agent", { + ...options, + interruptBefore: ["agent"], + onDisconnect: "cancel", + }); + assert.equal((await cancelled.next()).value.event, "metadata"); + await cancelled.return(); + assert.equal(braintrust.currentSpan().id, operationSpan.id); + }); + + await runOperation( + "Missing assistant error", + "missing-assistant-error", + () => + assert.rejects( + client.runs.wait(null, "missing-assistant", options), + /HTTP 404: No assistant found/, + ), + ); + await runOperation("Thrown graph error", "thrown-error", () => + assert.rejects( + client.runs.wait(null, "failing", options), + /Agent failed/, + ), + ); + await runOperation( + "Returned graph error", + "returned-error", + async () => { + assert.ok( + ( + await client.runs.wait(null, "failing", { + ...options, + raiseError: false, + }) + ).__error__, + ); + }, + ); + + await runOperation("Concurrent waits", "concurrent-waits", async () => { + await Promise.all( + ["left", "right"].map(async (name) => { + const state = await client.runs.wait(null, "agent", { + input: { + messages: [ + { role: "user", content: `Reply with exactly: ${name}` }, + ], + }, + }); + const answer = state.messages.at(-1); + assert.ok(answer.content.includes(name)); + expectedUsage[name] = answer.usage_metadata; + }), + ); + }); + root.log({ output: { status: "passed", expected_error_cases: 4 } }); + }, + }); + // Compare logged metrics with the untouched real SDK responses, outside + // the trace payload so usage is not duplicated in the displayed messages. + console.log(`LANGGRAPH_EXPECTED_USAGE ${JSON.stringify(expectedUsage)}`); + } finally { + if (server.connected) server.disconnect(); + const killTimer = setTimeout(() => server.kill("SIGKILL"), 5_000); + try { + await exited; + } finally { + clearTimeout(killTimer); + } + } +}); diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/scenario.test.ts b/e2e/scenarios/langgraph-sdk-instrumentation/scenario.test.ts new file mode 100644 index 000000000..03bb88480 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/scenario.test.ts @@ -0,0 +1,301 @@ +import { + findAllSpans, + findChildSpans, + findLatestSpan, +} from "../../helpers/trace-selectors"; +import { describe, expect, it } from "vitest"; +import { + prepareScenarioDir, + readInstalledPackageVersion, + resolveScenarioDir, + withScenarioHarness, +} from "../../helpers/scenario-harness"; +import { matchSpanTreeSnapshot, spanTreeFields } from "../../helpers/span-tree"; +import { resolveFileSnapshotPath } from "../../helpers/file-snapshot"; + +const originalScenarioDir = resolveScenarioDir(import.meta.url); +const scenarioDir = await prepareScenarioDir({ + scenarioDir: originalScenarioDir, +}); +const variants = await Promise.all( + ["langgraph-sdk-v1", "langgraph-sdk-v1-latest"].map(async (dependency) => ({ + dependency, + version: await readInstalledPackageVersion(scenarioDir, dependency), + })), +); + +describe.concurrent("variants", () => { + for (const { dependency, version } of variants) { + describe.sequential(`LangGraph SDK ${version} (${dependency})`, () => { + for (const module of ["esm", "cjs"]) { + for (const mode of ["wrapped", "auto", "both", "disabled"]) { + it(`${module} ${mode}`, async () => { + await withScenarioHarness( + async (harness) => { + const result = await harness.runNodeScenarioDir({ + scenarioDir, + entry: "scenario.mjs", + timeoutMs: 120_000, + env: { + LANGGRAPH_SDK_PACKAGE: dependency, + LANGGRAPH_SDK_VERSION: version, + LANGGRAPH_SDK_MODULE: module, + LANGGRAPH_SDK_MODE: mode, + ...(mode === "disabled" + ? { BRAINTRUST_DISABLE_INSTRUMENTATION: "langgraph-sdk" } + : {}), + }, + nodeArgs: + mode === "wrapped" + ? [] + : ["--import", "braintrust/hook.mjs"], + // The real server and graph run in every lane. Only model HTTP + // responses are recorded and replayed by the harness. + runContext: { originalScenarioDir, variantKey: dependency }, + }); + const usageLine = result.stdout + .split("\n") + .find((line) => + line.startsWith("LANGGRAPH_EXPECTED_USAGE "), + )!; + const expectedUsage = JSON.parse( + usageLine.slice("LANGGRAPH_EXPECTED_USAGE ".length), + ); + const rawEvents = harness.events(); + const events = [ + ...new Set(rawEvents.map((event) => event.span.name)), + ].flatMap((name) => + name ? findAllSpans(rawEvents, name) : [], + ); + const instrumented = events.filter((event) => + event.span.name?.startsWith("langgraph.runs."), + ); + const root = events.find( + (event) => + event.metadata?.scenario === + "langgraph-sdk-instrumentation", + )!; + expect(root.metadata).toMatchObject({ + sdk_version: version, + module, + instrumentation_mode: mode, + expected_error_cases: 4, + }); + expect(root.output).toEqual({ + status: "passed", + expected_error_cases: 4, + }); + expect(events.every((event) => event.span.ended)).toBe(true); + const operationSpecs = [ + [ + "background", + "Uninstrumented background APIs", + "background-apis", + ], + ["wait", "Wait for final result", "wait"], + [ + "interruptResume", + "Interrupt and resume", + "interrupt-resume", + ], + ["values", "Stream values mode", "values"], + ["messages", "Stream messages mode", "messages"], + ["updates", "Stream updates mode", "updates"], + ["streamError", "Stream error", "stream-error"], + ["cancel", "Cancel stream", "cancel"], + [ + "missingAssistant", + "Missing assistant error", + "missing-assistant-error", + ], + ["thrownError", "Thrown graph error", "thrown-error"], + ["returnedError", "Returned graph error", "returned-error"], + ["concurrent", "Concurrent waits", "concurrent-waits"], + ] as const; + const operations = Object.fromEntries( + operationSpecs.map(([key, spanName, operation]) => { + const event = findLatestSpan(rawEvents, spanName)!; + expect(event.span.parentIds).toEqual([root.span.id]); + expect(event.metadata).toMatchObject({ operation }); + return [key, event]; + }), + ) as Record< + (typeof operationSpecs)[number][0], + (typeof events)[number] + >; + expect( + events.filter((event) => + event.span.parentIds.includes( + operations.background.span.id!, + ), + ), + ).toEqual([]); + if (mode === "disabled") { + expect(instrumented).toHaveLength(0); + expect(events).toHaveLength(13); + return; + } + expect(events).toHaveLength(26); + expect(instrumented).toHaveLength(13); + expect( + instrumented.filter((event) => event.row.error), + ).toHaveLength(4); + for (const event of instrumented) { + expect(event.span.type).toBe("task"); + expect(event.context?.span_origin).toMatchObject({ + instrumentation: { name: "langgraph-sdk" }, + }); + expect(event.span.parentIds).toHaveLength(1); + } + const wait = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.wait.span.id, + ); + const interruptResume = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.interruptResume.span.id, + ); + const values = findChildSpans( + rawEvents, + "langgraph.runs.stream", + operations.values.span.id, + ); + const messages = findChildSpans( + rawEvents, + "langgraph.runs.stream", + operations.messages.span.id, + ); + const updates = findChildSpans( + rawEvents, + "langgraph.runs.stream", + operations.updates.span.id, + ); + const streamError = findChildSpans( + rawEvents, + "langgraph.runs.stream", + operations.streamError.span.id, + ); + const cancel = findChildSpans( + rawEvents, + "langgraph.runs.stream", + operations.cancel.span.id, + ); + const missingAssistant = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.missingAssistant.span.id, + ); + const thrownError = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.thrownError.span.id, + ); + const returnedError = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.returnedError.span.id, + ); + const concurrent = findChildSpans( + rawEvents, + "langgraph.runs.wait", + operations.concurrent.span.id, + ); + for (const group of [ + wait, + values, + messages, + updates, + streamError, + cancel, + missingAssistant, + thrownError, + returnedError, + ]) + expect(group).toHaveLength(1); + expect(interruptResume).toHaveLength(2); + expect(concurrent).toHaveLength(2); + const cases = { + wait: wait[0], + resume: interruptResume[1], + values: values[0], + messages: messages[0], + updates: updates[0], + left: concurrent.find((event) => + JSON.stringify(event.input).includes("exactly: left"), + )!, + right: concurrent.find((event) => + JSON.stringify(event.input).includes("exactly: right"), + )!, + }; + for (const [name, event] of Object.entries(cases)) { + const usage = expectedUsage[name]; + expect(event.metrics).toMatchObject({ + prompt_tokens: usage.input_tokens, + completion_tokens: usage.output_tokens, + tokens: usage.total_tokens, + }); + expect(event.output).toEqual({ + role: "assistant", + content: + name === "left" || name === "right" + ? name + : "hello from langgraph", + }); + } + for (const name of ["values", "messages", "updates"] as const) + expect( + cases[name].metrics?.time_to_first_token, + ).toBeGreaterThanOrEqual(0); + for (const name of ["values", "messages", "updates"] as const) + expect(cases[name].output).toEqual(cases.wait.output); + expect(interruptResume[0].output).toBeUndefined(); + expect(interruptResume[0].metadata).toMatchObject({ + "langgraph.interrupts": [ + { value: "Approve the model call?" }, + ], + }); + expect(interruptResume[1].input).toEqual({ + command: { resume: "yes" }, + }); + expect(missingAssistant[0].row.error).toContain("HTTP 404"); + expect(thrownError[0].row.error).toBe("Agent failed"); + expect(returnedError[0].output).toBeUndefined(); + expect(returnedError[0].row.error).toBe("Agent failed"); + const serialized = JSON.stringify(instrumented); + for (const field of [ + "DO_NOT_CAPTURE", + "additional_kwargs", + "response_metadata", + "usage_metadata", + "invalid_tool_calls", + "tool_call_chunks", + ]) + expect(serialized).not.toContain(field); + await matchSpanTreeSnapshot( + events.map((event) => ({ + event, + fields: { + ...spanTreeFields(event), + context: event.context, + }, + })), + resolveFileSnapshotPath( + import.meta.url, + `${dependency}-${module}-${mode}.span-tree.json`, + ), + ); + }, + { + // Keep every mode's assertions, but publish one representative + // trace per version so CI links do not contain duplicate/empty runs. + forwardToProduction: module === "esm" && mode === "wrapped", + }, + ); + }, 120_000); + } + } + }); + } +}); diff --git a/e2e/scenarios/langgraph-sdk-instrumentation/server.mjs b/e2e/scenarios/langgraph-sdk-instrumentation/server.mjs new file mode 100644 index 000000000..5adf33c06 --- /dev/null +++ b/e2e/scenarios/langgraph-sdk-instrumentation/server.mjs @@ -0,0 +1,38 @@ +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { startServer } from "@langchain/langgraph-api/server"; + +// Run the official server in its own process, as a remote deployment would. +// Only the client is instrumented; model traffic still uses the cassette proxy. +const cwd = await mkdtemp(join(tmpdir(), "braintrust-langgraph-server-")); +let server; +async function shutdown() { + await server?.cleanup(); + await rm(cwd, { recursive: true, force: true }); + // The server's background workers have no shutdown API. + process.exit(0); +} +process.once("disconnect", shutdown); +process.once("SIGTERM", shutdown); + +try { + const graphPath = fileURLToPath(new URL("./graph.mjs", import.meta.url)); + server = await startServer({ + cwd, + host: "127.0.0.1", + port: 0, + nWorkers: 2, + graphs: { + agent: `${graphPath}:agent`, + approval: `${graphPath}:approval`, + failing: `${graphPath}:failing`, + }, + }); + process.send({ apiUrl: `http://${server.host}` }); +} catch (error) { + console.error(error); + await rm(cwd, { recursive: true, force: true }); + process.exit(1); +} diff --git a/e2e/scripts/build-pr-e2e-links-comment.mjs b/e2e/scripts/build-pr-e2e-links-comment.mjs index 88f3086fa..b7144d754 100644 --- a/e2e/scripts/build-pr-e2e-links-comment.mjs +++ b/e2e/scripts/build-pr-e2e-links-comment.mjs @@ -209,6 +209,10 @@ async function readRunContextRecords(runContextDir) { continue; } + // These runs still provide local assertions and cassette coverage. + // Only published runs belong in the production trace links. + if (parsed.forwardToProduction === false) continue; + const scenarioDirName = parsed.scenarioDirName; const variantKey = typeof parsed.variantKey === "string" && parsed.variantKey.trim() diff --git a/js/README.md b/js/README.md index 595ff5b68..9c5e70094 100644 --- a/js/README.md +++ b/js/README.md @@ -104,49 +104,6 @@ If you use TypeScript or other transpilation plugins, place the Braintrust plugi For deeper details, see the [auto-instrumentation architecture docs](src/auto-instrumentations/README.md). -### LangSmith tracing - -Braintrust supports LangSmith `>=0.3.30 <1.0.0`. LangSmith tracing remains authoritative: LangSmith must be enabled, and it continues exporting traces to LangSmith while Braintrust mirrors the same run lifecycle. This integration covers tracing only; LangSmith eval, Jest, and Vitest APIs are not instrumented. - -For automatic Node.js instrumentation, use the standard hook before importing LangSmith: - -```bash -node --import braintrust/hook.mjs app.js -``` - -The Vite, Webpack, esbuild, and Rollup plugins shown above apply the same automatic instrumentation in bundled applications. To instrument explicit namespaces instead, wrap the three LangSmith entrypoints you use: - -```typescript -import { - wrapLangSmithClient, - wrapLangSmithRunTrees, - wrapLangSmithTraceable, -} from "braintrust"; -import * as clientNamespace from "langsmith/client"; -import * as runTreesNamespace from "langsmith/run_trees"; -import * as traceableNamespace from "langsmith/traceable"; - -const { Client } = wrapLangSmithClient(clientNamespace); -const { RunTree } = wrapLangSmithRunTrees(runTreesNamespace); -const { traceable } = wrapLangSmithTraceable(traceableNamespace); -``` - -The wrappers are composable and idempotent. They preserve LangSmith behavior, including its network export and `on_end` callbacks. Automatic and explicit instrumentation can safely be used together. - -Disable LangSmith instrumentation in code or through the environment: - -```typescript -import { configureInstrumentation } from "braintrust"; - -configureInstrumentation({ integrations: { langsmith: false } }); -``` - -```bash -BRAINTRUST_DISABLE_INSTRUMENTATION=langsmith node --import braintrust/hook.mjs app.js -``` - -When Braintrust LangChain/LangGraph instrumentation is enabled, LangSmith runs serialized by LangChain are ignored to avoid duplicate spans. Set `langchain: false` (and use LangSmith instrumentation) when LangSmith should be the source for those runs instead. - ## Migration Guides ### Upgrading from 2.x to 3.x diff --git a/js/src/auto-instrumentations/configs/all.ts b/js/src/auto-instrumentations/configs/all.ts index 9cbcbb449..bd2d45057 100644 --- a/js/src/auto-instrumentations/configs/all.ts +++ b/js/src/auto-instrumentations/configs/all.ts @@ -25,6 +25,7 @@ import { huggingFaceTransformersConfigs } from "./huggingface-transformers"; import { langchainConfigs } from "./langchain"; import { langSmithConfigs } from "./langsmith"; import { mistralConfigs } from "./mistral"; +import { langGraphSDKConfigs } from "./langgraph-sdk"; import { ollamaConfigs } from "./ollama"; import { openAIAgentsCoreConfigs } from "./openai-agents"; import { openaiConfigs } from "./openai"; @@ -101,6 +102,7 @@ const defaultInstrumentationConfigGroups: readonly InstrumentationConfigGroup[] configs: openRouterAgentConfigs, }, { integrations: ["mistral"], configs: mistralConfigs }, + { integrations: ["langgraphSDK"], configs: langGraphSDKConfigs }, { integrations: ["ollama"], configs: ollamaConfigs }, { integrations: ["googleADK"], configs: googleADKConfigs }, { integrations: ["cohere"], configs: cohereConfigs }, diff --git a/js/src/auto-instrumentations/configs/langgraph-sdk.ts b/js/src/auto-instrumentations/configs/langgraph-sdk.ts new file mode 100644 index 000000000..09488a76a --- /dev/null +++ b/js/src/auto-instrumentations/configs/langgraph-sdk.ts @@ -0,0 +1,22 @@ +import type { InstrumentationConfig } from "../orchestrion-js"; +import { langGraphSDKChannels } from "../../instrumentation/plugins/langgraph-sdk-channels"; + +// These public methods live in shared subclients for both package entrypoints. +export const langGraphSDKConfigs: InstrumentationConfig[] = [ + "js", + "cjs", +].flatMap((extension) => + (["wait", "stream"] as const).map((methodName) => ({ + channelName: langGraphSDKChannels[methodName].channelName, + module: { + name: "@langchain/langgraph-sdk", + versionRange: ">=1.9.25 <2.0.0", + filePath: `dist/client/runs/index.${extension}`, + }, + functionQuery: { + className: "RunsClient", + methodName, + kind: methodName === "stream" ? ("Sync" as const) : ("Async" as const), + }, + })), +); diff --git a/js/src/auto-instrumentations/index.ts b/js/src/auto-instrumentations/index.ts index fb3809158..e9737732f 100644 --- a/js/src/auto-instrumentations/index.ts +++ b/js/src/auto-instrumentations/index.ts @@ -44,6 +44,7 @@ export { huggingFaceConfigs } from "./configs/huggingface"; export { openRouterAgentConfigs } from "./configs/openrouter-agent"; export { openRouterConfigs } from "./configs/openrouter"; export { mistralConfigs } from "./configs/mistral"; +export { langGraphSDKConfigs } from "./configs/langgraph-sdk"; export { ollamaConfigs } from "./configs/ollama"; export { googleADKConfigs } from "./configs/google-adk"; export { cloudflareAIChatConfigs } from "./configs/cloudflare-ai-chat"; diff --git a/js/src/exports.ts b/js/src/exports.ts index 83eedccc8..42b124416 100644 --- a/js/src/exports.ts +++ b/js/src/exports.ts @@ -228,6 +228,7 @@ export { wrapHuggingFaceTransformers } from "./wrappers/huggingface-transformers export { wrapOpenRouterAgent } from "./wrappers/openrouter-agent"; export { wrapOpenRouter } from "./wrappers/openrouter"; export { wrapMistral } from "./wrappers/mistral"; +export { wrapLangGraphSDK } from "./wrappers/langgraph-sdk"; export { wrapOllama } from "./wrappers/ollama"; export { wrapCohere } from "./wrappers/cohere"; export { wrapVoyageAI } from "./wrappers/voyageai"; diff --git a/js/src/instrumentation/braintrust-plugin.ts b/js/src/instrumentation/braintrust-plugin.ts index 369bd9df3..942e7fe7c 100644 --- a/js/src/instrumentation/braintrust-plugin.ts +++ b/js/src/instrumentation/braintrust-plugin.ts @@ -14,6 +14,7 @@ import { HuggingFaceTransformersPlugin } from "./plugins/huggingface-transformer import { OpenRouterAgentPlugin } from "./plugins/openrouter-agent-plugin"; import { OpenRouterPlugin } from "./plugins/openrouter-plugin"; import { MistralPlugin } from "./plugins/mistral-plugin"; +import { LangGraphSDKPlugin } from "./plugins/langgraph-sdk-plugin"; import { OllamaPlugin } from "./plugins/ollama-plugin"; import { GoogleADKPlugin } from "./plugins/google-adk-plugin"; import { CoherePlugin } from "./plugins/cohere-plugin"; @@ -73,6 +74,7 @@ export class BraintrustPlugin extends BasePlugin { private openRouterPlugin: OpenRouterPlugin | null = null; private openRouterAgentPlugin: OpenRouterAgentPlugin | null = null; private mistralPlugin: MistralPlugin | null = null; + private langGraphSDKPlugin: LangGraphSDKPlugin | null = null; private ollamaPlugin: OllamaPlugin | null = null; private googleADKPlugin: GoogleADKPlugin | null = null; private coherePlugin: CoherePlugin | null = null; @@ -178,6 +180,11 @@ export class BraintrustPlugin extends BasePlugin { this.mistralPlugin.enable(); } + if (integrations.langgraphSDK !== false) { + this.langGraphSDKPlugin = new LangGraphSDKPlugin(); + this.langGraphSDKPlugin.enable(); + } + if (integrations.ollama !== false) { this.ollamaPlugin = new OllamaPlugin(); this.ollamaPlugin.enable(); @@ -347,6 +354,11 @@ export class BraintrustPlugin extends BasePlugin { this.mistralPlugin = null; } + if (this.langGraphSDKPlugin) { + this.langGraphSDKPlugin.disable(); + this.langGraphSDKPlugin = null; + } + if (this.ollamaPlugin) { this.ollamaPlugin.disable(); this.ollamaPlugin = null; diff --git a/js/src/instrumentation/config.ts b/js/src/instrumentation/config.ts index 43240e6a4..784ca7b2b 100644 --- a/js/src/instrumentation/config.ts +++ b/js/src/instrumentation/config.ts @@ -33,6 +33,7 @@ export interface InstrumentationIntegrationsConfig { cloudflareAgents?: boolean; langchain?: boolean; langgraph?: boolean; + langgraphSDK?: boolean; langsmith?: boolean; voyageai?: boolean; elevenlabs?: boolean; @@ -122,6 +123,9 @@ const envIntegrationAliases: Record< "langchain-js": "langchain", "@langchain": "langchain", langgraph: "langgraph", + langgraphsdk: "langgraphSDK", + "langgraph-sdk": "langgraphSDK", + "@langchain/langgraph-sdk": "langgraphSDK", langsmith: "langsmith", voyage: "voyageai", "voyage-ai": "voyageai", @@ -166,6 +170,7 @@ export function getDefaultInstrumentationIntegrations(): Record< gitHubCopilot: true, langchain: true, langgraph: true, + langgraphSDK: true, langsmith: true, voyageai: true, elevenlabs: true, diff --git a/js/src/instrumentation/plugins/instrumentation-names.test.ts b/js/src/instrumentation/plugins/instrumentation-names.test.ts index 39c95db44..fef4d8bfb 100644 --- a/js/src/instrumentation/plugins/instrumentation-names.test.ts +++ b/js/src/instrumentation/plugins/instrumentation-names.test.ts @@ -22,6 +22,7 @@ import { googleGenerativeAIChannels } from "./google-generative-ai-channels"; import { googleGenAIChannels } from "./google-genai-channels"; import { groqChannels } from "./groq-channels"; import { huggingFaceChannels } from "./huggingface-channels"; +import { langGraphSDKChannels } from "./langgraph-sdk-channels"; import { langChainChannels } from "./langchain-channels"; import { langSmithChannels } from "./langsmith-channels"; import { mistralChannels } from "./mistral-channels"; @@ -69,6 +70,7 @@ describe("built-in instrumentation provenance names", () => { [googleGenAIChannels.generateContent, INSTRUMENTATION_NAMES.GOOGLE_GENAI], [groqChannels.chatCompletionsCreate, INSTRUMENTATION_NAMES.GROQ], [huggingFaceChannels.chatCompletion, INSTRUMENTATION_NAMES.HUGGINGFACE], + [langGraphSDKChannels.wait, INSTRUMENTATION_NAMES.LANGGRAPH_SDK], [langChainChannels.configure, INSTRUMENTATION_NAMES.LANGCHAIN], [langSmithChannels.createRun, INSTRUMENTATION_NAMES.LANGSMITH], [mistralChannels.chatComplete, INSTRUMENTATION_NAMES.MISTRAL], diff --git a/js/src/instrumentation/plugins/langgraph-sdk-channels.ts b/js/src/instrumentation/plugins/langgraph-sdk-channels.ts new file mode 100644 index 000000000..1329982a5 --- /dev/null +++ b/js/src/instrumentation/plugins/langgraph-sdk-channels.ts @@ -0,0 +1,21 @@ +import { INSTRUMENTATION_NAMES } from "../../span-origin"; +import type { + LangGraphRunArgs, + LangGraphStreamEvent, +} from "../../vendor-sdk-types/langgraph-sdk"; +import { channel, defineChannels } from "../core/channel-definitions"; + +export const langGraphSDKChannels = defineChannels( + "@langchain/langgraph-sdk", + { + wait: channel({ + channelName: "runs.wait", + kind: "async", + }), + stream: channel>({ + channelName: "runs.stream", + kind: "sync-stream", + }), + }, + { instrumentationName: INSTRUMENTATION_NAMES.LANGGRAPH_SDK }, +); diff --git a/js/src/instrumentation/plugins/langgraph-sdk-plugin.test.ts b/js/src/instrumentation/plugins/langgraph-sdk-plugin.test.ts new file mode 100644 index 000000000..50dcfc6db --- /dev/null +++ b/js/src/instrumentation/plugins/langgraph-sdk-plugin.test.ts @@ -0,0 +1,565 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { _exportsForTestingOnly, initLogger } from "../../logger"; +import { configureNode } from "../../node/config"; +import { wrapLangGraphSDK } from "../../wrappers/langgraph-sdk"; +import { langGraphSDKChannels } from "./langgraph-sdk-channels"; + +configureNode(); + +describe("LangGraph SDK instrumentation", () => { + let backgroundLogger: ReturnType< + typeof _exportsForTestingOnly.useTestBackgroundLogger + >; + beforeAll(async () => { + await _exportsForTestingOnly.simulateLoginForTests(); + }); + beforeEach(() => { + backgroundLogger = _exportsForTestingOnly.useTestBackgroundLogger(); + initLogger({ + projectName: "tmp-luca-langgraph-sdk-test", + projectId: "test-project-id", + }); + }); + afterEach(() => { + _exportsForTestingOnly.clearTestBackgroundLogger(); + }); + + it("preserves promise identity and helpers", async () => { + const promise = Object.assign(Promise.resolve({ answer: "yes" }), { + helper: () => "helper", + }); + const result = langGraphSDKChannels.wait.invoke( + () => promise, + undefined, + [null, "agent", { input: "question" }], + {}, + ); + expect(result).toBe(promise); + expect(result.helper()).toBe("helper"); + await result; + expect(await backgroundLogger.drain()).toMatchObject([ + { input: "question", output: { answer: "yes" } }, + ]); + }); + + it("preserves synchronous exceptions and rejected error identity", async () => { + const error = new Error("original failure"); + expect(() => + langGraphSDKChannels.wait.invoke( + () => { + throw error; + }, + undefined, + [null, "agent"], + {}, + ), + ).toThrow(error); + await expect( + langGraphSDKChannels.wait.invoke( + () => Promise.reject(error), + undefined, + [null, "agent"], + {}, + ), + ).rejects.toBe(error); + const spans = await backgroundLogger.drain(); + expect(spans).toHaveLength(2); + for (const span of spans) + expect(span).toMatchObject({ + error: expect.stringContaining("original failure"), + metrics: { end: expect.any(Number) }, + }); + }); + + it("contains extraction failures without calling the provider twice", async () => { + let calls = 0; + const options = { + get input(): unknown { + throw new Error("hostile getter"); + }, + }; + const result = langGraphSDKChannels.wait.invoke( + async () => { + calls++; + return "result"; + }, + undefined, + [null, "agent", options], + {}, + ); + await expect(result).resolves.toBe("result"); + expect(calls).toBe(1); + }); + + it("retains partial output and ends a stream when its iterator rejects", async () => { + const error = new Error("connection lost"); + const original = (async function* () { + yield { event: "values", data: { answer: "partial" } }; + throw error; + })(); + const result = langGraphSDKChannels.stream.invoke( + () => original, + undefined, + [null, "agent"], + {}, + ); + expect(result).toBe(original); + await result.next(); + await expect(result.next()).rejects.toBe(error); + expect(await backgroundLogger.drain()).toMatchObject([ + { + output: { answer: "partial" }, + error: expect.stringContaining("connection lost"), + metrics: { end: expect.any(Number) }, + }, + ]); + }); + + it("does not interpret acknowledgements or empty message deltas as tokens", async () => { + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + yield { event: "metadata", data: { run_id: "run" } }; + yield { event: "messages", data: [{ content: "", id: "message" }, {}] }; + }, + undefined, + [null, "agent"], + {}, + ); + for await (const _ of stream) { + /* drain */ + } + const [span] = await backgroundLogger.drain(); + expect(span).not.toHaveProperty("metrics.time_to_first_token"); + }); + + it("captures reported usage without counting messages from previous turns", async () => { + const previous = { + id: "previous", + type: "ai", + content: "earlier", + usage_metadata: { + input_tokens: 100, + output_tokens: 100, + total_tokens: 200, + }, + }; + const answer = { + id: "answer", + type: "ai", + content: "new", + usage_metadata: { input_tokens: 3, output_tokens: 2, total_tokens: 5 }, + }; + await langGraphSDKChannels.wait.invoke( + async () => ({ messages: [previous, answer] }), + undefined, + [null, "agent", { input: { messages: [previous] } }], + {}, + ); + expect(await backgroundLogger.drain()).toMatchObject([ + { metrics: { prompt_tokens: 3, completion_tokens: 2, tokens: 5 } }, + ]); + }); + + it("preserves a null streamed graph value", async () => { + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + yield { event: "values", data: null }; + }, + undefined, + [null, "agent"], + {}, + ); + for await (const _ of stream) { + /* drain */ + } + expect(await backgroundLogger.drain()).toMatchObject([{ output: null }]); + }); + + it("logs generated tool calls without repeating input or unrelated graph state", async () => { + const content = [ + { + type: "image_url", + image_url: { url: "https://example.com/image.png" }, + }, + ]; + const state = Object.freeze({ + messages: [ + { + type: "human", + content, + additional_kwargs: {}, + response_metadata: {}, + }, + { + id: "answer", + type: "ai", + content: "", + additional_kwargs: {}, + response_metadata: { internal: "omit" }, + tool_calls: [ + { id: "call-1", name: "search", args: { query: "hello" } }, + ], + invalid_tool_calls: [], + tool_call_chunks: [], + usage_metadata: { + input_tokens: 3, + output_tokens: 2, + total_tokens: 5, + }, + }, + { + type: "tool", + content: "found", + name: "search", + tool_call_id: "call-1", + }, + ], + application_state: { additional_kwargs: { preserve: true }, score: 0.9 }, + }); + const result = await langGraphSDKChannels.wait.invoke( + async () => state, + undefined, + [null, "agent", { input: { ...state, messages: [state.messages[0]] } }], + {}, + ); + expect(result).toBe(state); + expect(state.messages[1]).toHaveProperty("usage_metadata"); + const [span] = await backgroundLogger.drain(); + const normalized = { + messages: [ + { role: "user", content }, + { + role: "assistant", + content: "", + tool_calls: [ + { + id: "call-1", + type: "function", + function: { name: "search", arguments: '{"query":"hello"}' }, + }, + ], + }, + { + role: "tool", + content: "found", + name: "search", + tool_call_id: "call-1", + }, + ], + application_state: state.application_state, + }; + expect(span).toHaveProperty("input", { + ...normalized, + messages: [normalized.messages[0]], + }); + expect(span).toHaveProperty("output", normalized.messages[1]); + }); + + it("combines message deltas and update snapshots into the generated response", async () => { + const usage = { input_tokens: 3, output_tokens: 2, total_tokens: 5 }; + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + yield { + event: "messages", + data: [ + { id: "answer", type: "AIMessageChunk", content: "hello " }, + {}, + ], + }; + yield { + event: "messages", + data: [ + { + id: "answer", + type: "AIMessageChunk", + content: "world", + usage_metadata: usage, + }, + {}, + ], + }; + yield { + event: "updates", + data: { + agent: { + messages: [ + { + id: "answer", + type: "ai", + content: "hello world", + usage_metadata: usage, + }, + ], + score: 0.9, + }, + }, + }; + }, + undefined, + [null, "agent"], + {}, + ); + for await (const _ of stream) { + /* drain */ + } + const [span] = await backgroundLogger.drain(); + expect(span).toHaveProperty("output", { + role: "assistant", + content: "hello world", + }); + expect(span).toMatchObject({ + metrics: { prompt_tokens: 3, completion_tokens: 2, tokens: 5 }, + }); + }); + + it.each(["", "Error: "])( + "unwraps serialized remote errors with prefix '%s' only in logged data", + async (prefix) => { + const error = new Error( + prefix + + JSON.stringify({ error: "ValueError", message: "Agent failed" }), + ); + const returned = { + __error__: { error: "Error", message: error.message }, + }; + await expect( + langGraphSDKChannels.wait.invoke( + async () => { + throw error; + }, + undefined, + [null, "failing"], + {}, + ), + ).rejects.toBe(error); + expect( + await langGraphSDKChannels.wait.invoke( + async () => returned, + undefined, + [null, "failing"], + {}, + ), + ).toBe(returned); + const spans = await backgroundLogger.drain(); + expect(spans).toHaveLength(2); + for (const span of spans) + expect(span).toHaveProperty("error", "Agent failed"); + expect(spans[1]).not.toHaveProperty("output"); + }, + ); + + it.each(["wait", "values", "updates", "messages"])( + "logs only the final generated response for %s, preserving media and total usage", + async (mode) => { + const input = { + messages: [ + { + id: "old", + type: "ai", + content: "Earlier answer", + usage_metadata: { total_tokens: 100 }, + }, + { id: "prompt", type: "human", content: "New question" }, + ], + }; + const generated = [ + { + id: "plan", + type: "ai", + content: "", + tool_calls: [{ id: "call", name: "search", args: {} }], + usage_metadata: { total_tokens: 4 }, + }, + { + id: "tool", + type: "tool", + content: "Internal tool result", + tool_call_id: "call", + }, + { + id: "answer", + type: "ai", + content: [ + { type: "text", text: "Final answer" }, + { + type: "image_url", + image_url: { url: "https://example.com/generated.png" }, + }, + ], + usage_metadata: { total_tokens: 9 }, + }, + ]; + const state = { + messages: [...input.messages, ...generated], + internal_state: "Do not display", + }; + if (mode === "wait") { + const result = await langGraphSDKChannels.wait.invoke( + async () => state, + undefined, + [null, "agent", { input }], + {}, + ); + expect(result).toBe(state); + } else { + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + if (mode === "values") { + yield { event: "values", data: input }; + yield { event: "values", data: state }; + } else if (mode === "updates") { + yield { + event: "updates", + data: { + agent: { + messages: generated, + internal_state: state.internal_state, + }, + }, + }; + } else { + for (const message of generated.filter( + (message) => message.type === "ai", + )) + yield { event: "messages", data: [message, {}] }; + } + }, + undefined, + [null, "agent", { input }], + {}, + ); + for await (const _ of stream) { + /* drain */ + } + } + const [span] = await backgroundLogger.drain(); + expect(span).toHaveProperty("output", { + role: "assistant", + content: generated[2].content, + }); + expect(span).toMatchObject({ metrics: { tokens: 13 } }); + expect(state.messages).toHaveLength(5); + expect(state.internal_state).toBe("Do not display"); + }, + ); + + it.each([ + { + input: [{ role: "assistant", content: "same" }], + messages: [{ role: "assistant", content: "same" }], + output: undefined, + }, + { + input: [ + { role: "assistant", content: "same" }, + { role: "user", content: "again" }, + ], + messages: [ + { role: "assistant", content: "same" }, + { role: "user", content: "again" }, + { role: "assistant", content: "same" }, + ], + output: { role: "assistant", content: "same" }, + }, + { + input: [{ id: "old", role: "assistant", content: "same" }], + messages: [{ id: "new", role: "assistant", content: "same" }], + output: { role: "assistant", content: "same" }, + }, + { + input: [{ id: "answer", role: "assistant", content: "old" }], + messages: [{ id: "answer", role: "assistant", content: "updated" }], + output: { role: "assistant", content: "updated" }, + }, + ])( + "distinguishes echoed history from generated or edited messages ($output)", + async ({ input, messages, output }) => { + await langGraphSDKChannels.wait.invoke( + async () => ({ messages }), + undefined, + [null, "agent", { input: { messages: input } }], + {}, + ); + const [span] = await backgroundLogger.drain(); + if (output === undefined) expect(span).not.toHaveProperty("output"); + else expect(span).toHaveProperty("output", output); + }, + ); + + it.each(["wait", "values", "updates"])( + "records %s interrupts as metadata without presenting history as output", + async (mode) => { + const input = { + messages: [{ id: "old", role: "assistant", content: "Earlier answer" }], + }; + const interrupts = [{ id: "approval", value: "Approve?" }]; + const state = { ...input, __interrupt__: interrupts }; + if (mode === "wait") { + expect( + await langGraphSDKChannels.wait.invoke( + async () => state, + undefined, + ["existing-thread", "agent", { command: { resume: "yes" } }], + {}, + ), + ).toBe(state); + } else { + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + yield { + event: mode, + data: mode === "values" ? state : { __interrupt__: interrupts }, + }; + }, + undefined, + ["existing-thread", "agent", { command: { resume: "yes" } }], + {}, + ); + for await (const _ of stream) { + /* drain */ + } + } + const [span] = await backgroundLogger.drain(); + expect(span).not.toHaveProperty("output"); + expect(span).not.toHaveProperty("error"); + expect(span).toMatchObject({ + metadata: { "langgraph.interrupts": interrupts }, + metrics: { end: expect.any(Number) }, + }); + }, + ); + + it("keeps generated stream content when the last state snapshot contains only input", async () => { + const input = { messages: [{ role: "user", content: "Question" }] }; + const stream = langGraphSDKChannels.stream.invoke( + async function* () { + yield { event: "values", data: input }; + yield { + event: "messages", + data: [ + { id: "answer", type: "AIMessageChunk", content: "Partial answer" }, + {}, + ], + }; + throw new Error("Connection closed"); + }, + undefined, + [null, "agent", { input }], + {}, + ); + await stream.next(); + await stream.next(); + await expect(stream.next()).rejects.toThrow("Connection closed"); + const [span] = await backgroundLogger.drain(); + expect(span).toHaveProperty("output", { + role: "assistant", + content: "Partial answer", + }); + expect(span).toHaveProperty("error", "Connection closed"); + }); + + it("leaves unsupported wrapper inputs untouched", () => { + for (const value of [null, undefined, {}, { runs: {} }]) + expect(wrapLangGraphSDK(value)).toBe(value); + }); +}); diff --git a/js/src/instrumentation/plugins/langgraph-sdk-plugin.ts b/js/src/instrumentation/plugins/langgraph-sdk-plugin.ts new file mode 100644 index 000000000..b920cd554 --- /dev/null +++ b/js/src/instrumentation/plugins/langgraph-sdk-plugin.ts @@ -0,0 +1,503 @@ +import { isObject, SpanTypeAttribute } from "../../../util"; +import { debugLogger } from "../../debug-logger"; +import { startSpan, withCurrent, type Span } from "../../logger"; +import { + INSTRUMENTATION_NAMES, + withSpanInstrumentationName, +} from "../../span-origin"; +import { getCurrentUnixTimestamp } from "../../util"; +import type { + LangGraphRunArgs, + LangGraphStreamEvent, +} from "../../vendor-sdk-types/langgraph-sdk"; +import { + isAutoInstrumentationSuppressed, + runWithAutoInstrumentationSuppressed, +} from "../auto-instrumentation-suppression"; +import { BasePlugin } from "../core"; +import { unsubscribeAll } from "../core/channel-tracing"; +import { patchStreamIfNeeded } from "../core/stream-patcher"; +import { langGraphSDKChannels } from "./langgraph-sdk-channels"; + +export class LangGraphSDKPlugin extends BasePlugin { + protected onEnable(): void { + this.unsubscribers.push( + langGraphSDKChannels.wait.intercept((target, self, args) => + instrumentRun("wait", args, () => Reflect.apply(target, self, args)), + ), + langGraphSDKChannels.stream.intercept((target, self, args) => + instrumentRun("stream", args, () => Reflect.apply(target, self, args)), + ), + ); + } + + protected onDisable(): void { + this.unsubscribers = unsubscribeAll(this.unsubscribers); + } +} + +// Normalize only message fields; arbitrary graph state is application data. +function normalizeMessage(value: unknown): unknown { + if (!isObject(value)) return value; + const role = + value.role ?? + (value.type === "human" + ? "user" + : value.type === "ai" || value.type === "AIMessageChunk" + ? "assistant" + : value.type === "system" || + value.type === "tool" || + value.type === "function" + ? value.type + : undefined); + if (typeof role !== "string") return value; + const message: Record = { + role, + content: value.content ?? "", + }; + for (const key of ["name", "tool_call_id", "refusal"] as const) { + if (value[key] !== undefined) message[key] = value[key]; + } + const additional = isObject(value.additional_kwargs) + ? value.additional_kwargs + : {}; + const toolCalls = + Array.isArray(value.tool_calls) && value.tool_calls.length + ? value.tool_calls + : additional.tool_calls; + if (Array.isArray(toolCalls) && toolCalls.length > 0) { + message.tool_calls = toolCalls.map((call) => { + if (!isObject(call)) return call; + if (isObject(call.function)) return call; + return { + id: call.id, + type: "function", + function: { + name: call.name, + arguments: + typeof call.args === "string" + ? call.args + : JSON.stringify(call.args ?? {}), + }, + }; + }); + } + // Invalid calls and refusals are meaningful output, unlike empty SDK fields. + if ( + Array.isArray(value.invalid_tool_calls) && + value.invalid_tool_calls.length > 0 + ) + message.invalid_tool_calls = value.invalid_tool_calls; + if (message.refusal === undefined && additional.refusal !== undefined) + message.refusal = additional.refusal; + return message; +} + +function normalizeRunError(value: unknown): unknown { + let name: string; + let message: string; + if (value instanceof Error) { + name = value.name; + message = value.message; + } else if ( + isObject(value) && + typeof value.error === "string" && + typeof value.message === "string" + ) { + name = value.error; + message = value.message; + } else { + return value; + } + // The server may serialize a graph exception into another exception's message. + for (let depth = 0; depth < 3; depth++) { + try { + const nested: unknown = JSON.parse( + message.startsWith(`${name}: `) + ? message.slice(name.length + 2) + : message, + ); + if ( + !isObject(nested) || + typeof nested.error !== "string" || + typeof nested.message !== "string" + ) + break; + name = nested.error; + message = nested.message; + } catch { + break; + } + } + if ( + value instanceof Error && + name === value.name && + message === value.message + ) + return value; + return Object.assign(new Error(message), { name }); +} + +function normalizeState(value: unknown): unknown { + if (!isObject(value)) return value; + return Object.fromEntries( + Object.entries(value).map(([key, field]) => { + if (key === "messages" && Array.isArray(field)) + return [key, field.map(normalizeMessage)]; + if (key === "__error__") { + const error = normalizeRunError(field); + if (error instanceof Error) + return [key, { error: error.name, message: error.message }]; + } + return [key, field]; + }), + ); +} + +function normalizeRunOutput(value: unknown, input: unknown): unknown { + if (!isObject(value)) return value; + if (Array.isArray(value.messages)) { + // A paused/failed state can contain only a previous turn's answer. + // Any generated streaming content is retained separately by the caller. + if (value.__interrupt__ !== undefined || value.__error__ !== undefined) + return undefined; + const inputMessages = + isObject(input) && Array.isArray(input.messages) ? input.messages : []; + let inputPrefixLength = 0; + while (inputPrefixLength < inputMessages.length) { + const previous = inputMessages[inputPrefixLength]; + const message = value.messages[inputPrefixLength]; + if ( + (isObject(previous) && + isObject(message) && + previous.id !== undefined && + message.id !== undefined && + previous.id !== message.id) || + JSON.stringify(normalizeMessage(previous)) !== + JSON.stringify(normalizeMessage(message)) + ) + break; + inputPrefixLength++; + } + // Agent spans show the final generated response, not the conversation or + // intermediate tool results carried in the graph's state. + for ( + let index = value.messages.length - 1; + index >= inputPrefixLength; + index-- + ) { + const message = value.messages[index]; + const normalized = normalizeMessage(message); + if (!isObject(normalized)) continue; + if (normalized.role === "user") return undefined; + if (normalized.role !== "assistant") continue; + if ( + inputMessages.some((previous) => { + if (!isObject(previous) || !isObject(message)) return false; + return ( + previous.id !== undefined && + previous.id === message.id && + JSON.stringify(normalizeMessage(previous)) === + JSON.stringify(normalized) + ); + }) + ) + continue; + return normalized; + } + return undefined; + } + // Graphs with non-message output still have a useful structured result. + // Interrupts and errors are run status, rather than generated content. + const result = Object.fromEntries( + Object.entries(value).filter( + ([key]) => key !== "__interrupt__" && key !== "__error__", + ), + ); + return !Object.keys(result).length && + (value.__interrupt__ !== undefined || value.__error__ !== undefined) + ? undefined + : result; +} + +function instrumentRun( + operation: "wait" | "stream", + [threadId, assistantId, options]: LangGraphRunArgs, + invoke: () => T, +): T { + if (isAutoInstrumentationSuppressed()) return invoke(); + const start = getCurrentUnixTimestamp(); + let span: Span; + try { + // The remote server owns the agent loop. These client task spans do not + // invent LLM/tool children or token counts that the server has not exposed. + const metadata: Record = { + "langgraph.thread_id": threadId, + "langgraph.assistant_id": assistantId, + }; + for (const key of [ + "streamMode", + "streamSubgraphs", + "interruptBefore", + "interruptAfter", + "multitaskStrategy", + "durability", + ] as const) { + if (options?.[key] !== undefined) metadata[key] = options[key]; + } + span = startSpan( + withSpanInstrumentationName( + { + name: `langgraph.runs.${operation}`, + spanAttributes: { type: SpanTypeAttribute.TASK }, + event: { + input: + options?.command === undefined + ? normalizeState(options?.input) + : { + input: normalizeState(options.input), + command: options.command, + }, + metadata, + }, + }, + INSTRUMENTATION_NAMES.LANGGRAPH_SDK, + ), + ); + } catch (error) { + debugLogger.error("Error starting LangGraph SDK span:", error); + return invoke(); + } + + let ended = false; + let output: unknown; + let streamError: unknown; + let firstToken: number | undefined; + const updates: unknown[] = []; + const usageByMessage = new Map>(); + const captureUsage = (id: string, usage: unknown) => { + if (!isObject(usage)) return; + const metrics: Record = {}; + for (const [source, destination] of [ + ["input_tokens", "prompt_tokens"], + ["output_tokens", "completion_tokens"], + ["total_tokens", "tokens"], + ] as const) { + const value = usage[source]; + if (typeof value === "number" && Number.isFinite(value) && value >= 0) + metrics[destination] = value; + } + if ( + metrics.tokens === undefined && + metrics.prompt_tokens !== undefined && + metrics.completion_tokens !== undefined + ) + metrics.tokens = metrics.prompt_tokens + metrics.completion_tokens; + usageByMessage.set(id, { ...usageByMessage.get(id), ...metrics }); + }; + const messages = new Map>(); + const messageSnapshots = new Map>(); + const finish = (error?: unknown) => { + if (ended) return; + ended = true; + try { + const metrics: Record = {}; + for (const usage of usageByMessage.values()) { + for (const [key, value] of Object.entries(usage)) + metrics[key] = (metrics[key] ?? 0) + value; + } + if (firstToken !== undefined) + metrics.time_to_first_token = firstToken - start; + const finalMessages = [ + ...new Map([...messages, ...messageSnapshots]).values(), + ]; + let loggedOutput = normalizeRunOutput(output, options?.input); + if (loggedOutput === undefined && finalMessages.length) + loggedOutput = normalizeRunOutput( + { messages: finalMessages }, + undefined, + ); + if (output === undefined && !finalMessages.length && updates.length) { + const results = updates + .map((update) => normalizeRunOutput(update, options?.input)) + .filter((update) => update !== undefined); + if (results.length) loggedOutput = { updates: results }; + } + const interrupted = [output, ...updates].find( + (state) => isObject(state) && state.__interrupt__ !== undefined, + ); + span.log({ + ...(loggedOutput !== undefined ? { output: loggedOutput } : {}), + ...(isObject(interrupted) + ? { metadata: { "langgraph.interrupts": interrupted.__interrupt__ } } + : {}), + ...(error !== undefined || streamError !== undefined + ? { error: normalizeRunError(error ?? streamError) } + : {}), + metrics, + }); + } catch (error) { + debugLogger.error("Error logging LangGraph SDK span:", error); + } + try { + span.end(); + } catch (error) { + debugLogger.error("Error ending LangGraph SDK span:", error); + } + }; + const observeMessages = (value: unknown, streaming: boolean) => { + if (!isObject(value) || !Array.isArray(value.messages)) return; + const inputMessages = + isObject(options?.input) && Array.isArray(options.input.messages) + ? options.input.messages + : []; + for (const message of value.messages) { + if ( + !isObject(message) || + (message.type !== "ai" && message.role !== "assistant") + ) + continue; + // State snapshots may include messages from earlier turns. + if ( + message.id !== undefined && + inputMessages.some( + (input) => isObject(input) && input.id === message.id, + ) + ) + continue; + captureUsage( + typeof message.id === "string" ? message.id : "message", + message.usage_metadata, + ); + if ( + streaming && + (typeof message.content === "string" + ? message.content.length > 0 + : Array.isArray(message.content) && + message.content.some( + (part) => + isObject(part) && + typeof part.text === "string" && + part.text.length > 0, + )) + ) + firstToken ??= getCurrentUnixTimestamp(); + } + }; + const onChunk = ({ event, data }: LangGraphStreamEvent) => { + if (ended) return; + if (event === "metadata" && isObject(data)) { + if (typeof data.run_id === "string") + span.log({ metadata: { "langgraph.run_id": data.run_id } }); + } else if (event === "error") { + streamError = normalizeRunError(data); + } else if (event === "values") { + output = data; + observeMessages(data, true); + } else if (event === "updates") { + if (isObject(data)) { + const stateUpdates: Array<[string, unknown]> = []; + for (const [node, update] of Object.entries(data)) { + observeMessages(update, true); + if (isObject(update) && Array.isArray(update.messages)) { + for (const message of update.messages) { + if (isObject(message)) + messageSnapshots.set( + typeof message.id === "string" + ? message.id + : `update-${messageSnapshots.size}`, + message, + ); + } + const state = Object.fromEntries( + Object.entries(update).filter(([key]) => key !== "messages"), + ); + if (Object.keys(state).length) stateUpdates.push([node, state]); + } else { + stateUpdates.push([node, update]); + } + } + if (stateUpdates.length) updates.push(Object.fromEntries(stateUpdates)); + } else { + updates.push(data); + } + } else if ( + (event === "messages" || + event === "messages/partial" || + event === "messages/complete") && + Array.isArray(data) + ) { + const parts = event === "messages" ? [data[0]] : data; + for (const part of parts) { + if (!isObject(part)) continue; + const id = typeof part.id === "string" ? part.id : "message"; + captureUsage(id, part.usage_metadata); + const previous = messages.get(id); + // `messages` carries deltas; the other modes carry message snapshots. + messages.set( + id, + event === "messages" && + previous && + typeof part.content === "string" && + typeof previous.content === "string" + ? { ...part, content: previous.content + part.content } + : part, + ); + if (typeof part.content === "string" && part.content.length > 0) + firstToken ??= getCurrentUnixTimestamp(); + } + } + }; + + let result: T; + try { + result = withCurrent(span, () => + runWithAutoInstrumentationSuppressed(invoke), + ); + } catch (error) { + finish(error); + throw error; + } + if (operation === "stream") { + try { + patchStreamIfNeeded(result, { + shouldCollect: (chunk) => { + try { + onChunk(chunk); + } catch (error) { + debugLogger.error( + "Error processing LangGraph stream event:", + error, + ); + } + return false; + }, + aroundNext: (next) => + withCurrent(span, () => runWithAutoInstrumentationSuppressed(next)), + onComplete: () => finish(), + onCancel: () => finish(), + onError: (error) => finish(error), + }); + } catch (error) { + debugLogger.error("Error observing LangGraph stream:", error); + finish(); + } + } else { + // Observe the original promise, retaining its identity and helper methods. + void Promise.resolve(result).then( + (value) => { + try { + output = value; + observeMessages(value, false); + if (isObject(value) && isObject(value.__error__)) + streamError = normalizeRunError(value.__error__); + finish(); + } catch (error) { + finish(error); + } + }, + (error) => finish(error), + ); + } + return result; +} diff --git a/js/src/span-origin.ts b/js/src/span-origin.ts index 2276344f7..ffc9cd037 100644 --- a/js/src/span-origin.ts +++ b/js/src/span-origin.ts @@ -32,6 +32,7 @@ export const INSTRUMENTATION_NAMES = { LANGSMITH: "langsmith", MASTRA: "mastra", MISTRAL: "mistral", + LANGGRAPH_SDK: "langgraph-sdk", OLLAMA: "ollama", OPENAI: "openai", OPENAI_AGENTS: "openai-agents", diff --git a/js/src/vendor-sdk-types/langgraph-sdk.ts b/js/src/vendor-sdk-types/langgraph-sdk.ts new file mode 100644 index 000000000..a9f7ae9dc --- /dev/null +++ b/js/src/vendor-sdk-types/langgraph-sdk.ts @@ -0,0 +1,29 @@ +/** Minimal public surfaces of @langchain/langgraph-sdk >=1.9.25 <2. */ +export interface LangGraphRunOptions { + input?: unknown; + command?: unknown; + streamMode?: string | string[]; + streamSubgraphs?: boolean; + interruptBefore?: string[] | "*"; + interruptAfter?: string[] | "*"; + multitaskStrategy?: string; + durability?: string; +} + +export type LangGraphRunArgs = [ + threadId: string | null, + assistantId: string, + options?: LangGraphRunOptions, +]; + +export interface LangGraphStreamEvent { + event: string; + data: unknown; +} + +export interface LangGraphSDKClient { + runs: { + wait(...args: LangGraphRunArgs): PromiseLike; + stream(...args: LangGraphRunArgs): AsyncGenerator; + }; +} diff --git a/js/src/wrappers/langgraph-sdk.ts b/js/src/wrappers/langgraph-sdk.ts new file mode 100644 index 000000000..c97f5face --- /dev/null +++ b/js/src/wrappers/langgraph-sdk.ts @@ -0,0 +1,47 @@ +import { isObject } from "../../util"; +import { debugLogger } from "../debug-logger"; +import { langGraphSDKChannels } from "../instrumentation/plugins/langgraph-sdk-channels"; +import type { LangGraphSDKClient } from "../vendor-sdk-types/langgraph-sdk"; + +const clients = new WeakMap(); + +/** Trace LangGraph Platform runs that the caller waits for or streams. */ +export function wrapLangGraphSDK(client: T): T { + const runsClient = isObject(client) ? client.runs : undefined; + if ( + !isObject(client) || + !isObject(runsClient) || + !["wait", "stream"].every((key) => typeof runsClient[key] === "function") + ) { + debugLogger.warn("Unsupported LangGraph SDK client. Not wrapping."); + return client; + } + const sdk = client as unknown as LangGraphSDKClient; + const cached = clients.get(sdk); + if (cached) return cached as T; + const runs = new Proxy(sdk.runs, { + get(target, key) { + switch (key) { + case "wait": + return (...args: Parameters) => + langGraphSDKChannels.wait.invoke(target.wait, target, args, {}); + case "stream": + return (...args: Parameters) => + langGraphSDKChannels.stream.invoke(target.stream, target, args, {}); + default: + const value = Reflect.get(target, key, target); + return typeof value === "function" ? value.bind(target) : value; + } + }, + }); + const wrapped = new Proxy(sdk, { + get(target, key) { + if (key === "runs") return runs; + const value = Reflect.get(target, key, target); + return typeof value === "function" ? value.bind(target) : value; + }, + }); + clients.set(sdk, wrapped); + clients.set(wrapped, wrapped); + return wrapped as T; +}