Skip to content

Commit 0188233

Browse files
MarkDaoustcopybara-github
authored andcommitted
feat: interaction.{output_text,output_image,output_audio,output_video}
Add SDK methods for shortcut properties on the response object to access the output generated in response to the current request, without forcing developers to iterate through the full steps timeline or filter out previous conversation history: interaction.output_text: Concatenated last consecutive text generated by the model in response to the current request. .output_image: The last image generated by the model in response to the current request. .output_audio: The last audio clip generated by the model in response to the current request. .output_video: The last video generated by the model in response to the current request. PiperOrigin-RevId: 915804808
1 parent 2a51b78 commit 0188233

1 file changed

Lines changed: 103 additions & 9 deletions

File tree

src/interactions/resources/interactions.ts

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,17 @@ export class BaseInteractions extends APIResource {
7474
...options,
7575
stream: isStreaming,
7676
...(needsLegacyLyriaShim && isStreaming ? { __streamClass: LegacyLyriaStream } : {}),
77-
}) as APIPromise<Interaction> | APIPromise<Stream<InteractionSSEEvent>>;
78-
if (needsLegacyLyriaShim && !isStreaming) {
79-
return (promise as APIPromise<Interaction>)._thenUnwrap(
80-
(data) => coerceLegacyInteractionResponse(data) as Interaction,
81-
);
77+
});
78+
79+
if (isStreaming) {
80+
return promise as APIPromise<Stream<InteractionSSEEvent>>;
81+
}
82+
83+
let nonStreaming = promise as APIPromise<Interaction>;
84+
if (needsLegacyLyriaShim) {
85+
nonStreaming = nonStreaming._thenUnwrap((data) => coerceLegacyInteractionResponse(data) as Interaction);
8286
}
83-
return promise;
87+
return nonStreaming._thenUnwrap(addOutputProperties);
8488
}
8589

8690
/**
@@ -119,7 +123,9 @@ export class BaseInteractions extends APIResource {
119123
options?: RequestOptions,
120124
): APIPromise<Interaction> {
121125
const { api_version = this._client.apiVersion } = params ?? {};
122-
return this._client.post(path`/${api_version}/interactions/${id}/cancel`, options);
126+
return (
127+
this._client.post(path`/${api_version}/interactions/${id}/cancel`, options) as APIPromise<Interaction>
128+
)._thenUnwrap(addOutputProperties);
123129
}
124130

125131
/**
@@ -154,15 +160,75 @@ export class BaseInteractions extends APIResource {
154160
options?: RequestOptions,
155161
): APIPromise<Interaction> | APIPromise<Stream<InteractionSSEEvent>> {
156162
const { api_version = this._client.apiVersion, ...query } = params ?? {};
157-
return this._client.get(path`/${api_version}/interactions/${id}`, {
163+
const response = this._client.get(path`/${api_version}/interactions/${id}`, {
158164
query,
159165
...options,
160166
stream: params?.stream ?? false,
161-
}) as APIPromise<Interaction> | APIPromise<Stream<InteractionSSEEvent>>;
167+
});
168+
169+
if (params?.stream) {
170+
return response as APIPromise<Stream<InteractionSSEEvent>>;
171+
}
172+
173+
return (response as APIPromise<Interaction>)._thenUnwrap(addOutputProperties);
162174
}
163175
}
164176
export class Interactions extends BaseInteractions {}
165177

178+
function addOutputProperties(interaction: Interaction): Interaction {
179+
const steps = interaction.steps ?? [];
180+
181+
let firstTrailing = steps.length;
182+
while (firstTrailing > 0 && steps[firstTrailing - 1]!.type === 'model_output') {
183+
firstTrailing--;
184+
}
185+
const modelSteps = steps.slice(firstTrailing) as ModelOutputStep[];
186+
187+
const output = modelSteps.flatMap((step) => step.content ?? []);
188+
189+
const textParts: string[] = [];
190+
for (let i = output.length - 1; i >= 0; i--) {
191+
const content = output[i]!;
192+
if (content.type !== 'text') break;
193+
textParts.push(content.text ?? '');
194+
}
195+
const output_text = textParts.reverse().join('');
196+
197+
let output_image: ImageContent | undefined;
198+
let output_audio: AudioContent | undefined;
199+
let output_video: VideoContent | undefined;
200+
201+
for (let i = steps.length - 1; i >= 0; i--) {
202+
const step = steps[i]!;
203+
const anyStep = step as any;
204+
if (anyStep.type === 'user_input') {
205+
break;
206+
}
207+
if (anyStep.type === 'model_output' && anyStep.content) {
208+
for (let j = anyStep.content.length - 1; j >= 0; j--) {
209+
const content = anyStep.content[j]!;
210+
if (content.type === 'image' && !output_image) {
211+
output_image = content as any;
212+
}
213+
if (content.type === 'audio' && !output_audio) {
214+
output_audio = content as any;
215+
}
216+
if (content.type === 'video' && !output_video) {
217+
output_video = content as any;
218+
}
219+
}
220+
}
221+
}
222+
223+
return {
224+
...interaction,
225+
...(output_text && { output_text }),
226+
...(output_image && { output_image }),
227+
...(output_audio && { output_audio }),
228+
...(output_video && { output_video }),
229+
};
230+
}
231+
166232
/**
167233
* The configuration for allowed tools.
168234
*/
@@ -1134,6 +1200,34 @@ export interface Interaction {
11341200
* completes.
11351201
*/
11361202
webhook_config?: WebhookConfig;
1203+
1204+
/**
1205+
* Concatenated text from the last model output in response to the current request.
1206+
*
1207+
* Note: this is added by the SDK.
1208+
*/
1209+
output_text?: string;
1210+
1211+
/**
1212+
* The last image generated by the model in response to the current request.
1213+
*
1214+
* Note: this is added by the SDK.
1215+
*/
1216+
output_image?: ImageContent;
1217+
1218+
/**
1219+
* The last audio generated by the model in response to the current request.
1220+
*
1221+
* Note: this is added by the SDK.
1222+
*/
1223+
output_audio?: AudioContent;
1224+
1225+
/**
1226+
* The last video generated by the model in response to the current request.
1227+
*
1228+
* Note: this is added by the SDK.
1229+
*/
1230+
output_video?: VideoContent;
11371231
}
11381232

11391233
export interface InteractionCompletedEvent {

0 commit comments

Comments
 (0)