Skip to main content

openai_core/resources/
responses.rs

1//! Responses and Realtime namespace implementations and builders.
2
3use std::collections::BTreeMap;
4#[cfg(feature = "structured-output")]
5use std::marker::PhantomData;
6use std::time::Duration;
7
8use http::Method;
9#[cfg(feature = "structured-output")]
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13use tokio_util::sync::CancellationToken;
14
15use crate::Client;
16use crate::config::RequestOptions;
17use crate::error::{Error, Result};
18use crate::generated::endpoints;
19#[cfg(feature = "structured-output")]
20use crate::helpers::{ParsedResponse, parse_json_payload};
21use crate::json_payload::JsonPayload;
22use crate::response_meta::ApiResponse;
23use crate::stream::{ResponseEventStream, ResponseStream};
24use crate::transport::{RequestSpec, merge_json_body};
25#[cfg(feature = "realtime")]
26use crate::websocket::RealtimeSocket;
27#[cfg(feature = "responses-ws")]
28use crate::websocket::ResponsesSocket;
29
30use super::{
31    ChatToolDefinition, ConversationItem, DeleteResponse, InputTokenCount, JsonRequestBuilder,
32    ListRequestBuilder, McpToolDefinition, NoContentRequestBuilder, RealtimeCallsResource,
33    RealtimeClientSecretsResource, RealtimeResource, RealtimeSessionPayload, Response,
34    ResponseCreateParams, ResponseInputItemPayload, ResponseInputItemsResource,
35    ResponseInputPayload, ResponseInputTokensResource, ResponsesResource, encode_path_segment,
36    value_from,
37};
38
39/// Realtime API 返回的临时 client secret。
40#[derive(Debug, Clone, Serialize, Deserialize, Default)]
41pub struct RealtimeSessionClientSecret {
42    /// 过期时间。
43    pub expires_at: u64,
44    /// 可下发给前端的临时密钥。
45    #[serde(default)]
46    pub value: String,
47    /// 额外字段。
48    #[serde(flatten)]
49    pub extra: BTreeMap<String, Value>,
50}
51
52/// `realtime.client_secrets.create` 的返回值。
53#[derive(Debug, Clone, Serialize, Deserialize, Default)]
54pub struct RealtimeClientSecretCreateResponse {
55    /// 官方 documented spec 返回的顶层 secret 值。
56    pub value: Option<String>,
57    /// 官方 documented spec 返回的顶层过期时间。
58    pub expires_at: Option<u64>,
59    /// 新版结构化 client secret。
60    pub client_secret: Option<RealtimeSessionClientSecret>,
61    /// 某些兼容 Provider 返回的扁平 secret 字段。
62    pub secret: Option<String>,
63    /// 会话配置类型。
64    #[serde(rename = "type")]
65    pub session_type: Option<String>,
66    /// 生效后的会话配置。
67    pub session: Option<RealtimeSessionPayload>,
68    /// 额外字段。
69    #[serde(flatten)]
70    pub extra: BTreeMap<String, Value>,
71}
72
73impl RealtimeClientSecretCreateResponse {
74    /// 返回兼容不同 Provider 形态的 secret 值。
75    pub fn secret_value(&self) -> Option<&str> {
76        self.client_secret
77            .as_ref()
78            .map(|secret| secret.value.as_str())
79            .or(self.value.as_deref())
80            .or(self.secret.as_deref())
81    }
82}
83
84impl ResponsesResource {
85    /// 创建 responses 请求构建器。
86    pub fn create(&self) -> ResponseCreateRequestBuilder {
87        ResponseCreateRequestBuilder::new(self.client.clone())
88    }
89
90    /// 创建 responses 结构化解析构建器。
91    #[cfg(feature = "structured-output")]
92    #[cfg_attr(docsrs, doc(cfg(feature = "structured-output")))]
93    pub fn parse<T>(&self) -> ResponseParseRequestBuilder<T> {
94        ResponseParseRequestBuilder::new(self.client.clone())
95    }
96
97    /// 创建 responses 流式构建器。
98    pub fn stream(&self) -> ResponseStreamRequestBuilder {
99        ResponseStreamRequestBuilder::new(self.client.clone())
100    }
101
102    /// 按响应 ID 继续一个已有的 Responses SSE 流。
103    pub fn stream_response(&self, response_id: impl Into<String>) -> ResponseStreamRequestBuilder {
104        ResponseStreamRequestBuilder::new(self.client.clone()).response_id(response_id)
105    }
106
107    /// 创建 Responses WebSocket 连接构建器。
108    #[cfg(feature = "responses-ws")]
109    #[cfg_attr(docsrs, doc(cfg(feature = "responses-ws")))]
110    pub fn ws(&self) -> ResponsesSocketRequestBuilder {
111        ResponsesSocketRequestBuilder::new(self.client.clone())
112    }
113
114    /// 获取 response。
115    pub fn retrieve(&self, response_id: impl Into<String>) -> JsonRequestBuilder<Response> {
116        JsonRequestBuilder::new(
117            self.client.clone(),
118            "responses.retrieve",
119            Method::GET,
120            format!("/responses/{}", encode_path_segment(response_id.into())),
121        )
122    }
123
124    /// 删除 response。
125    pub fn delete(&self, response_id: impl Into<String>) -> JsonRequestBuilder<DeleteResponse> {
126        JsonRequestBuilder::new(
127            self.client.clone(),
128            "responses.delete",
129            Method::DELETE,
130            format!("/responses/{}", encode_path_segment(response_id.into())),
131        )
132    }
133
134    /// 取消后台 response。
135    pub fn cancel(&self, response_id: impl Into<String>) -> JsonRequestBuilder<Response> {
136        JsonRequestBuilder::new(
137            self.client.clone(),
138            "responses.cancel",
139            Method::POST,
140            format!(
141                "/responses/{}/cancel",
142                encode_path_segment(response_id.into())
143            ),
144        )
145    }
146
147    /// 压缩 response。
148    pub fn compact(&self) -> JsonRequestBuilder<Response> {
149        JsonRequestBuilder::new(
150            self.client.clone(),
151            "responses.compact",
152            Method::POST,
153            "/responses/compact",
154        )
155    }
156
157    /// 返回 input_items 子资源。
158    pub fn input_items(&self) -> ResponseInputItemsResource {
159        ResponseInputItemsResource::new(self.client.clone())
160    }
161
162    /// 返回 input_tokens 子资源。
163    pub fn input_tokens(&self) -> ResponseInputTokensResource {
164        ResponseInputTokensResource::new(self.client.clone())
165    }
166}
167
168impl ResponseInputItemsResource {
169    /// 列出 response 输入项。
170    pub fn list(&self, response_id: impl Into<String>) -> ListRequestBuilder<ConversationItem> {
171        let endpoint = endpoints::responses::RESPONSES_INPUT_ITEMS_LIST;
172        ListRequestBuilder::new(
173            self.client.clone(),
174            endpoint.id,
175            endpoint.render(&[("response_id", &encode_path_segment(response_id.into()))]),
176        )
177    }
178}
179
180impl ResponseInputTokensResource {
181    /// 统计输入 token。
182    pub fn count(&self) -> JsonRequestBuilder<InputTokenCount> {
183        let endpoint = endpoints::responses::RESPONSES_INPUT_TOKENS_COUNT;
184        JsonRequestBuilder::new(
185            self.client.clone(),
186            endpoint.id,
187            Method::POST,
188            endpoint.template,
189        )
190    }
191}
192
193impl RealtimeResource {
194    /// 创建 Realtime WebSocket 连接构建器。
195    #[cfg(feature = "realtime")]
196    #[cfg_attr(docsrs, doc(cfg(feature = "realtime")))]
197    pub fn ws(&self) -> RealtimeSocketRequestBuilder {
198        RealtimeSocketRequestBuilder::new(self.client.clone())
199    }
200
201    /// 返回 client_secrets 子资源。
202    pub fn client_secrets(&self) -> RealtimeClientSecretsResource {
203        RealtimeClientSecretsResource::new(self.client.clone())
204    }
205
206    /// 返回 calls 子资源。
207    pub fn calls(&self) -> RealtimeCallsResource {
208        RealtimeCallsResource::new(self.client.clone())
209    }
210}
211
212impl RealtimeClientSecretsResource {
213    /// 创建 client secret。
214    pub fn create(&self) -> JsonRequestBuilder<RealtimeClientSecretCreateResponse> {
215        let endpoint = endpoints::responses::REALTIME_CLIENT_SECRETS_CREATE;
216        JsonRequestBuilder::new(
217            self.client.clone(),
218            endpoint.id,
219            Method::POST,
220            endpoint.template,
221        )
222    }
223}
224
225impl RealtimeCallsResource {
226    /// 接听通话。
227    pub fn accept(&self, call_id: impl Into<String>) -> NoContentRequestBuilder {
228        realtime_call_action(
229            self.client.clone(),
230            endpoints::responses::REALTIME_CALLS_ACCEPT,
231            call_id,
232        )
233    }
234
235    /// 挂断通话。
236    pub fn hangup(&self, call_id: impl Into<String>) -> NoContentRequestBuilder {
237        realtime_call_action(
238            self.client.clone(),
239            endpoints::responses::REALTIME_CALLS_HANGUP,
240            call_id,
241        )
242    }
243
244    /// 转接通话。
245    pub fn refer(&self, call_id: impl Into<String>) -> NoContentRequestBuilder {
246        realtime_call_action(
247            self.client.clone(),
248            endpoints::responses::REALTIME_CALLS_REFER,
249            call_id,
250        )
251    }
252
253    /// 拒绝通话。
254    pub fn reject(&self, call_id: impl Into<String>) -> NoContentRequestBuilder {
255        realtime_call_action(
256            self.client.clone(),
257            endpoints::responses::REALTIME_CALLS_REJECT,
258            call_id,
259        )
260    }
261}
262
263fn realtime_call_action(
264    client: Client,
265    endpoint: endpoints::PathTemplateEndpoint,
266    call_id: impl Into<String>,
267) -> NoContentRequestBuilder {
268    NoContentRequestBuilder::new(
269        client,
270        endpoint.id,
271        Method::POST,
272        endpoint.render(&[("call_id", &encode_path_segment(call_id.into()))]),
273    )
274    .extra_header("accept", "*/*")
275}
276
277/// 表示 Responses 创建构建器。
278#[derive(Debug, Clone, Default)]
279pub struct ResponseCreateRequestBuilder {
280    client: Option<Client>,
281    pub(crate) params: ResponseCreateParams,
282    options: RequestOptions,
283    extra_body: BTreeMap<String, Value>,
284    provider_options: BTreeMap<String, Value>,
285    mcp_tools: Vec<McpToolDefinition>,
286}
287
288/// 表示 Responses 流式构建器。
289#[derive(Debug, Clone)]
290pub struct ResponseStreamRequestBuilder {
291    inner: ResponseCreateRequestBuilder,
292    response_id: Option<String>,
293    starting_after: Option<u64>,
294}
295
296/// 表示 Realtime WebSocket 连接构建器。
297#[cfg(feature = "realtime")]
298#[cfg_attr(docsrs, doc(cfg(feature = "realtime")))]
299#[derive(Debug, Clone)]
300pub struct RealtimeSocketRequestBuilder {
301    client: Client,
302    model: Option<String>,
303    options: RequestOptions,
304}
305
306/// 表示 Responses WebSocket 连接构建器。
307#[cfg(feature = "responses-ws")]
308#[cfg_attr(docsrs, doc(cfg(feature = "responses-ws")))]
309#[derive(Debug, Clone)]
310pub struct ResponsesSocketRequestBuilder {
311    client: Client,
312    options: RequestOptions,
313}
314
315impl ResponseStreamRequestBuilder {
316    pub(crate) fn new(client: Client) -> Self {
317        Self {
318            inner: ResponseCreateRequestBuilder::new(client),
319            response_id: None,
320            starting_after: None,
321        }
322    }
323
324    /// 设置模型。
325    pub fn model(mut self, model: impl Into<String>) -> Self {
326        self.inner = self.inner.model(model);
327        self
328    }
329
330    /// 设置输入文本。
331    pub fn input_text(mut self, input: impl Into<String>) -> Self {
332        self.inner = self.inner.input_text(input);
333        self
334    }
335
336    /// 设置输入项数组。
337    pub fn input_items(mut self, items: Vec<ResponseInputItemPayload>) -> Self {
338        self.inner = self.inner.input_items(items);
339        self
340    }
341
342    /// 直接设置输入载荷。
343    pub fn input(mut self, input: impl Into<ResponseInputPayload>) -> Self {
344        self.inner = self.inner.input(input);
345        self
346    }
347
348    /// 设置温度。
349    pub fn temperature(mut self, temperature: f32) -> Self {
350        self.inner = self.inner.temperature(temperature);
351        self
352    }
353
354    /// 追加工具定义。
355    pub fn tool(mut self, tool: ChatToolDefinition) -> Self {
356        self.inner = self.inner.tool(tool);
357        self
358    }
359
360    /// 追加 MCP 工具定义。
361    pub fn mcp_tool(mut self, tool: McpToolDefinition) -> Self {
362        self.inner = self.inner.mcp_tool(tool);
363        self
364    }
365
366    /// 添加请求体字段。
367    pub fn extra_body(mut self, key: impl Into<String>, value: impl Into<JsonPayload>) -> Self {
368        self.inner = self.inner.extra_body(key, value);
369        self
370    }
371
372    /// 添加 provider 选项。
373    pub fn provider_option(
374        mut self,
375        key: impl Into<String>,
376        value: impl Into<JsonPayload>,
377    ) -> Self {
378        self.inner = self.inner.provider_option(key, value);
379        self
380    }
381
382    /// 添加额外请求头。
383    pub fn extra_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
384        self.inner.options.insert_header(key, value);
385        self
386    }
387
388    /// 添加额外查询参数。
389    pub fn extra_query(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
390        self.inner.options.insert_query(key, value);
391        self
392    }
393
394    /// 覆盖请求超时时间。
395    pub fn timeout(mut self, timeout: Duration) -> Self {
396        self.inner.options.timeout = Some(timeout);
397        self
398    }
399
400    /// 覆盖最大重试次数。
401    pub fn max_retries(mut self, max_retries: u32) -> Self {
402        self.inner.options.max_retries = Some(max_retries);
403        self
404    }
405
406    /// 设置取消令牌。
407    pub fn cancellation_token(mut self, token: CancellationToken) -> Self {
408        self.inner.options.cancellation_token = Some(token);
409        self
410    }
411
412    /// 按响应 ID 继续一个已有的 Responses SSE 流。
413    pub fn response_id(mut self, response_id: impl Into<String>) -> Self {
414        self.response_id = Some(response_id.into());
415        self
416    }
417
418    /// 当继续已有流时,只消费给定序号之后的事件。
419    pub fn starting_after(mut self, sequence_number: u64) -> Self {
420        self.starting_after = Some(sequence_number);
421        self
422    }
423
424    /// 发送流式 Responses 请求。
425    ///
426    /// # Errors
427    ///
428    /// 当参数校验失败、请求失败或流初始化失败时返回错误。
429    pub async fn send(mut self) -> Result<ResponseStream> {
430        let (client, spec) = if let Some(response_id) = self.response_id.take() {
431            if self.inner.params.model.is_some()
432                || self.inner.params.input.is_some()
433                || self.inner.params.temperature.is_some()
434                || !self.inner.params.tools.is_empty()
435                || !self.inner.mcp_tools.is_empty()
436                || !self.inner.extra_body.is_empty()
437                || !self.inner.provider_options.is_empty()
438            {
439                return Err(Error::InvalidConfig(
440                    "按 response_id 继续流时,不应再设置创建期参数或请求体扩展字段".into(),
441                ));
442            }
443
444            let client = self
445                .inner
446                .client
447                .take()
448                .ok_or_else(|| Error::InvalidConfig("Responses 构建器缺少客户端".into()))?;
449            let mut spec = RequestSpec::new(
450                "responses.stream.retrieve",
451                Method::GET,
452                format!("/responses/{}", encode_path_segment(response_id)),
453            );
454            spec.options = self.inner.options;
455            spec.options.insert_query("stream", "true");
456            if let Some(sequence_number) = self.starting_after {
457                spec.options
458                    .insert_query("starting_after", sequence_number.to_string());
459            }
460            (client, spec)
461        } else {
462            if self.starting_after.is_some() {
463                return Err(Error::InvalidConfig(
464                    "`starting_after` 只能与 `response_id` 一起使用".into(),
465                ));
466            }
467            self.inner.build_spec(true)?
468        };
469        Ok(ResponseStream::new(client.execute_sse(spec).await?))
470    }
471
472    /// 发送流式 Responses 请求,并返回带高层语义事件的运行时流。
473    ///
474    /// # Errors
475    ///
476    /// 当参数校验失败、请求失败或流初始化失败时返回错误。
477    pub async fn send_events(self) -> Result<ResponseEventStream> {
478        Ok(self.send().await?.events())
479    }
480}
481
482#[cfg(feature = "realtime")]
483impl RealtimeSocketRequestBuilder {
484    pub(crate) fn new(client: Client) -> Self {
485        Self {
486            client,
487            model: None,
488            options: RequestOptions::default(),
489        }
490    }
491
492    /// 设置 Realtime 连接所使用的模型或 deployment。
493    pub fn model(mut self, model: impl Into<String>) -> Self {
494        self.model = Some(model.into());
495        self
496    }
497
498    /// 添加额外请求头。
499    pub fn extra_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
500        self.options.insert_header(key, value);
501        self
502    }
503
504    /// 添加额外查询参数。
505    pub fn extra_query(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
506        self.options.insert_query(key, value);
507        self
508    }
509
510    /// 建立 Realtime WebSocket 连接。
511    ///
512    /// # Errors
513    ///
514    /// 当参数校验失败或握手失败时返回错误。
515    pub async fn connect(self) -> Result<RealtimeSocket> {
516        RealtimeSocket::connect(&self.client, self.model, self.options).await
517    }
518}
519
520#[cfg(feature = "responses-ws")]
521impl ResponsesSocketRequestBuilder {
522    pub(crate) fn new(client: Client) -> Self {
523        Self {
524            client,
525            options: RequestOptions::default(),
526        }
527    }
528
529    /// 添加额外请求头。
530    pub fn extra_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
531        self.options.insert_header(key, value);
532        self
533    }
534
535    /// 添加额外查询参数。
536    pub fn extra_query(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
537        self.options.insert_query(key, value);
538        self
539    }
540
541    /// 建立 Responses WebSocket 连接。
542    ///
543    /// # Errors
544    ///
545    /// 当握手失败时返回错误。
546    pub async fn connect(self) -> Result<ResponsesSocket> {
547        ResponsesSocket::connect(&self.client, self.options).await
548    }
549}
550
551impl ResponseCreateRequestBuilder {
552    pub(crate) fn new(client: Client) -> Self {
553        Self {
554            client: Some(client),
555            ..Self::default()
556        }
557    }
558
559    /// 设置模型。
560    pub fn model(mut self, model: impl Into<String>) -> Self {
561        self.params.model = Some(model.into());
562        self
563    }
564
565    /// 直接设置输入文本。
566    pub fn input_text(mut self, input: impl Into<String>) -> Self {
567        self.params.input = Some(ResponseInputPayload::from(input.into()));
568        self
569    }
570
571    /// 设置输入项数组。
572    pub fn input_items(mut self, items: Vec<ResponseInputItemPayload>) -> Self {
573        self.params.input = Some(ResponseInputPayload::from(items));
574        self
575    }
576
577    /// 直接设置输入载荷。
578    pub fn input(mut self, input: impl Into<ResponseInputPayload>) -> Self {
579        self.params.input = Some(input.into());
580        self
581    }
582
583    /// 设置温度。
584    pub fn temperature(mut self, temperature: f32) -> Self {
585        self.params.temperature = Some(temperature);
586        self
587    }
588
589    /// 追加工具定义。
590    pub fn tool(mut self, tool: ChatToolDefinition) -> Self {
591        self.params.tools.push(tool);
592        self
593    }
594
595    /// 追加 MCP 工具定义。
596    pub fn mcp_tool(mut self, tool: McpToolDefinition) -> Self {
597        self.mcp_tools.push(tool);
598        self
599    }
600
601    /// 追加请求体字段。
602    pub fn extra_body(mut self, key: impl Into<String>, value: impl Into<JsonPayload>) -> Self {
603        self.extra_body.insert(key.into(), value.into().into_raw());
604        self
605    }
606
607    /// 追加 provider 选项。
608    pub fn provider_option(
609        mut self,
610        key: impl Into<String>,
611        value: impl Into<JsonPayload>,
612    ) -> Self {
613        self.provider_options
614            .insert(key.into(), value.into().into_raw());
615        self
616    }
617
618    /// 添加额外请求头。
619    pub fn extra_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
620        self.options.insert_header(key, value);
621        self
622    }
623
624    /// 添加额外查询参数。
625    pub fn extra_query(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
626        self.options.insert_query(key, value);
627        self
628    }
629
630    /// 覆盖请求超时时间。
631    pub fn timeout(mut self, timeout: Duration) -> Self {
632        self.options.timeout = Some(timeout);
633        self
634    }
635
636    /// 覆盖最大重试次数。
637    pub fn max_retries(mut self, max_retries: u32) -> Self {
638        self.options.max_retries = Some(max_retries);
639        self
640    }
641
642    /// 设置取消令牌。
643    pub fn cancellation_token(mut self, token: CancellationToken) -> Self {
644        self.options.cancellation_token = Some(token);
645        self
646    }
647
648    pub(crate) fn build_spec(mut self, stream: bool) -> Result<(Client, RequestSpec)> {
649        let client = self
650            .client
651            .take()
652            .ok_or_else(|| Error::InvalidConfig("Responses 构建器缺少客户端".into()))?;
653        if self.params.model.as_deref().unwrap_or_default().is_empty() {
654            return Err(Error::MissingRequiredField { field: "model" });
655        }
656        if self.params.input.is_none() {
657            return Err(Error::MissingRequiredField { field: "input" });
658        }
659
660        self.params.stream = Some(stream);
661        let provider_key = client.provider().kind().as_key();
662        let mut body = merge_json_body(
663            Some(value_from(&self.params)?),
664            &self.extra_body,
665            provider_key,
666            &self.provider_options,
667        );
668        if (!self.params.tools.is_empty() || !self.mcp_tools.is_empty())
669            && let Some(object) = body.as_object_mut()
670        {
671            let mut tools = Vec::with_capacity(self.params.tools.len() + self.mcp_tools.len());
672            tools.extend(
673                self.params
674                    .tools
675                    .iter()
676                    .map(ChatToolDefinition::as_response_tool_value),
677            );
678            for tool in &self.mcp_tools {
679                tools.push(value_from(tool)?);
680            }
681            object.insert("tools".into(), Value::Array(tools));
682        }
683        let mut spec = RequestSpec::new(
684            if stream {
685                "responses.stream"
686            } else {
687                "responses.create"
688            },
689            Method::POST,
690            "/responses",
691        );
692        spec.body = Some(body);
693        spec.options = self.options;
694        Ok((client, spec))
695    }
696
697    /// 发送普通 Responses 请求。
698    ///
699    /// # Errors
700    ///
701    /// 当参数校验失败、请求失败或反序列化失败时返回错误。
702    pub async fn send(self) -> Result<Response> {
703        Ok(self.send_with_meta().await?.data)
704    }
705
706    /// 发送普通 Responses 请求并保留元信息。
707    ///
708    /// # Errors
709    ///
710    /// 当参数校验失败、请求失败或反序列化失败时返回错误。
711    pub async fn send_with_meta(self) -> Result<ApiResponse<Response>> {
712        let (client, spec) = self.build_spec(false)?;
713        client.execute_json(spec).await
714    }
715}
716
717/// 表示 Responses 结构化解析构建器。
718#[cfg(feature = "structured-output")]
719#[derive(Debug, Clone)]
720pub struct ResponseParseRequestBuilder<T> {
721    inner: ResponseCreateRequestBuilder,
722    _marker: PhantomData<T>,
723}
724
725#[cfg(feature = "structured-output")]
726impl<T> ResponseParseRequestBuilder<T> {
727    pub(crate) fn new(client: Client) -> Self {
728        Self {
729            inner: ResponseCreateRequestBuilder::new(client),
730            _marker: PhantomData,
731        }
732    }
733
734    /// 设置模型。
735    pub fn model(mut self, model: impl Into<String>) -> Self {
736        self.inner = self.inner.model(model);
737        self
738    }
739
740    /// 设置输入文本。
741    pub fn input_text(mut self, input: impl Into<String>) -> Self {
742        self.inner = self.inner.input_text(input);
743        self
744    }
745
746    /// 设置输入数组。
747    pub fn input_items(mut self, items: Vec<ResponseInputItemPayload>) -> Self {
748        self.inner = self.inner.input_items(items);
749        self
750    }
751}
752
753#[cfg(feature = "structured-output")]
754impl<T> ResponseParseRequestBuilder<T>
755where
756    T: JsonSchema + serde::de::DeserializeOwned,
757{
758    /// 发送请求并解析结构化输出。
759    ///
760    /// # Errors
761    ///
762    /// 当响应缺少可解析文本或 JSON 解析失败时返回错误。
763    pub async fn send(self) -> Result<ParsedResponse<T>> {
764        let response = self.inner.send().await?;
765        let output_text = response
766            .output_text()
767            .ok_or_else(|| Error::InvalidConfig("Responses 返回中缺少可解析文本".into()))?;
768        let parsed = parse_json_payload(&output_text)?;
769        Ok(ParsedResponse { response, parsed })
770    }
771}