Skip to content

Commit

Permalink
fix: Leading whitespace chunks break partial parser
Browse files Browse the repository at this point in the history
  • Loading branch information
tillkolter committed Dec 17, 2024
1 parent f361a0c commit 62254df
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/lib/ChatCompletionStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,9 @@ export class ChatCompletionStream<ParsedT = null>
choice.message.content = (choice.message.content || '') + content;

if (!choice.message.refusal && this.#getAutoParseableResponseFormat()) {
choice.message.parsed = partialParse(choice.message.content);
// Even a partial parser does not accept empty string
const trimmed = choice.message.content.trimStart();
choice.message.parsed = trimmed ? partialParse(trimmed) : null;
}
}

Expand Down
41 changes: 41 additions & 0 deletions tests/lib/ChatCompletionStream.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,47 @@ describe('.stream()', () => {
`);
});

it('is robust against leading newline chunks', async () => {
const stream = await makeStreamSnapshotRequest((openai) =>
openai.beta.chat.completions.stream({
model: 'gpt-4o-2024-08-06',
messages: [
{
role: 'user',
content: "What's the weather like in SF?",
},
],
response_format: zodResponseFormat(
z.object({
city: z.string(),
units: z.enum(['c', 'f']).default('f'),
}),
'location',
),
}),
);

expect((await stream.finalChatCompletion()).choices[0]).toMatchInlineSnapshot(`
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"message": {
"content": "
{"city":"San Francisco","units":"c"}",
"parsed": {
"city": "San Francisco",
"units": "c",
},
"refusal": null,
"role": "assistant",
"tool_calls": [],
},
}
`);
});

it('emits content logprobs events', async () => {
var capturedLogProbs: ChatCompletionTokenLogprob[] | undefined;

Expand Down
34 changes: 34 additions & 0 deletions tests/lib/__snapshots__/ChatCompletionStream.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,37 @@ data: [DONE]
"
`;
exports[`.stream() is robust against leading newline chunks 1`] = `
"data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\\n\\n"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"{\\""},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"city"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\\":\\""},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"San"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":" Francisco"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\\",\\""},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"units"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\\":\\""},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"c"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{"content":"\\"}"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}
data: {"id":"chatcmpl-9tZXEmwtoDf6vqCqEWSvDP8jx9OXe","object":"chat.completion.chunk","created":1723031664,"model":"gpt-4o-2024-08-06","system_fingerprint":"fp_845eaabc1f","choices":[],"usage":{"prompt_tokens":17,"completion_tokens":10,"total_tokens":27}}
data: [DONE]
"
`;

0 comments on commit 62254df

Please sign in to comment.