From 6bda4b0d5afb6e46cb2818ea7aad1b9869c1719a Mon Sep 17 00:00:00 2001 From: Nir Gazit Date: Fri, 5 Apr 2024 13:38:48 +0200 Subject: [PATCH] fix(anthropic): support streaming for completion API --- .../recording.har | 166 +++++++++++++++++ .../recording.har | 20 +- .../recording.har | 171 ++++++++++++++++++ .../recording.har | 22 +-- .../src/instrumentation.ts | 102 ++++++++++- .../test/instrumentation.test.ts | 111 +++++++++++- 6 files changed, 568 insertions(+), 24 deletions(-) create mode 100644 packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har create mode 100644 packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har rename packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/{should-set-attributes-in-span-for-messages-chat_1442873136 => should-set-attributes-in-span-for-messages_831758903}/recording.har (77%) diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har new file mode 100644 index 00000000..bf3d5d6c --- /dev/null +++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions-streaming_2198009633/recording.har @@ -0,0 +1,166 @@ +{ + "log": { + "_recordingName": "Test Anthropic instrumentation/should set attributes in span for completions (streaming)", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "411df901c53641005b599f973e8b2068", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 149, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "content-length", + "value": "149" + }, + { + "_fromType": "array", + "name": "accept", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "content-type", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "Anthropic/JS 0.20.1" + }, + { + "_fromType": "array", + "name": "x-stainless-lang", + "value": "js" + }, + { + "_fromType": "array", + "name": "x-stainless-package-version", + "value": "0.20.1" + }, + { + "_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": "anthropic-version", + "value": "2023-06-01" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "name": "host", + "value": "api.anthropic.com" + } + ], + "headersSize": 548, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\n \"model\": \"claude-2\",\n \"max_tokens_to_sample\": 300,\n \"prompt\": \"\\n\\nHuman: Tell me a joke about OpenTelemetry\\n\\nAssistant:\",\n \"stream\": true\n}" + }, + "queryString": [], + "url": "https://api.anthropic.com/v1/complete" + }, + "response": { + "bodySize": 6983, + "content": { + "mimeType": "text/event-stream; charset=utf-8", + "size": 6983, + "text": "event: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Here\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"'s\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: ping\r\ndata: {\"type\": \"ping\"}\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" a\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" silly\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" joke\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" about\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Open\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"Tele\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"metry\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\":\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"\\n\\nWhat\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" do\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" you\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" call\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" an\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" Open\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"Tele\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"metry\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" collector\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" that\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" keeps\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" getting\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" distracted\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"?\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" A\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" span\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"-\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"t\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"ention\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" deficit\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\" tracer\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"!\",\"stop_reason\":null,\"model\":\"claude-2.1\",\"stop\":null,\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\nevent: completion\r\ndata: {\"type\":\"completion\",\"id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\",\"completion\":\"\",\"stop_reason\":\"stop_sequence\",\"model\":\"claude-2.1\",\"stop\":\"\\n\\nHuman:\",\"log_id\":\"compl_01NxHrRrvyAuE77TjBS7tyTt\" }\r\n\r\n" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Fri, 05 Apr 2024 11:20:12 GMT" + }, + { + "name": "content-type", + "value": "text/event-stream; charset=utf-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "name": "cache-control", + "value": "no-cache" + }, + { + "name": "request-id", + "value": "req_01QgLb4tbuUR3myMtpiyaSZX" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "cf-cache-status", + "value": "DYNAMIC" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "86f925c39fd7a268-FCO" + } + ], + "headersSize": 299, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-04-05T11:20:12.047Z", + "time": 2070, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 2070 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har index 7ac23682..9a9ef085 100644 --- a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har +++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-completions_1224394582/recording.har @@ -92,18 +92,18 @@ "url": "https://api.anthropic.com/v1/complete" }, "response": { - "bodySize": 320, + "bodySize": 600, "content": { "encoding": "base64", "mimeType": "application/json", - "size": 320, - "text": "[\"H4sIAAAAAAAAA4yQwUrEQBBEf6Xti5coRhTWXDwJgRW87KKHhdDONDGbzvRkpoMM4r9LFgW9eayiHlTVB1qJjA06naKwDRqwwsH/ON1V/Xjn5vfb2bf1zWb/st+UUR+mLVa/kQah5cTnGQjyIFLgqCMDvepi8BQ57Fh4YkulOYRDeH4jA69QdAFHIkDhbwqcirAzTWBrdmSOGXo2G0IPfsiWyBn7e9glcgw5kuNyhhVm09glpnxqdVKZ54WDY6xwUs+ybhNaPF9cX9bfCDa4FmuXiUKDFYr23X9e+PwCAAD//wMAKmQrP0EBAAA=\"]" + "size": 600, + "text": "[\"H4sIAAAAAAAAA4xSwWobMRD9lWddfNmY2s0h+BLS9hBDIJdAWjCYyWpqqdZqttIoW7X034s2DSQlh14EmuG9efPm/TJaRzZb08swBlYv0XTG2+fK4d366qOupw2fX1R7MX7m8/c3m3u2pnsJ2Rpcc+JlBiF41cBo3aKc4MogCfQgRXE7crzjwANrqtt93Md7VzFRhjp+3YUm6hklOhrHeokP3FPJDK9wZBEFeaSYF43kNXDiqFCZKa302qZHi0zedtibT3Opww7qfDxhB0ePDBXBQLGil6j8Q/Nib9DI7yb5R1l7fZ8xUTjBRxUQHiitcBsZmWp+ni7qOLWZX6TgFGXqMDESUwgVPmZNZWhi+ZFTbWqOoCQlWjhOvNibJ4dIYQVVCnoKARTfdEod6TLjKJHRJ/pZL3GFWFTr7NRs1A5ORp6pgj+xxVCRfVNDqjyMmkGKb3Li/NbFVrhhxcDzLvBfG9HSzlRtZcfUrK4YJDGUexclyLGeqeOB7VMSFqYzWWU8JKY8R2f+Zf5eOPZsOjOI5dACGKhYPtus1n8hZjsbcl0GilvTmSDHw/9E9fcfAAAA//8DAOxCDkfmAgAA\"]" }, "cookies": [], "headers": [ { "name": "date", - "value": "Fri, 05 Apr 2024 10:38:14 GMT" + "value": "Fri, 05 Apr 2024 11:20:12 GMT" }, { "name": "content-type", @@ -119,11 +119,11 @@ }, { "name": "request-id", - "value": "req_014CcafYLaePcG11ZYue24Jd" + "value": "req_01MF9Mk2Pm5K7idAdKGVuKtn" }, { "name": "x-cloud-trace-context", - "value": "aae2aed4e069035246097cae098de4fb" + "value": "bfd63b2c08c48c70d3ba04406af4864c" }, { "name": "via", @@ -139,7 +139,7 @@ }, { "name": "cf-ray", - "value": "86f8e842edf274e2-FCO" + "value": "86f925a33e42a268-FCO" }, { "name": "content-encoding", @@ -152,8 +152,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2024-04-05T10:38:12.599Z", - "time": 1869, + "startedDateTime": "2024-04-05T11:20:06.759Z", + "time": 5267, "timings": { "blocked": -1, "connect": -1, @@ -161,7 +161,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 1869 + "wait": 5267 } } ], diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har new file mode 100644 index 00000000..90b95cab --- /dev/null +++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-streaming_44400664/recording.har @@ -0,0 +1,171 @@ +{ + "log": { + "_recordingName": "Test Anthropic instrumentation/should set attributes in span for messages (streaming)", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "169f6f7c83e96867124983806f6d7be4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 188, + "cookies": [], + "headers": [ + { + "_fromType": "array", + "name": "content-length", + "value": "188" + }, + { + "_fromType": "array", + "name": "accept", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "content-type", + "value": "application/json" + }, + { + "_fromType": "array", + "name": "user-agent", + "value": "Anthropic/JS 0.20.1" + }, + { + "_fromType": "array", + "name": "x-stainless-lang", + "value": "js" + }, + { + "_fromType": "array", + "name": "x-stainless-package-version", + "value": "0.20.1" + }, + { + "_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": "anthropic-version", + "value": "2023-06-01" + }, + { + "_fromType": "array", + "name": "x-stainless-helper-method", + "value": "stream" + }, + { + "_fromType": "array", + "name": "accept-encoding", + "value": "gzip,deflate" + }, + { + "name": "host", + "value": "api.anthropic.com" + } + ], + "headersSize": 583, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Tell me a joke about OpenTelemetry\"\n }\n ],\n \"model\": \"claude-3-opus-20240229\",\n \"stream\": true\n}" + }, + "queryString": [], + "url": "https://api.anthropic.com/v1/messages" + }, + "response": { + "bodySize": 19048, + "content": { + "mimeType": "text/event-stream; charset=utf-8", + "size": 19048, + "text": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_01B1V5rsrrCx1gdMW82NDgHk\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"claude-3-opus-20240229\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":17,\"output_tokens\":1}} }\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"} }\n\nevent: ping\ndata: {\"type\": \"ping\"}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Sure\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"!\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Here\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"'s\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" joke\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" about\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\":\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\n\\nWhy\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" did\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" developer\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" love\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" using\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"?\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\nBecause\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" it\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" made\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tr\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"acing\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" their\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" code\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"-\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"t\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"astic\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" experience\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"!\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\n\\nExplanation\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\":\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" is\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" set\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" of\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" APIs\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" SD\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"K\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"s\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tools\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" used\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" for\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" collecting\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" ex\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"porting\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tel\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" data\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" (\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"like\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" traces\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" metrics\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" logs\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\")\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" to\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" help\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" observe\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" monitor\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" distributed\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" systems\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" In\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" represents\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" single\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" operation\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" or\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" unit\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" of\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" work\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" within\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" trace\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" The\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" joke\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" plays\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" on\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" similarity\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" between\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" the\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" word\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"span\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" and\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"fantastic\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\",\\\"\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" impl\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ying\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" that\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" using\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" Open\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"T\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"el\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"emet\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"ry\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" makes\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" tr\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"acing\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" code\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" great\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" experience\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" for\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" developers\"} }\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"} }\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0 }\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"usage\":{\"output_tokens\":151}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\" }\n\n" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Fri, 05 Apr 2024 11:20:24 GMT" + }, + { + "name": "content-type", + "value": "text/event-stream; charset=utf-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "name": "cache-control", + "value": "no-cache" + }, + { + "name": "request-id", + "value": "req_01MSkAn89zj7EbecovHP9E65" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "cf-cache-status", + "value": "DYNAMIC" + }, + { + "name": "server", + "value": "cloudflare" + }, + { + "name": "cf-ray", + "value": "86f926063927a268-FCO" + } + ], + "headersSize": 299, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-04-05T11:20:22.711Z", + "time": 9590, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 9590 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-chat_1442873136/recording.har b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har similarity index 77% rename from packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-chat_1442873136/recording.har rename to packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har index 4562c9ab..a86aea9c 100644 --- a/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages-chat_1442873136/recording.har +++ b/packages/instrumentation-anthropic/recordings/Test-Anthropic-instrumentation_3769946143/should-set-attributes-in-span-for-messages_831758903/recording.har @@ -1,6 +1,6 @@ { "log": { - "_recordingName": "Test Anthropic instrumentation/should set attributes in span for messages (chat)", + "_recordingName": "Test Anthropic instrumentation/should set attributes in span for messages", "creator": { "comment": "persister:fs", "name": "Polly.JS", @@ -92,18 +92,18 @@ "url": "https://api.anthropic.com/v1/messages" }, "response": { - "bodySize": 832, + "bodySize": 736, "content": { "encoding": "base64", "mimeType": "application/json", - "size": 832, - "text": "[\"H4sIAAAAAAAAA4STX2sdOQzFv4rWL9nC3JCkLZvOS2FhX3cfEmhLpwTF1p1x45EcS77/Qr578dy9oYFCnwakI/v4pzNPLgbXu1nHu4vLt353uH7kz//6m++Xt9eHL7a5Pbx3nbN9pqYiVRzJda5IagVUjWrI5jrnhY3YXP/16aQ32rXO8undTS3UwUSFzhQQvssDAd5LNfgvE99Sopms7PuBB/407SHEADYRBNpQkkwF1LAYVI08vp75OPDf5LEqtYk9bJGNApiAFfRLMbZxygrIAUYy0Iy8MlSLHiJrHCdTiNxmFjXmnKJHi8JnCpnKWsqM7OmPZvCfXU7IS7cf+JUZiO0SkEy8UqnFE6wLzrSV8gA2oUEusomBGoVGL2AJ8UABtrhvnkdiKmjUgZeUyFu3mKZdlmJgL/cENIQ/lxdqB60WvR61SUZ9A2spEKJaife18dC9Gs16DrcTHfnnhHsF4QW0F/aUDWS9YIs8drCdop8g8kbShnSpPzT8Tb9Osm3iQo+V1BRsKlLHqb3+J3pHRw23ns4rlAspsUHkEDcxVExQOZq28xZQ22hTZMDjBs8b8+baqMwwuJ+WN7gFOOTK4GW+j3zyt5US9H/x4BYXg1sjH+e6wQHNeUKNh9PES9TOFGjno9HcTB5T2gQvQVli5pFhxMiwLjL/Kpdtm7NwNCnL9ciY9gf6XcLO3fO3zs0SKLne+YQ10OrtSnLV1dXF1buLq6sPrnNqku8KoQq73hGHO6uFTw1tW2FPrueaUufq8uv2Ty5yrnZn8kCsrr/8q3NS7VXp+uL5+QcAAAD//wMACpefuBkEAAA=\"]" + "size": 736, + "text": "[\"H4sIAAAAAAAAA1RSX2vbMBD/Kle95MUpbdZR5pexQseS0Q220nUsI8jWJdYs37m6U10T+t2HnJWsT4a7+/2V98Y7U5pOdpuz8+un1erx56dvl6vP9/cPVzd0dacfr01hdOwxX6GI3aEpTOSQB1bEi1pSU5iaSZHUlL/2L/eKT3kzfUrzPUUsoMGIMwELf7hFsBUnha890i0G7FDjWK5pTR/A4SMG7jHCYEMr4EkZLFQ2giUHHB3GTOOip/YUbhvMO0VyGMFKKwWszQ9OwcHICYJvEZRB4wicIhAOr2XnlRV0IKModu9hqVBbAo22xkwQD4qwjdyBNggdd0g6cfchH3md+I8rrzMBwfiI7mRtcqps8pgrYh88Tj6/ZKClbHoJfcQtRujGQzbJtBVCosmMm+InclynLIPuFJbgmGYKgyXNuIplQrXEAzQ8QJfqBpazDqRHcp52wAQ21NxwAJdingwcW2g4RfnP7bHSYNOukUlc7Di5XsIuoUjuYBYRiBUiWjfCliNwlaPbygevI3g6lDglymqNrbwKjKincGPHCkHU1+1LhRzcfGul8UzoYLAj8PbwAhn8r5fspeE+T7JixlUoerI25vl3YTp2GExp6mCTw/mbOfdJ5ouzxcXZYvHOFEaU+01EK0ymNEhuoynSy0LwISHVaEpKIRQmTb9+uTee+qQb5RZJTHl+WRhO+mr09uL5+S8AAAD//wMACb+NKFkDAAA=\"]" }, "cookies": [], "headers": [ { "name": "date", - "value": "Fri, 05 Apr 2024 10:38:23 GMT" + "value": "Fri, 05 Apr 2024 11:20:22 GMT" }, { "name": "content-type", @@ -119,11 +119,11 @@ }, { "name": "request-id", - "value": "req_01KVi9KJu77aGUxCqVF99yqS" + "value": "req_0182vaPgMhnXsMnBS73p6Yqd" }, { "name": "x-cloud-trace-context", - "value": "a8cb6fe2ea3a28abf9468000f8ed7073" + "value": "42ba21496f6152a6803a8a29a8855cd7" }, { "name": "via", @@ -139,7 +139,7 @@ }, { "name": "cf-ray", - "value": "86f8e84d1f3b74e2-FCO" + "value": "86f925d0bb53a268-FCO" }, { "name": "content-encoding", @@ -152,8 +152,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2024-04-05T10:38:14.480Z", - "time": 9138, + "startedDateTime": "2024-04-05T11:20:14.137Z", + "time": 8561, "timings": { "blocked": -1, "connect": -1, @@ -161,7 +161,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 9138 + "wait": 8561 } } ], diff --git a/packages/instrumentation-anthropic/src/instrumentation.ts b/packages/instrumentation-anthropic/src/instrumentation.ts index 1c9f57ed..00880d2d 100644 --- a/packages/instrumentation-anthropic/src/instrumentation.ts +++ b/packages/instrumentation-anthropic/src/instrumentation.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as anthropic from "@anthropic-ai/sdk"; import { context, trace, @@ -33,15 +32,20 @@ import { SpanAttributes, } from "@traceloop/ai-semantic-conventions"; import { AnthropicInstrumentationConfig } from "./types"; +import { version } from "../package.json"; +import type * as anthropic from "@anthropic-ai/sdk"; import type { CompletionCreateParamsNonStreaming, + CompletionCreateParamsStreaming, Completion, } from "@anthropic-ai/sdk/resources/completions"; import type { MessageCreateParamsNonStreaming, + MessageCreateParamsStreaming, Message, + MessageStreamEvent, } from "@anthropic-ai/sdk/resources/messages"; -import { version } from "../package.json"; +import type { Stream } from "@anthropic-ai/sdk/streaming"; export class AnthropicInstrumentation extends InstrumentationBase { protected declare _config: AnthropicInstrumentationConfig; @@ -143,6 +147,24 @@ export class AnthropicInstrumentation extends InstrumentationBase { }, ); + if ( + ( + args[0] as + | MessageCreateParamsStreaming + | CompletionCreateParamsStreaming + ).stream && + type === "completion" // For some reason, this causes an exception with chat, so disabled for now + ) { + return context.bind( + execContext, + plugin._streamingWrapPromise({ + span, + type, + promise: execPromise, + }), + ); + } + const wrappedPromise = plugin._wrapPromise(type, span, execPromise); return context.bind(execContext, wrappedPromise as any); @@ -217,6 +239,82 @@ export class AnthropicInstrumentation extends InstrumentationBase { }); } + private async *_streamingWrapPromise({ + span, + type, + promise, + }: + | { + span: Span; + type: "chat"; + promise: Promise>; + } + | { + span: Span; + type: "completion"; + promise: Promise>; + }) { + if (type === "chat") { + const result: Message = { + id: "0", + type: "message", + model: "", + role: "assistant", + stop_reason: null, + stop_sequence: null, + usage: { input_tokens: 0, output_tokens: 0 }, + content: [], + }; + for await (const chunk of await promise) { + yield chunk; + + switch (chunk.type) { + case "content_block_start": + if (result.content.length <= chunk.index) { + result.content.push(chunk.content_block); + } + break; + + case "content_block_delta": + if (chunk.index < result.content.length) { + result.content[chunk.index] = { + type: "text", + text: result.content[chunk.index].text + chunk.delta.text, + }; + } + } + } + + this._endSpan({ span, type, result }); + } else { + const result: Completion = { + id: "0", + type: "completion", + model: "", + completion: "", + stop_reason: null, + }; + for await (const chunk of await promise) { + yield chunk; + + result.id = chunk.id; + result.model = chunk.model; + + if (chunk.stop_reason) { + result.stop_reason = chunk.stop_reason; + } + if (chunk.model) { + result.model = chunk.model; + } + if (chunk.completion) { + result.completion += chunk.completion; + } + } + + this._endSpan({ span, type, result }); + } + } + private _wrapPromise( type: "chat" | "completion", span: Span, diff --git a/packages/instrumentation-anthropic/test/instrumentation.test.ts b/packages/instrumentation-anthropic/test/instrumentation.test.ts index 6de45ac4..04caec91 100644 --- a/packages/instrumentation-anthropic/test/instrumentation.test.ts +++ b/packages/instrumentation-anthropic/test/instrumentation.test.ts @@ -128,7 +128,57 @@ describe("Test Anthropic instrumentation", async function () { ); }).timeout(30000); - it("should set attributes in span for messages (chat)", async () => { + it("should set attributes in span for completions (streaming)", async () => { + const result = await anthropic.completions.create({ + model: "claude-2", + max_tokens_to_sample: 300, + prompt: `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`, + stream: true, + }); + + let completion = ""; + for await (const chunk of result) { + assert.ok(chunk); + completion += chunk.completion; + } + + const spans = memoryExporter.getFinishedSpans(); + const completionSpan = spans.find( + (span) => span.name === "anthropic.completion", + ); + + assert.ok(completionSpan); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`], + "claude-2", + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`], + 300, + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`], + "claude-2.1", + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`], + "user", + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`], + `${AnthropicModule.HUMAN_PROMPT} Tell me a joke about OpenTelemetry${AnthropicModule.AI_PROMPT}`, + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`], + "assistant", + ); + assert.strictEqual( + completionSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`], + completion, + ); + }).timeout(30000); + + it("should set attributes in span for messages", async () => { const message = await anthropic.messages.create({ max_tokens: 1024, messages: [ @@ -180,4 +230,63 @@ describe("Test Anthropic instrumentation", async function () { chatSpan.attributes[`${SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`], ); }).timeout(30000); + + it.skip( + "should set attributes in span for messages (streaming)", + async () => { + const stream = anthropic.messages.stream({ + max_tokens: 1024, + messages: [ + { role: "user", content: "Tell me a joke about OpenTelemetry" }, + ], + model: "claude-3-opus-20240229", + }); + const message = await stream.finalMessage(); + + const spans = memoryExporter.getFinishedSpans(); + const chatSpan = spans.find((span) => span.name === "anthropic.chat"); + + assert.ok(message); + assert.ok(chatSpan); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MODEL}`], + "claude-3-opus-20240229", + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_RESPONSE_MODEL}`], + "claude-3-opus-20240229", + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_REQUEST_MAX_TOKENS}`], + 1024, + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`], + "user", + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`], + `Tell me a joke about OpenTelemetry`, + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`], + "assistant", + ); + assert.strictEqual( + chatSpan.attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`], + JSON.stringify(message.content), + ); + assert.equal( + chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`], + 17, + ); + assert.equal( + +chatSpan.attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`]! + + +chatSpan.attributes[ + `${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}` + ]!, + chatSpan.attributes[`${SpanAttributes.LLM_USAGE_TOTAL_TOKENS}`], + ); + }, + ).timeout(30000); });