@@ -35,7 +35,7 @@ The process parameter is a callback in which you can run the assistant on thread
35
35
36
36
It gets invoked with the following functions that you can use to send messages and data messages to the client:
37
37
38
- - ` sendMessage : (message: AssistantMessage ) => void` : Sends an assistant message to the client.
38
+ - ` forwardStream : (stream: AssistantStream ) => void` : Forwards the assistant response stream to the client.
39
39
- ` sendDataMessage: (message: DataMessage) => void ` : Send a data message to the client. You can use this to provide information for rendering custom UIs while the assistant is processing the thread.
40
40
41
41
## Example
@@ -50,7 +50,6 @@ Server:
50
50
``` tsx filename="app/api/assistant/route.ts"
51
51
import { experimental_AssistantResponse } from ' ai' ;
52
52
import OpenAI from ' openai' ;
53
- import { MessageContentText } from ' openai/resources/beta/threads/messages/messages' ;
54
53
55
54
// Create an OpenAI API client (that's edge friendly!)
56
55
const openai = new OpenAI ({
@@ -86,118 +85,82 @@ export async function POST(req: Request) {
86
85
87
86
return experimental_AssistantResponse (
88
87
{ threadId , messageId: createdMessage .id },
89
- async ({ threadId , sendMessage , sendDataMessage }) => {
88
+ async ({ forwardStream , sendDataMessage }) => {
90
89
// Run the assistant on the thread
91
- const run = await openai .beta .threads .runs .create (threadId , {
90
+ const runStream = openai .beta .threads .runs .createAndStream (threadId , {
92
91
assistant_id:
93
92
process .env .ASSISTANT_ID ??
94
93
(() => {
95
94
throw new Error (' ASSISTANT_ID is not set' );
96
95
})(),
97
96
});
98
97
99
- async function waitForRun(run : OpenAI .Beta .Threads .Runs .Run ) {
100
- // Poll for status change
101
- while (run .status === ' queued' || run .status === ' in_progress' ) {
102
- // delay for 500ms:
103
- await new Promise (resolve => setTimeout (resolve , 500 ));
104
-
105
- run = await openai .beta .threads .runs .retrieve (threadId ! , run .id );
106
- }
107
-
108
- // Check the run status
109
- if (
110
- run .status === ' cancelled' ||
111
- run .status === ' cancelling' ||
112
- run .status === ' failed' ||
113
- run .status === ' expired'
114
- ) {
115
- throw new Error (run .status );
116
- }
117
-
118
- if (run .status === ' requires_action' ) {
119
- if (run .required_action ?.type === ' submit_tool_outputs' ) {
120
- const tool_outputs =
121
- run .required_action .submit_tool_outputs .tool_calls .map (
122
- toolCall => {
123
- const parameters = JSON .parse (toolCall .function .arguments );
124
-
125
- switch (toolCall .function .name ) {
126
- case ' getRoomTemperature' : {
127
- const temperature =
128
- homeTemperatures [
129
- parameters .room as keyof typeof homeTemperatures
130
- ];
131
-
132
- return {
133
- tool_call_id: toolCall .id ,
134
- output: temperature .toString (),
135
- };
136
- }
137
-
138
- case ' setRoomTemperature' : {
139
- const oldTemperature =
140
- homeTemperatures [
141
- parameters .room as keyof typeof homeTemperatures
142
- ];
143
-
144
- homeTemperatures [
145
- parameters .room as keyof typeof homeTemperatures
146
- ] = parameters .temperature ;
147
-
148
- sendDataMessage ({
149
- role: ' data' ,
150
- data: {
151
- oldTemperature ,
152
- newTemperature: parameters .temperature ,
153
- description: ` Temperature in ${parameters .room } changed from ${oldTemperature } to ${parameters .temperature } ` ,
154
- },
155
- });
156
-
157
- return {
158
- tool_call_id: toolCall .id ,
159
- output: ` temperature set successfully ` ,
160
- };
161
- }
162
-
163
- default :
164
- throw new Error (
165
- ` Unknown tool call function: ${toolCall .function .name } ` ,
166
- );
167
- }
168
- },
169
- );
170
-
171
- run = await openai .beta .threads .runs .submitToolOutputs (
172
- threadId ! ,
173
- run .id ,
174
- { tool_outputs },
175
- );
176
-
177
- await waitForRun (run );
178
- }
179
- }
180
- }
181
-
182
- await waitForRun (run );
183
-
184
- // Get new thread messages (after our message)
185
- const responseMessages = (
186
- await openai .beta .threads .messages .list (threadId , {
187
- after: createdMessage .id ,
188
- order: ' asc' ,
189
- })
190
- ).data ;
191
-
192
- // Send the messages
193
- for (const message of responseMessages ) {
194
- sendMessage ({
195
- id: message .id ,
196
- role: ' assistant' ,
197
- content: message .content .filter (
198
- content => content .type === ' text' ,
199
- ) as Array <MessageContentText >,
200
- });
98
+ // forward run status would stream message deltas
99
+ let runResult = await forwardStream (runStream );
100
+
101
+ // status can be: queued, in_progress, requires_action, cancelling, cancelled, failed, completed, or expired
102
+ while (
103
+ runResult .status === ' requires_action' &&
104
+ runResult .required_action ?.type === ' submit_tool_outputs'
105
+ ) {
106
+ const tool_outputs =
107
+ runResult .required_action .submit_tool_outputs .tool_calls .map (
108
+ (toolCall : any ) => {
109
+ const parameters = JSON .parse (toolCall .function .arguments );
110
+
111
+ switch (toolCall .function .name ) {
112
+ case ' getRoomTemperature' : {
113
+ const temperature =
114
+ homeTemperatures [
115
+ parameters .room as keyof typeof homeTemperatures
116
+ ];
117
+
118
+ return {
119
+ tool_call_id: toolCall .id ,
120
+ output: temperature .toString (),
121
+ };
122
+ }
123
+
124
+ case ' setRoomTemperature' : {
125
+ const oldTemperature =
126
+ homeTemperatures [
127
+ parameters .room as keyof typeof homeTemperatures
128
+ ];
129
+
130
+ homeTemperatures [
131
+ parameters .room as keyof typeof homeTemperatures
132
+ ] = parameters .temperature ;
133
+
134
+ sendDataMessage ({
135
+ role: ' data' ,
136
+ data: {
137
+ oldTemperature ,
138
+ newTemperature: parameters .temperature ,
139
+ description: ` Temperature in ${parameters .room } changed from ${oldTemperature } to ${parameters .temperature } ` ,
140
+ },
141
+ });
142
+
143
+ return {
144
+ tool_call_id: toolCall .id ,
145
+ output: ` temperature set successfully ` ,
146
+ };
147
+ }
148
+
149
+ default :
150
+ throw new Error (
151
+ ` Unknown tool call function: ${toolCall .function .name } ` ,
152
+ );
153
+ }
154
+ },
155
+ );
156
+
157
+ runResult = await forwardStream (
158
+ openai .beta .threads .runs .submitToolOutputsStream (
159
+ threadId ,
160
+ runResult .id ,
161
+ { tool_outputs },
162
+ ),
163
+ );
201
164
}
202
165
},
203
166
);
0 commit comments