Skip to content

Commit 0a2a810

Browse files
Merge pull request #128 from jamesrochabrun/jroch-issues
Support for Response API (Non Stream)
2 parents 318c23c + b505cad commit 0a2a810

18 files changed

+2132
-6
lines changed

README.md

+291
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ An open-source Swift package designed for effortless interaction with OpenAI's p
3333
- [Function Calling](#function-calling)
3434
- [Structured Outputs](#structured-outputs)
3535
- [Vision](#vision)
36+
- [Response](#response)
3637
- [Embeddings](#embeddings)
3738
- [Fine-tuning](#fine-tuning)
3839
- [Batch](#batch)
@@ -1260,6 +1261,296 @@ let chatCompletionObject = try await service.startStreamedChat(parameters: param
12601261

12611262
For more details about how to also uploading base 64 encoded images in iOS check the [ChatVision](https://github.com/jamesrochabrun/SwiftOpenAI/tree/main/Examples/SwiftOpenAIExample/SwiftOpenAIExample/Vision) demo on the Examples section of this package.
12621263

1264+
### Response
1265+
1266+
OpenAI's most advanced interface for generating model responses. Supports text and image inputs, and text outputs. Create stateful interactions with the model, using the output of previous responses as input. Extend the model's capabilities with built-in tools for file search, web search, computer use, and more. Allow the model access to external systems and data using function calling.
1267+
1268+
Related guides:
1269+
1270+
- [Quickstart](https://platform.openai.com/docs/quickstart?api-mode=responses)
1271+
- [Text inputs and outputs](https://platform.openai.com/docs/guides/text?api-mode=responses)
1272+
- [Image inputs](https://platform.openai.com/docs/guides/images?api-mode=responses)
1273+
- [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses)
1274+
- [Function calling](https://platform.openai.com/docs/guides/function-calling?api-mode=responses)
1275+
- [Conversation state](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses)
1276+
- [Extend the models with tools](https://platform.openai.com/docs/guides/tools?api-mode=responses)
1277+
1278+
Parameters
1279+
```swift
1280+
/// [Creates a model response.](https://platform.openai.com/docs/api-reference/responses/create)
1281+
public struct ModelResponseParameter: Codable {
1282+
1283+
/// Text, image, or file inputs to the model, used to generate a response.
1284+
/// A text input to the model, equivalent to a text input with the user role.
1285+
/// A list of one or many input items to the model, containing different content types.
1286+
public var input: InputType
1287+
1288+
/// Model ID used to generate the response, like gpt-4o or o1. OpenAI offers a wide range of models with
1289+
/// different capabilities, performance characteristics, and price points.
1290+
/// Refer to the model guide to browse and compare available models.
1291+
public var model: String
1292+
1293+
/// Specify additional output data to include in the model response. Currently supported values are:
1294+
/// file_search_call.results : Include the search results of the file search tool call.
1295+
/// message.input_image.image_url : Include image urls from the input message.
1296+
/// computer_call_output.output.image_url : Include image urls from the computer call output.
1297+
public var include: [String]?
1298+
1299+
/// Inserts a system (or developer) message as the first item in the model's context.
1300+
/// When using along with previous_response_id, the instructions from a previous response will be not be
1301+
/// carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses.
1302+
public var instructions: String?
1303+
1304+
/// An upper bound for the number of tokens that can be generated for a response, including visible output tokens
1305+
/// and reasoning tokens.
1306+
public var maxOutputTokens: Int?
1307+
1308+
/// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information
1309+
/// about the object in a structured format, and querying for objects via API or the dashboard.
1310+
/// Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters.
1311+
public var metadata: [String: String]?
1312+
1313+
/// Whether to allow the model to run tool calls in parallel.
1314+
/// Defaults to true
1315+
public var parallelToolCalls: Bool?
1316+
1317+
/// The unique ID of the previous response to the model. Use this to create multi-turn conversations.
1318+
/// Learn more about conversation state.
1319+
public var previousResponseId: String?
1320+
1321+
/// o-series models only
1322+
/// Configuration options for reasoning models.
1323+
public var reasoning: Reasoning?
1324+
1325+
/// Whether to store the generated model response for later retrieval via API.
1326+
/// Defaults to true
1327+
public var store: Bool?
1328+
1329+
/// If set to true, the model response data will be streamed to the client as it is generated using server-sent events.
1330+
public var stream: Bool?
1331+
1332+
/// What sampling temperature to use, between 0 and 2.
1333+
/// Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.
1334+
/// We generally recommend altering this or top_p but not both.
1335+
/// Defaults to 1
1336+
public var temperature: Double?
1337+
1338+
/// Configuration options for a text response from the model. Can be plain text or structured JSON data.
1339+
public var text: TextConfiguration?
1340+
1341+
/// How the model should select which tool (or tools) to use when generating a response.
1342+
/// See the tools parameter to see how to specify which tools the model can call.
1343+
public var toolChoice: ToolChoiceMode?
1344+
1345+
/// An array of tools the model may call while generating a response. You can specify which tool to use by setting the tool_choice parameter.
1346+
public var tools: [Tool]?
1347+
1348+
/// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass.
1349+
/// So 0.1 means only the tokens comprising the top 10% probability mass are considered.
1350+
/// We generally recommend altering this or temperature but not both.
1351+
/// Defaults to 1
1352+
public var topP: Double?
1353+
1354+
/// The truncation strategy to use for the model response.
1355+
/// Defaults to disabled
1356+
public var truncation: String?
1357+
1358+
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
1359+
public var user: String?
1360+
}
1361+
```
1362+
1363+
[The Response object](https://platform.openai.com/docs/api-reference/responses/object)
1364+
1365+
```swift
1366+
/// The Response object returned when retrieving a model response
1367+
public struct ResponseModel: Decodable {
1368+
1369+
/// Unix timestamp (in seconds) of when this Response was created.
1370+
public let createdAt: Int
1371+
1372+
/// An error object returned when the model fails to generate a Response.
1373+
public let error: ErrorObject?
1374+
1375+
/// Unique identifier for this Response.
1376+
public let id: String
1377+
1378+
/// Details about why the response is incomplete.
1379+
public let incompleteDetails: IncompleteDetails?
1380+
1381+
/// Inserts a system (or developer) message as the first item in the model's context.
1382+
public let instructions: String?
1383+
1384+
/// An upper bound for the number of tokens that can be generated for a response, including visible output tokens
1385+
/// and reasoning tokens.
1386+
public let maxOutputTokens: Int?
1387+
1388+
/// Set of 16 key-value pairs that can be attached to an object.
1389+
public let metadata: [String: String]
1390+
1391+
/// Model ID used to generate the response, like gpt-4o or o1.
1392+
public let model: String
1393+
1394+
/// The object type of this resource - always set to response.
1395+
public let object: String
1396+
1397+
/// An array of content items generated by the model.
1398+
public let output: [OutputItem]
1399+
1400+
/// Whether to allow the model to run tool calls in parallel.
1401+
public let parallelToolCalls: Bool
1402+
1403+
/// The unique ID of the previous response to the model. Use this to create multi-turn conversations.
1404+
public let previousResponseId: String?
1405+
1406+
/// Configuration options for reasoning models.
1407+
public let reasoning: Reasoning?
1408+
1409+
/// The status of the response generation. One of completed, failed, in_progress, or incomplete.
1410+
public let status: String
1411+
1412+
/// What sampling temperature to use, between 0 and 2.
1413+
public let temperature: Double?
1414+
1415+
/// Configuration options for a text response from the model.
1416+
public let text: TextConfiguration
1417+
1418+
/// How the model should select which tool (or tools) to use when generating a response.
1419+
public let toolChoice: ToolChoiceMode
1420+
1421+
/// An array of tools the model may call while generating a response.
1422+
public let tools: [Tool]
1423+
1424+
/// An alternative to sampling with temperature, called nucleus sampling.
1425+
public let topP: Double?
1426+
1427+
/// The truncation strategy to use for the model response.
1428+
public let truncation: String?
1429+
1430+
/// Represents token usage details.
1431+
public let usage: Usage?
1432+
1433+
/// A unique identifier representing your end-user.
1434+
public let user: String?
1435+
}
1436+
```
1437+
1438+
Usage
1439+
1440+
Simple text input
1441+
```swift
1442+
let prompt = "What is the capital of France?"
1443+
let parameters = ModelResponseParameter(input: .string(prompt), model: .gpt4o)
1444+
let response = try await service.responseCreate(parameters)
1445+
```
1446+
1447+
Text input with reasoning
1448+
```swift
1449+
let prompt = "How much wood would a woodchuck chuck?"
1450+
let parameters = ModelResponseParameter(
1451+
input: .string(prompt),
1452+
model: .o3Mini,
1453+
reasoning: Reasoning(effort: "high")
1454+
)
1455+
let response = try await service.responseCreate(parameters)
1456+
```
1457+
1458+
Image input
1459+
```swift
1460+
let textPrompt = "What is in this image?"
1461+
let imageUrl = "https://example.com/path/to/image.jpg"
1462+
let imageContent = ContentItem.imageUrl(ImageUrlContent(imageUrl: imageUrl))
1463+
let textContent = ContentItem.text(TextContent(text: textPrompt))
1464+
let message = InputItem(role: "user", content: [textContent, imageContent])
1465+
let parameters = ModelResponseParameter(input: .array([message]), model: .gpt4o)
1466+
let response = try await service.responseCreate(parameters)
1467+
```
1468+
1469+
Using tools (web search)
1470+
```swift
1471+
let prompt = "What was a positive news story from today?"
1472+
let parameters = ModelResponseParameter(
1473+
input: .string(prompt),
1474+
model: .gpt4o,
1475+
tools: [Tool(type: "web_search_preview", function: nil)]
1476+
)
1477+
let response = try await service.responseCreate(parameters)
1478+
```
1479+
1480+
Using tools (file search)
1481+
```swift
1482+
let prompt = "What are the key points in the document?"
1483+
let parameters = ModelResponseParameter(
1484+
input: .string(prompt),
1485+
model: .gpt4o,
1486+
tools: [
1487+
Tool(
1488+
type: "file_search",
1489+
function: ChatCompletionParameters.ChatFunction(
1490+
name: "file_search",
1491+
strict: false,
1492+
description: "Search through files",
1493+
parameters: JSONSchema(
1494+
type: .object,
1495+
properties: [
1496+
"vector_store_ids": JSONSchema(
1497+
type: .array,
1498+
items: JSONSchema(type: .string)
1499+
),
1500+
"max_num_results": JSONSchema(type: .integer)
1501+
],
1502+
required: ["vector_store_ids"],
1503+
additionalProperties: false
1504+
)
1505+
)
1506+
)
1507+
]
1508+
)
1509+
let response = try await service.responseCreate(parameters)
1510+
```
1511+
1512+
Function calling
1513+
```swift
1514+
let prompt = "What is the weather like in Boston today?"
1515+
let parameters = ModelResponseParameter(
1516+
input: .string(prompt),
1517+
model: .gpt4o,
1518+
tools: [
1519+
Tool(
1520+
type: "function",
1521+
function: ChatCompletionParameters.ChatFunction(
1522+
name: "get_current_weather",
1523+
strict: false,
1524+
description: "Get the current weather in a given location",
1525+
parameters: JSONSchema(
1526+
type: .object,
1527+
properties: [
1528+
"location": JSONSchema(
1529+
type: .string,
1530+
description: "The city and state, e.g. San Francisco, CA"
1531+
),
1532+
"unit": JSONSchema(
1533+
type: .string,
1534+
enum: ["celsius", "fahrenheit"]
1535+
)
1536+
],
1537+
required: ["location", "unit"],
1538+
additionalProperties: false
1539+
)
1540+
)
1541+
)
1542+
],
1543+
toolChoice: .auto
1544+
)
1545+
let response = try await service.responseCreate(parameters)
1546+
```
1547+
1548+
Retrieving a response
1549+
```swift
1550+
let responseId = "resp_abc123"
1551+
let response = try await service.responseModel(id: responseId)
1552+
```
1553+
12631554
### Embeddings
12641555
Parameters
12651556
```swift

Sources/OpenAI/AIProxy/AIProxyService.swift

+20
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,26 @@ struct AIProxyService: OpenAIService {
823823
let request = try await OpenAIAPI.vectorStoreFileBatch(.list(vectorStoreID: vectorStoreID, batchID: batchID)).request(aiproxyPartialKey: partialKey, clientID: clientID, organizationID: organizationID, openAIEnvironment: openAIEnvironment, method: .get, queryItems: queryItems, betaHeaderField: Self.assistantsBetaV2)
824824
return try await fetch(debugEnabled: debugEnabled, type: OpenAIResponse<VectorStoreFileObject>.self, with: request)
825825
}
826+
827+
// MARK: Response
828+
829+
func responseCreate(
830+
_ parameters: ModelResponseParameter)
831+
async throws -> ResponseModel
832+
{
833+
var responseParameters = parameters
834+
responseParameters.stream = false
835+
let request = try await OpenAIAPI.chat.request(aiproxyPartialKey: partialKey, clientID: clientID, organizationID: organizationID, openAIEnvironment: openAIEnvironment, method: .post, params: responseParameters)
836+
return try await fetch(debugEnabled: debugEnabled, type: ResponseModel.self, with: request)
837+
}
838+
839+
func responseModel(
840+
id: String)
841+
async throws -> ResponseModel
842+
{
843+
let request = try await OpenAIAPI.chat.request(aiproxyPartialKey: partialKey, clientID: clientID, organizationID: organizationID, openAIEnvironment: openAIEnvironment, method: .post)
844+
return try await fetch(debugEnabled: debugEnabled, type: ResponseModel.self, with: request)
845+
}
826846
}
827847

828848

Sources/OpenAI/Azure/AzureOpenAIAPI.swift

+13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ enum AzureOpenAIAPI {
2929
/// https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/file-search?tabs=python#vector-stores
3030
case vectorStoreFile(VectorStoreFileCategory)
3131

32+
/// OpenAI's most advanced interface for generating model responses. Supports text and image inputs, and text outputs. Create stateful interactions with the model, using the output of previous responses as input. Extend the model's capabilities with built-in tools for file search, web search, computer use, and more. Allow the model access to external systems and data using function calling.
33+
case response(ResponseCategory) // https://platform.openai.com/docs/api-reference/responses
34+
3235
enum AssistantCategory {
3336
case create
3437
case list
@@ -82,6 +85,11 @@ enum AzureOpenAIAPI {
8285
case retrieve(vectorStoreID: String, fileID: String)
8386
case delete(vectorStoreID: String, fileID: String)
8487
}
88+
89+
enum ResponseCategory {
90+
case create(deploymentID: String)
91+
case retrieve(responseID: String)
92+
}
8593
}
8694

8795
// MARK: Endpoint
@@ -129,6 +137,11 @@ extension AzureOpenAIAPI: Endpoint {
129137
case .create(let vectorStoreID), .list(let vectorStoreID): return "/openai/vector_stores/\(vectorStoreID)/files"
130138
case .retrieve(let vectorStoreID, let fileID), .delete(let vectorStoreID, let fileID): return "/openai/vector_stores/\(vectorStoreID)/files/\(fileID)"
131139
}
140+
case .response(let category):
141+
switch category {
142+
case .create(let deploymentID): return "/openai/deployments/\(deploymentID)/responses"
143+
case .retrieve(let responseID): return "/openai/responses/\(responseID)"
144+
}
132145
}
133146
}
134147
}

0 commit comments

Comments
 (0)