Skip to content

Commit 1bf1fa2

Browse files
OpenAI: TypeSpec representations of new Assistants streaming response models (#28555)
* initial commit for models in support of streaming Assistants calls * merge + pr feedback * [OpenAI] [Assistants] PR feedback (#28786) * Adding streaming events and modified class visibilities * Represented the alias as a union to align better with the swagger and have a class generated * Adding chunk classes to be included on code emission * Update specification/ai/OpenAI.Assistants/streaming/events.tsp * Added usage models for run and runStep (#28864) * Added usage models for run and runStep * Added added annotation * Added warning suppresion for nullable fields * Compiled with new models and unions * back ported everything to a past version. Extracted SubmitToolOutputsOptions model * re-compile * Removed toolresources for now and added warning supressions * Brought up to date the classes related to streaming for AssistantStreamEvent * Making filename mandatory uploadFile operation * Project compilation * Re-formated definitiones according to CI instructions * Added missing documentation * Reverted nullability of fileName * re-compiled * Removed openapi v2 and v3 files generated with the placeholder version * reformating * Maded the stream events public to expose types and docs to users * Made stream events publics * remove single-use options model, merge into route params directly * proactively add 2024-05-01-preview label * Removed 05_01 from service version enum ... for now * Added string type to AssistantStreamEvent * tsp validation check --------- Co-authored-by: Jose Alvarez <[email protected]> Co-authored-by: Jose Alvarez <[email protected]>
1 parent 162fb3a commit 1bf1fa2

File tree

9 files changed

+1668
-45
lines changed

9 files changed

+1668
-45
lines changed

specification/ai/OpenAI.Assistants/client.tsp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,62 @@ namespace Azure.AI.OpenAI.Assistants {
156156

157157
// Ensure some shared types remain public despite interaction with previously internalized details
158158

159+
// Ensure generator inclusion of streaming "leaf" types not yet referenced by a route
160+
161+
@@usage(MessageDeltaTextFileCitationAnnotation, Usage.output);
162+
@@access(MessageDeltaTextFileCitationAnnotation, Access.public);
163+
164+
@@usage(MessageDeltaTextFilePathAnnotation, Usage.output);
165+
@@access(MessageDeltaTextFilePathAnnotation, Access.public);
166+
167+
@@usage(MessageDeltaImageFileContent, Usage.output);
168+
@@access(MessageDeltaImageFileContent, Access.public);
169+
170+
@@usage(MessageDeltaTextContent, Usage.output);
171+
@@access(MessageDeltaTextContent, Access.public);
172+
173+
@@usage(RunStepDeltaMessageCreationObject, Usage.output);
174+
@@access(RunStepDeltaMessageCreationObject, Access.public);
175+
176+
@@usage(RunStepDeltaFunction, Usage.output);
177+
@@access(RunStepDeltaFunction, Access.public);
178+
179+
@@usage(RunStepDeltaCodeInterpreterLogOutput, Usage.output);
180+
@@access(RunStepDeltaCodeInterpreterLogOutput, Access.public);
181+
182+
@@usage(RunStepDeltaCodeInterpreterImageOutputObject, Usage.output);
183+
@@access(RunStepDeltaCodeInterpreterImageOutputObject, Access.public);
184+
185+
@@usage(RunStepDeltaChunk, Usage.output);
186+
@@access(RunStepDeltaChunk, Access.public);
187+
188+
@@usage(MessageDeltaChunk, Usage.output);
189+
@@access(MessageDeltaChunk, Access.public);
190+
191+
// Stream events : made public to expose documentation and make class casting for strongly typed languages easier
192+
193+
@@usage(AssistantStreamEvent, Usage.output);
194+
@@access(AssistantStreamEvent, Access.public);
195+
196+
@@usage(ThreadStreamEvent, Usage.output);
197+
@@access(ThreadStreamEvent, Access.public);
198+
199+
@@usage(RunStreamEvent, Usage.output);
200+
@@access(RunStreamEvent, Access.public);
201+
202+
@@usage(RunStepStreamEvent, Usage.output);
203+
@@access(RunStepStreamEvent, Access.public);
204+
205+
@@usage(MessageStreamEvent, Usage.output);
206+
@@access(MessageStreamEvent, Access.public);
207+
208+
@@usage(ErrorEvent, Usage.output);
209+
@@access(ErrorEvent, Access.public);
210+
211+
@@usage(DoneEvent, Usage.output);
212+
@@access(DoneEvent, Access.public);
213+
214+
// Ensure some shared types remain public despite interaction with previously internalized details
159215
@@access(MessageTextFilePathAnnotation, Access.public);
160216
@@access(MessageTextFileCitationAnnotation, Access.public);
161217
@@access(ListSortOrder, Access.public);

specification/ai/OpenAI.Assistants/main.tsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "./messages/main.tsp";
77
import "./runs/main.tsp";
88
import "./run_steps/main.tsp";
99
import "./files/main.tsp";
10+
import "./streaming/events.tsp";
1011

1112
using TypeSpec.Http;
1213
using TypeSpec.Versioning;

specification/ai/OpenAI.Assistants/messages/models.tsp

Lines changed: 236 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@ model ThreadMessage {
4141
@doc("The ID of the thread that this message belongs to.")
4242
threadId: string;
4343

44+
/** The status of the message. */
45+
@added(ServiceApiVersions.v2024_02_15_preview)
46+
status: MessageStatus;
47+
48+
/** On an incomplete message, details about why the message is incomplete. */
49+
#suppress "@azure-tools/typespec-azure-core/no-nullable" "OpenAI uses explicit nullability, distinct from optionality"
50+
@encodedName("application/json", "incomplete_details")
51+
@added(ServiceApiVersions.v2024_02_15_preview)
52+
incompleteDetails: MessageIncompleteDetailsReason | null;
53+
54+
/** The Unix timestamp (in seconds) for when the message was completed. */
55+
#suppress "@azure-tools/typespec-azure-core/no-nullable" "OpenAI uses explicit nullability, distinct from optionality"
56+
@encode(DateTimeKnownEncoding.unixTimestamp, int32)
57+
@encodedName("application/json", "completed_at")
58+
@added(ServiceApiVersions.v2024_02_15_preview)
59+
completedAt: utcDateTime | null;
60+
61+
/** The Unix timestamp (in seconds) for when the message was marked as incomplete. */
62+
#suppress "@azure-tools/typespec-azure-core/no-nullable" "OpenAI uses explicit nullability, distinct from optionality"
63+
@encode(DateTimeKnownEncoding.unixTimestamp, int32)
64+
@encodedName("application/json", "incomplete_at")
65+
@added(ServiceApiVersions.v2024_02_15_preview)
66+
incompleteAt: utcDateTime | null;
67+
4468
@doc("The role associated with the assistant thread message.")
4569
role: MessageRole;
4670

@@ -119,14 +143,6 @@ model MessageTextAnnotation {
119143

120144
@doc("The textual content associated with this text annotation item.")
121145
text: string;
122-
123-
@encodedName("application/json", "start_index")
124-
@doc("The first text index associated with this text annotation.")
125-
startIndex: int32;
126-
127-
@encodedName("application/json", "end_index")
128-
@doc("The last text index associated with this text annotation.")
129-
endIndex: int32;
130146
}
131147

132148
// File citation annotation + details
@@ -143,6 +159,14 @@ model MessageTextFileCitationAnnotation extends MessageTextAnnotation {
143159
Generated when the assistant uses the "retrieval" tool to search files.
144160
""")
145161
fileCitation: MessageTextFileCitationDetails;
162+
163+
@encodedName("application/json", "start_index")
164+
@doc("The first text index associated with this text annotation.")
165+
startIndex?: int32;
166+
167+
@encodedName("application/json", "end_index")
168+
@doc("The last text index associated with this text annotation.")
169+
endIndex?: int32;
146170
}
147171

148172
@doc("A representation of a file-based text citation, as used in a file-based annotation of text thread message content.")
@@ -167,6 +191,14 @@ model MessageTextFilePathAnnotation extends MessageTextAnnotation {
167191
@encodedName("application/json", "file_path")
168192
@doc("A URL for the file that's generated when the assistant used the code_interpreter tool to generate a file.")
169193
filePath: MessageTextFilePathDetails;
194+
195+
@encodedName("application/json", "start_index")
196+
@doc("The first text index associated with this text annotation.")
197+
startIndex?: int32;
198+
199+
@encodedName("application/json", "end_index")
200+
@doc("The last text index associated with this text annotation.")
201+
endIndex?: int32;
170202
}
171203

172204
@doc("An encapsulation of an image file ID, as used by message image content.")
@@ -207,3 +239,199 @@ model MessageFile {
207239
@doc("The ID of the message that this file is attached to.")
208240
messageId: string;
209241
}
242+
243+
/** The possible execution status values for a thread message. */
244+
@added(ServiceApiVersions.v2024_02_15_preview)
245+
union MessageStatus {
246+
string,
247+
248+
/** A run is currently creating this message. */
249+
inProgress: "in_progress",
250+
251+
/** This message is incomplete. See incomplete_details for more information. */
252+
incomplete: "incomplete",
253+
254+
/** This message was successfully completed by a run. */
255+
completed: "completed",
256+
}
257+
258+
/** Information providing additional detail about a message entering an incomplete status. */
259+
@added(ServiceApiVersions.v2024_02_15_preview)
260+
model MessageIncompleteDetails {
261+
/** The provided reason describing why the message was marked as incomplete. */
262+
reason: MessageIncompleteDetailsReason;
263+
}
264+
265+
/** A set of reasons describing why a message is marked as incomplete. */
266+
@added(ServiceApiVersions.v2024_02_15_preview)
267+
union MessageIncompleteDetailsReason {
268+
string,
269+
270+
/** The run generating the message was terminated due to content filter flagging. */
271+
contentFilter: "content_filter",
272+
273+
/** The run generating the message exhausted available tokens before completion. */
274+
maxTokens: "max_tokens",
275+
276+
/** The run generating the message was cancelled before completion. */
277+
runCancelled: "run_cancelled",
278+
279+
/** The run generating the message failed. */
280+
runFailed: "run_failed",
281+
282+
/** The run generating the message expired. */
283+
runExpired: "run_expired",
284+
}
285+
286+
//
287+
// These types are specifically used for streaming.
288+
//
289+
290+
/** Represents a message delta i.e. any changed fields on a message during streaming. */
291+
@added(ServiceApiVersions.v2024_02_15_preview)
292+
model MessageDeltaChunk {
293+
/** The identifier of the message, which can be referenced in API endpoints. */
294+
id: string;
295+
296+
/** The object type, which is always `thread.message.delta`. */
297+
object: "thread.message.delta";
298+
299+
/** The delta containing the fields that have changed on the Message. */
300+
delta: MessageDelta;
301+
}
302+
303+
/** Represents the typed 'delta' payload within a streaming message delta chunk. */
304+
@added(ServiceApiVersions.v2024_02_15_preview)
305+
model MessageDelta {
306+
/** The entity that produced the message. */
307+
role: MessageRole;
308+
309+
/** The content of the message as an array of text and/or images. */
310+
content: MessageDeltaContent[];
311+
}
312+
313+
/** The abstract base representation of a partial streamed message content payload. */
314+
@discriminator("type")
315+
@added(ServiceApiVersions.v2024_02_15_preview)
316+
model MessageDeltaContent {
317+
/** The index of the content part of the message. */
318+
index: int32;
319+
320+
/** The type of content for this content part. */
321+
type: string;
322+
}
323+
324+
/** Represents a streamed image file content part within a streaming message delta chunk. */
325+
@added(ServiceApiVersions.v2024_02_15_preview)
326+
model MessageDeltaImageFileContent extends MessageDeltaContent {
327+
/** The type of content for this content part, which is always "image_file." */
328+
type: "image_file";
329+
330+
/** The image_file data. */
331+
@encodedName("application/json", "image_file")
332+
imageFile?: MessageDeltaImageFileContentObject;
333+
}
334+
335+
/** Represents the 'image_file' payload within streaming image file content. */
336+
@added(ServiceApiVersions.v2024_02_15_preview)
337+
model MessageDeltaImageFileContentObject {
338+
/** The file ID of the image in the message content. */
339+
@encodedName("application/json", "file_id")
340+
fileId?: string;
341+
}
342+
343+
/** Represents a streamed text content part within a streaming message delta chunk. */
344+
@added(ServiceApiVersions.v2024_02_15_preview)
345+
model MessageDeltaTextContentObject extends MessageDeltaContent {
346+
/** The type of content for this content part, which is always "text." */
347+
type: "text";
348+
349+
/** The text content details. */
350+
text?: MessageDeltaTextContent;
351+
}
352+
353+
/** Represents the data of a streamed text content part within a streaming message delta chunk. */
354+
@added(ServiceApiVersions.v2024_02_15_preview)
355+
model MessageDeltaTextContent {
356+
/** The data that makes up the text. */
357+
value?: string;
358+
359+
/** Annotations for the text. */
360+
annotations?: MessageDeltaTextAnnotation[];
361+
}
362+
363+
/** The abstract base representation of a streamed text content part's text annotation. */
364+
@discriminator("type")
365+
@added(ServiceApiVersions.v2024_02_15_preview)
366+
model MessageDeltaTextAnnotation {
367+
/** The index of the annotation within a text content part. */
368+
index: int32;
369+
370+
/** The type of the text content annotation. */
371+
type: string;
372+
}
373+
374+
/** Represents a streamed file citation applied to a streaming text content part. */
375+
@added(ServiceApiVersions.v2024_02_15_preview)
376+
model MessageDeltaTextFileCitationAnnotationObject
377+
extends MessageDeltaTextAnnotation {
378+
/** The type of the text content annotation, which is always "file_citation." */
379+
type: "file_citation";
380+
381+
/** The file citation information. */
382+
@encodedName("application/json", "file_citation")
383+
fileCitation?: MessageDeltaTextFileCitationAnnotation;
384+
385+
/** The text in the message content that needs to be replaced */
386+
text?: string;
387+
388+
/** The start index of this annotation in the content text. */
389+
@encodedName("application/json", "start_index")
390+
startIndex?: int32;
391+
392+
/** The end index of this annotation in the content text. */
393+
@encodedName("application/json", "end_index")
394+
endIndex?: int32;
395+
}
396+
397+
/** Represents the data of a streamed file citation as applied to a streaming text content part. */
398+
@added(ServiceApiVersions.v2024_02_15_preview)
399+
model MessageDeltaTextFileCitationAnnotation {
400+
/** The ID of the specific file the citation is from. */
401+
@encodedName("application/json", "file_id")
402+
fileId?: string;
403+
404+
/** The specific quote in the cited file. */
405+
quote?: string;
406+
}
407+
408+
/** Represents a streamed file path annotation applied to a streaming text content part. */
409+
@added(ServiceApiVersions.v2024_02_15_preview)
410+
model MessageDeltaTextFilePathAnnotationObject
411+
extends MessageDeltaTextAnnotation {
412+
/** The type of the text content annotation, which is always "file_path." */
413+
type: "file_path";
414+
415+
/** The file path information. */
416+
@encodedName("application/json", "file_path")
417+
filePath?: MessageDeltaTextFilePathAnnotation;
418+
419+
/** The start index of this annotation in the content text. */
420+
@encodedName("application/json", "start_index")
421+
startIndex?: int32;
422+
423+
/** The end index of this annotation in the content text. */
424+
@encodedName("application/json", "end_index")
425+
endIndex?: int32;
426+
427+
/** The text in the message content that needs to be replaced */
428+
text?: string;
429+
}
430+
431+
/** Represents the data of a streamed file path annotation as applied to a streaming text content part. */
432+
@added(ServiceApiVersions.v2024_02_15_preview)
433+
model MessageDeltaTextFilePathAnnotation {
434+
/** The file ID for the annotation. */
435+
@encodedName("application/json", "file_id")
436+
fileId?: string;
437+
}

0 commit comments

Comments
 (0)