Skip to content

Commit d836abf

Browse files
authored
feat: Add streaming API to orchestration (#352)
1 parent e35cab5 commit d836abf

File tree

47 files changed

+1891
-243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1891
-243
lines changed

.changeset/hip-melons-destroy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sap-ai-sdk/orchestration': minor
3+
---
4+
5+
[New Functionality] Add support for streaming in the orchestration client.

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export {
99
AwsBedrockChatModel,
1010
AiCoreOpenSourceChatModel
1111
} from './model-types.js';
12+
export { SseStream, LineDecoder, SSEDecoder } from './stream/index.js';

packages/core/src/stream/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './sse-stream.js';
2+
export * from './sse-decoder.js';
3+
export * from './line-decoder.js';

packages/foundation-models/src/azure-openai/stream/line-decoder.ts renamed to packages/core/src/stream/line-decoder.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined;
55
* reading lines from text.
66
*
77
* Https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258.
8-
* @internal
98
*/
109
export class LineDecoder {
1110
// prettier-ignore

packages/foundation-models/src/azure-openai/stream/sse-decoder.ts renamed to packages/core/src/stream/sse-decoder.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export interface ServerSentEvent {
1919

2020
/**
2121
* Server-Sent Event decoder.
22-
* @internal
2322
*/
2423
export class SSEDecoder {
2524
private data: string[];

packages/foundation-models/src/azure-openai/stream/sse-stream.test.ts renamed to packages/core/src/stream/sse-stream.test.ts

File renamed without changes.

packages/foundation-models/src/azure-openai/stream/sse-stream.ts renamed to packages/core/src/stream/sse-stream.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined;
1313

1414
/**
1515
* Stream implemented as an async iterable.
16-
* @internal
1716
*/
1817
export class SseStream<Item> implements AsyncIterable<Item> {
1918
protected static transformToSseStream<Item>(

packages/foundation-models/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Refer to `AzureOpenAiChatCompletionParameters` interface for other parameters th
152152
The `AzureOpenAiChatClient` supports streaming response for chat completion requests based on the [Server-sent events](https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events) standard.
153153

154154
Use the `stream()` method to receive a stream of chunk responses from the model.
155-
After consuming the stream, call the helper methods to get the finish reason and token usage information respectively.
155+
After consuming the stream, call the helper methods to get the finish reason and token usage information.
156156

157157
```ts
158158
const chatClient = new AzureOpenAiChatClient('gpt-4o');
@@ -178,7 +178,7 @@ console.log(`Token usage: ${JSON.stringify(tokenUsage)}\n`);
178178

179179
##### Streaming the Delta Content
180180

181-
The client provides a helper method to extract delta content and stream string directly.
181+
The client provides a helper method to extract the text chunks as strings:
182182

183183
```ts
184184
for await (const chunk of response.stream.toContentStream()) {
@@ -198,7 +198,7 @@ Additionally, it can be aborted manually by calling the `stream()` method with a
198198
```ts
199199
const chatClient = new AzureOpenAiChatClient('gpt-4o');
200200
const controller = new AbortController();
201-
const response = await new AzureOpenAiChatClient('gpt-35-turbo').stream(
201+
const response = await chatClient.stream(
202202
{
203203
messages: [
204204
{

packages/foundation-models/src/azure-openai/azure-openai-chat-client.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ describe('Azure OpenAI chat client', () => {
198198

199199
const response = await client.stream(prompt);
200200
for await (const chunk of response.stream) {
201-
expect(JSON.stringify(chunk.data)).toEqual(initialResponse);
201+
expect(chunk.data).toEqual(JSON.parse(initialResponse));
202202
break;
203203
}
204204
});

packages/foundation-models/src/azure-openai/azure-openai-chat-completion-stream.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { createLogger } from '@sap-cloud-sdk/util';
22
import { jest } from '@jest/globals';
3+
import { LineDecoder, SSEDecoder } from '@sap-ai-sdk/core';
34
import { parseFileToString } from '../../../../test-util/mock-http.js';
45
import { AzureOpenAiChatCompletionStream } from './azure-openai-chat-completion-stream.js';
5-
import { LineDecoder } from './stream/line-decoder.js';
6-
import { SSEDecoder } from './stream/sse-decoder.js';
76

87
describe('OpenAI chat completion stream', () => {
98
let sseChunks: string[];
@@ -39,12 +38,12 @@ describe('OpenAI chat completion stream', () => {
3938

4039
it('should wrap the raw chunk', async () => {
4140
let output = '';
42-
const asnycGenerator = AzureOpenAiChatCompletionStream._processChunk(
41+
const asyncGenerator = AzureOpenAiChatCompletionStream._processChunk(
4342
originalChatCompletionStream
4443
);
45-
for await (const chunk of asnycGenerator) {
44+
for await (const chunk of asyncGenerator) {
4645
expect(chunk).toBeDefined();
47-
chunk.getDeltaContent() ? (output += chunk.getDeltaContent()) : null;
46+
output += chunk.getDeltaContent() ?? '';
4847
}
4948
expect(output).toEqual('The capital of France is Paris.');
5049
});

0 commit comments

Comments
 (0)