diff --git a/packages/traceloop-sdk/recordings/Test-SDK-Decorators_847855269/should-create-spans-for-workflows-using-decoration-syntax_3330947443/recording.har b/packages/traceloop-sdk/recordings/Test-SDK-Decorators_847855269/should-create-spans-for-workflows-using-decoration-syntax_3330947443/recording.har index 031cbb88..c2fe45ca 100644 --- a/packages/traceloop-sdk/recordings/Test-SDK-Decorators_847855269/should-create-spans-for-workflows-using-decoration-syntax_3330947443/recording.har +++ b/packages/traceloop-sdk/recordings/Test-SDK-Decorators_847855269/should-create-spans-for-workflows-using-decoration-syntax_3330947443/recording.har @@ -236,6 +236,236 @@ "ssl": -1, "wait": 1036 } + }, + { + "_id": "d4be3eb45f9e267d7e2a1694e080fc01", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 136, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "content-length", + "value": "136" + }, + { + "_fromType": "array", + "name": "accept", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "content-type", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "OpenAI/JS 4.26.0" + }, + { + "_fromType": "array", + "name": "x-stainless-lang", + "value": "js" + }, + { + "_fromType": "array", + "name": "x-stainless-package-version", + "value": "4.26.0" + }, + { + "_fromType": "array", + "name": "x-stainless-os", + "value": "MacOS" + }, + { + "_fromType": "array", + "name": "x-stainless-arch", + "value": "arm64" + }, + { + "_fromType": "array", + "name": "x-stainless-runtime", + "value": "node" + }, + { + "_fromType": "array", + "name": "x-stainless-runtime-version", + "value": "v18.17.1" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "name": "host", + "value": "api.openai.com" + } + ], + "headersSize": 470, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Tell me a fact about JavaScript\"\n }\n ],\n \"model\": \"gpt-3.5-turbo\"\n}" + }, + "queryString": [], + "url": "https://api.openai.com/v1/chat/completions" + }, + "response": { + "bodySize": 519, + "content": { + "encoding": "base64", + "mimeType": "application/json", + "size": 519, + "text": "[\"H4sIAAAAAAAAA1SRTWvjMBCG7/4Vg85JsJu4cXJrQwvbw8KyhUKXJUzkia1EX0jjfFDy3xc5bsJedHhfPcOj0VcGIFQtliBkiyyN1+Pq+H54M/y54u384/3X0+nz9fCjOPmPw/S0E6NEuM2OJH9TE+mM18TK2WstAyFTmlrM82oxq+azoi+Mq0knrPE8nk7KMQ==\",\"d2HjxnnxUA5k65SkKJbwJwMA+OrP5GhrOokl5KPvxFCM2JBY3i4BiOB0SgTGqCKjZTG6l9JZJttrv+EBf8ugPMMRIwzCsDnDcyBbo4UXJVtQFnZdZChyqPEc4dgqTdBSDx1d2CvbADL8JI4SPcHKGdNZJTEtIya+WCzKiRgkLjd77Rof3Ca91HZa3/Ktsiq260AYnU2mkZ2/4pcM4G+/pe6/hwsfnPG8ZrcnmwYW0+s4cf+Xe/lQDiU7Rn3Pp1U2+Il4jkxmvVW2oeCDuq5s69fVY1E+4mKGucgu2T8AAAD//wMA0ODQADwCAAA=\"]" + }, + "cookies": [ + { + "domain": ".api.openai.com", + "expires": "2024-02-26T12:29:02.000Z", + "httpOnly": true, + "name": "__cf_bm", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "42zJWnh2q7NVPIuivpqE4VYE3Ilql9KWyOrpxdR3E78-1708948742-1.0-AWCLQ1JQaoC4kOjohFFu6kBPXiT43bZxI74Tr2nznrG4D7VznGD53Kx1poVKtjmcfbhCILqGgunKzbEOwqnp1iE=" + }, + { + "domain": ".api.openai.com", + "httpOnly": true, + "name": "_cfuvid", + "path": "/", + "sameSite": "None", + "secure": true, + "value": "6hh7AnmrNgPbJfbcRF08DGFTwrRglcIZRfYk.Ng0xH8-1708948742319-0.0-604800000" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 26 Feb 2024 11:59:02 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "name": "access-control-allow-origin", + "value": "*" + }, + { + "name": "cache-control", + "value": "no-cache, must-revalidate" + }, + { + "name": "openai-model", + "value": "gpt-3.5-turbo-0125" + }, + { + "name": "openai-organization", + "value": "traceloop" + }, + { + "name": "openai-processing-ms", + "value": "760" + }, + { + "name": "openai-version", + "value": "2020-10-01" + }, + { + "name": "strict-transport-security", + "value": "max-age=15724800; includeSubDomains" + }, + { + "name": "x-ratelimit-limit-requests", + "value": "5000" + }, + { + "name": "x-ratelimit-limit-tokens", + "value": "160000" + }, + { + "name": "x-ratelimit-remaining-requests", + "value": "4999" + }, + { + "name": "x-ratelimit-remaining-tokens", + "value": "159975" + }, + { + "name": "x-ratelimit-reset-requests", + "value": "12ms" + }, + { + "name": "x-ratelimit-reset-tokens", + "value": "9ms" + }, + { + "name": "x-request-id", + "value": "req_39025d75991f71c729b2b391741515a6" + }, + { + "name": "cf-cache-status", + "value": "DYNAMIC" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "__cf_bm=42zJWnh2q7NVPIuivpqE4VYE3Ilql9KWyOrpxdR3E78-1708948742-1.0-AWCLQ1JQaoC4kOjohFFu6kBPXiT43bZxI74Tr2nznrG4D7VznGD53Kx1poVKtjmcfbhCILqGgunKzbEOwqnp1iE=; path=/; expires=Mon, 26-Feb-24 12:29:02 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "_cfuvid=6hh7AnmrNgPbJfbcRF08DGFTwrRglcIZRfYk.Ng0xH8-1708948742319-0.0-604800000; path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "85b804ffdda2babd-MXP" + }, + { + "name": "content-encoding", + "value": "gzip" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=86400" + } + ], + "headersSize": 1202, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-02-26T11:59:00.988Z", + "time": 1312, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 1312 + } } ], "pages": [], diff --git a/packages/traceloop-sdk/src/lib/tracing/decorators.ts b/packages/traceloop-sdk/src/lib/tracing/decorators.ts index d6790e16..4ed19cb0 100644 --- a/packages/traceloop-sdk/src/lib/tracing/decorators.ts +++ b/packages/traceloop-sdk/src/lib/tracing/decorators.ts @@ -62,7 +62,11 @@ function withEntity< if (shouldSendTraces()) { try { const input = inputParameters ?? args; - if (input.length === 1 && typeof input[0] === "object") { + if ( + input.length === 1 && + typeof input[0] === "object" && + !(input[0] instanceof Map) + ) { span.setAttribute( SpanAttributes.TRACELOOP_ENTITY_INPUT, JSON.stringify({ args: [], kwargs: input[0] }), @@ -70,7 +74,12 @@ function withEntity< } else { span.setAttribute( SpanAttributes.TRACELOOP_ENTITY_INPUT, - JSON.stringify({ args: input, kwargs: {} }), + JSON.stringify({ + args: input.map((arg) => + arg instanceof Map ? Array.from(arg.entries()) : arg, + ), + kwargs: {}, + }), ); } } catch { @@ -83,10 +92,17 @@ function withEntity< return res.then((resolvedRes) => { try { if (shouldSendTraces()) { - span.setAttribute( - SpanAttributes.TRACELOOP_ENTITY_OUTPUT, - JSON.stringify(resolvedRes), - ); + if (resolvedRes instanceof Map) { + span.setAttribute( + SpanAttributes.TRACELOOP_ENTITY_OUTPUT, + JSON.stringify(Array.from(resolvedRes.entries())), + ); + } else { + span.setAttribute( + SpanAttributes.TRACELOOP_ENTITY_OUTPUT, + JSON.stringify(resolvedRes), + ); + } } return resolvedRes; } finally { diff --git a/packages/traceloop-sdk/test/decorators.test.ts b/packages/traceloop-sdk/test/decorators.test.ts index 69db13d4..da5f47f9 100644 --- a/packages/traceloop-sdk/test/decorators.test.ts +++ b/packages/traceloop-sdk/test/decorators.test.ts @@ -135,20 +135,32 @@ describe("Test SDK Decorators", () => { it("should create spans for workflows using decoration syntax", async () => { class TestOpenAI { @traceloop.workflow({ name: "sample_chat" }) - async chat(subject: string) { - const chatCompletion = await openai.chat.completions.create({ - messages: [ - { role: "user", content: `Tell me a joke about ${subject}` }, - ], - model: "gpt-3.5-turbo", - }); + async chat(things: Map) { + const generations: Map = new Map(); + for await (const [key, value] of things) { + const chatCompletion = await openai.chat.completions.create({ + messages: [ + { role: "user", content: `Tell me a ${key} about ${value}` }, + ], + model: "gpt-3.5-turbo", + }); - return chatCompletion.choices[0].message.content; + if (chatCompletion.choices[0].message.content) { + generations.set(key, chatCompletion.choices[0].message.content); + } + } + + return generations; } } const testOpenAI = new TestOpenAI(); - const result = await testOpenAI.chat("OpenTelemetry"); + const result = await testOpenAI.chat( + new Map([ + ["joke", "OpenTelemetry"], + ["fact", "JavaScript"], + ]), + ); const spans = memoryExporter.getFinishedSpans(); const workflowSpan = spans.find( @@ -172,11 +184,22 @@ describe("Test SDK Decorators", () => { ); assert.strictEqual( workflowSpan.attributes[`${SpanAttributes.TRACELOOP_ENTITY_INPUT}`], - JSON.stringify({ args: ["OpenTelemetry"], kwargs: {} }), + JSON.stringify({ + args: [ + [ + ["joke", "OpenTelemetry"], + ["fact", "JavaScript"], + ], + ], + kwargs: {}, + }), ); assert.strictEqual( workflowSpan.attributes[`${SpanAttributes.TRACELOOP_ENTITY_OUTPUT}`], - JSON.stringify(result), + JSON.stringify([ + ["joke", result.get("joke")], + ["fact", result.get("fact")], + ]), ); assert.ok(chatSpan); assert.strictEqual(