Skip to content

Commit b378b5f

Browse files
committed
AI-310: address streaming sample review comments
Move streaming config onto the client plugin, where its modelParams propagate into the Workflow via the config header; drop the inert worker-plugin modelParams. Remove the client's OPENAI_API_KEY requirement since the client never calls the model, and correct the README accordingly. Make the fake model emit incremental per-word deltas so the sample and test genuinely demonstrate streaming.
1 parent eabcb52 commit b378b5f

5 files changed

Lines changed: 18 additions & 16 deletions

File tree

openai-agents/src/streaming/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ topic, and an external client subscribes to that topic to print the deltas live.
88

99
The Workflow (`src/streaming/workflows.ts`) constructs `new WorkflowStream()` at the top, then
1010
iterates the `StreamedRunResult` to drive the run to completion and returns the final text. The
11-
Worker configures `modelParams.streamingTopic` (and a `streamingBatchInterval`) on the
12-
`OpenAIAgentsPlugin` so the streaming Activity knows which topic to publish to. The client
13-
(`src/streaming/client.ts`) subscribes from outside the Workflow with
11+
client (`src/streaming/client.ts`) configures `modelParams.streamingTopic` and `streamingBatchInterval`
12+
on its `OpenAIAgentsPlugin`, and the client interceptor injects them into the Workflow via the config
13+
header so the streaming Activity knows which topic to publish to. The client also subscribes from
14+
outside the Workflow with
1415
`WorkflowStreamClient.create(client, workflowId).topic(streamingTopic).subscribe()`.
1516

1617
## Run
1718

1819
Run these from the `openai-agents/` root (run `npm install` there once first).
1920

21+
Only the Worker needs `OPENAI_API_KEY`, because the model runs in the Worker's Activity. The client
22+
never calls the model, so it starts without a key.
23+
2024
```bash
2125
# In one terminal, start the Worker (requires a local Temporal server and OPENAI_API_KEY):
2226
OPENAI_API_KEY=sk-... npx ts-node src/streaming/worker.ts

openai-agents/src/streaming/client.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,14 @@ interface ModelStreamEvent {
1111
}
1212

1313
async function run() {
14-
const apiKey = process.env.OPENAI_API_KEY;
15-
if (!apiKey) {
16-
throw new Error('OPENAI_API_KEY environment variable is required');
17-
}
18-
1914
const connection = await Connection.connect();
2015
const client = new Client({
2116
connection,
2217
plugins: [
2318
new OpenAIAgentsPlugin({
24-
modelProvider: new OpenAIProvider({ apiKey }),
25-
modelParams: { streamingTopic },
19+
// The client never calls the model (it runs in the Worker's Activity); this only satisfies the plugin's required modelProvider field.
20+
modelProvider: new OpenAIProvider({}),
21+
modelParams: { streamingTopic, streamingBatchInterval: '200 milliseconds' },
2622
}),
2723
],
2824
});

openai-agents/src/streaming/mocha/fake-model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ export function streamingTextEvents(text: string): StreamEvent[] {
1717
status: 'completed',
1818
},
1919
];
20+
const chunks = text.match(/\s*\S+\s*/g) ?? [text];
2021
return [
21-
{ type: 'output_text_delta', delta: text },
22+
...chunks.map((delta) => ({ type: 'output_text_delta', delta })),
2223
{
2324
type: 'response_done',
2425
response: {

openai-agents/src/streaming/mocha/workflows.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ describe('openai-agents/streaming workflow scenarios', function () {
3737
plugins: [
3838
new OpenAIAgentsPlugin({
3939
modelProvider: new StreamingFakeModelProvider(events),
40-
modelParams: { streamingTopic, streamingBatchInterval: '50 milliseconds' },
4140
}),
4241
],
4342
bundlerOptions: {
@@ -57,7 +56,7 @@ describe('openai-agents/streaming workflow scenarios', function () {
5756
plugins: [
5857
new OpenAIAgentsPlugin({
5958
modelProvider: new StreamingFakeModelProvider(events),
60-
modelParams: { streamingTopic },
59+
modelParams: { streamingTopic, streamingBatchInterval: '50 milliseconds' },
6160
}),
6261
],
6362
});
@@ -91,7 +90,11 @@ describe('openai-agents/streaming workflow scenarios', function () {
9190
received.map((e) => e.type),
9291
events.map((e) => e.type),
9392
);
94-
assert.strictEqual(received[0]!.delta, 'Hello streamed world');
93+
const streamedText = received
94+
.filter((e) => e.type === 'output_text_delta')
95+
.map((e) => e.delta)
96+
.join('');
97+
assert.strictEqual(streamedText, 'Hello streamed world');
9598
return finalOutput;
9699
});
97100

openai-agents/src/streaming/worker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { NativeConnection, Worker } from '@temporalio/worker';
22
import { OpenAIAgentsPlugin } from '@temporalio/openai-agents';
33
import { OpenAIProvider } from '@openai/agents-openai';
4-
import { streamingTopic } from './workflows';
54

65
async function run() {
76
const apiKey = process.env.OPENAI_API_KEY;
@@ -18,7 +17,6 @@ async function run() {
1817
plugins: [
1918
new OpenAIAgentsPlugin({
2019
modelProvider: new OpenAIProvider({ apiKey }),
21-
modelParams: { streamingTopic, streamingBatchInterval: '200 milliseconds' },
2220
}),
2321
],
2422
bundlerOptions: {

0 commit comments

Comments
 (0)