Skip to content

Commit

Permalink
fix(openai): content and tool calls in streamed responses do not error (
Browse files Browse the repository at this point in the history
#4651)

* fix

* test

* remove .only
  • Loading branch information
sabrenner authored and juan-fernandez committed Sep 30, 2024
1 parent 3606b91 commit 85b8f3a
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 2 deletions.
6 changes: 4 additions & 2 deletions packages/datadog-instrumentations/src/openai.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,12 @@ function addStreamedChunk (content, chunk) {

if (tools) {
oldChoice.delta.tool_calls = tools.map((newTool, toolIdx) => {
const oldTool = oldChoice.delta.tool_calls[toolIdx]
const oldTool = oldChoice.delta.tool_calls?.[toolIdx]

if (oldTool) {
oldTool.function.arguments += newTool.function.arguments
} else {
return newTool
}

return oldTool
Expand Down Expand Up @@ -247,7 +249,7 @@ function wrapStreamIterator (response, options, n, ctx) {
return res
})
.catch(err => {
finish(undefined, err)
finish(ctx, undefined, err)

throw err
})
Expand Down
55 changes: 55 additions & 0 deletions packages/datadog-plugin-openai/test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3615,6 +3615,61 @@ describe('Plugin', () => {

await checkTraces
})

it('makes a successful chat completion call with tools and content', async () => {
nock('https://api.openai.com:443')
.post('/v1/chat/completions')
.reply(200, function () {
return fs.createReadStream(
Path.join(__dirname, 'streamed-responses/chat.completions.tool.and.content.txt')
)
}, {
'Content-Type': 'text/plain',
'openai-organization': 'kill-9'
})

const checkTraces = agent
.use(traces => {
const span = traces[0][0]

expect(span).to.have.property('name', 'openai.request')
expect(span).to.have.property('type', 'openai')
expect(span).to.have.property('error', 0)
expect(span.meta).to.have.property('openai.organization.name', 'kill-9')
expect(span.meta).to.have.property('openai.request.method', 'POST')
expect(span.meta).to.have.property('openai.request.endpoint', '/v1/chat/completions')
expect(span.meta).to.have.property('openai.request.model', 'gpt-4')
expect(span.meta).to.have.property('openai.request.messages.0.content', 'Hello, OpenAI!')
expect(span.meta).to.have.property('openai.request.messages.0.role', 'user')
expect(span.meta).to.have.property('openai.request.messages.0.name', 'hunter2')
expect(span.meta).to.have.property('openai.response.choices.0.message.role', 'assistant')
expect(span.meta).to.have.property('openai.response.choices.0.message.content',
'THOUGHT: Hi')
expect(span.meta).to.have.property('openai.response.choices.0.finish_reason', 'tool_calls')
expect(span.meta).to.have.property('openai.response.choices.0.logprobs', 'returned')
expect(span.meta).to.have.property('openai.response.choices.0.message.tool_calls.0.function.name',
'finish')
expect(span.meta).to.have.property(
'openai.response.choices.0.message.tool_calls.0.function.arguments',
'{\n"answer": "5"\n}'
)
})

const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello, OpenAI!', name: 'hunter2' }],
temperature: 0.5,
tools: [], // dummy tools, the response is hardcoded
stream: true
})

for await (const part of stream) {
expect(part).to.have.property('choices')
expect(part.choices[0]).to.have.property('delta')
}

await checkTraces
})
}
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"TH"},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"O"},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"UGHT"},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" Hi"},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_Tg0o5wgoNSKF2iggAPmfWwem","type":"function","function":{"name":"finish","arguments":""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\n"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"answer"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" \""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"5"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"\n"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-A3juVlDlz6tV3bfCY2WZfYxRlKiAH","object":"chat.completion.chunk","created":1725454827,"model":"gpt-4-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}]}

data: [DONE]

0 comments on commit 85b8f3a

Please sign in to comment.