Skip to content

Commit aa6e1d7

Browse files
committed
Add prompt parameter support for stored prompts in Responses API
- Add ResponsePrompt class with Id, Version, and Variables properties - Add Prompt property to ResponseCreationOptions - Include proper JSON serialization/deserialization support - Add unit tests for serialization and deserialization - Add sync and async examples showing usage - Follows existing codebase patterns and conventions Resolves #500
1 parent b8d4d6d commit aa6e1d7

File tree

6 files changed

+240
-0
lines changed

6 files changed

+240
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using NUnit.Framework;
2+
using OpenAI.Responses;
3+
using System;
4+
5+
namespace OpenAI.Examples;
6+
7+
public partial class ResponseExamples
8+
{
9+
[Test]
10+
public void Example03_StoredPrompts()
11+
{
12+
OpenAIResponseClient client = new(model: "gpt-4o", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
13+
14+
// Create options using a stored prompt
15+
ResponseCreationOptions options = new()
16+
{
17+
Prompt = new ResponsePrompt
18+
{
19+
Id = "your-stored-prompt-id",
20+
Version = "v1.0"
21+
}
22+
};
23+
24+
// Add variables to substitute in the prompt template
25+
options.Prompt.Variables["location"] = "San Francisco";
26+
options.Prompt.Variables["unit"] = "celsius";
27+
28+
OpenAIResponse response = client.CreateResponse([], options);
29+
30+
Console.WriteLine($"[ASSISTANT]: {response.GetOutputText()}");
31+
}
32+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using NUnit.Framework;
2+
using OpenAI.Responses;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace OpenAI.Examples;
7+
8+
public partial class ResponseExamples
9+
{
10+
[Test]
11+
public async Task Example03_StoredPromptsAsync()
12+
{
13+
OpenAIResponseClient client = new(model: "gpt-4o", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
14+
15+
// Create options using a stored prompt
16+
ResponseCreationOptions options = new()
17+
{
18+
Prompt = new ResponsePrompt
19+
{
20+
Id = "your-stored-prompt-id",
21+
Version = "v1.0"
22+
}
23+
};
24+
25+
// Add variables to substitute in the prompt template
26+
options.Prompt.Variables["location"] = "San Francisco";
27+
options.Prompt.Variables["unit"] = "celsius";
28+
29+
OpenAIResponse response = await client.CreateResponseAsync([], options);
30+
31+
Console.WriteLine($"[ASSISTANT]: {response.GetOutputText()}");
32+
}
33+
}

src/Custom/Responses/ResponseCreationOptions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public partial class ResponseCreationOptions
2929
// CUSTOM: Made internal. This value comes from a parameter on the client method.
3030
internal bool? Stream { get; set; }
3131

32+
// CUSTOM: Added prompt parameter support for stored prompts.
33+
[CodeGenMember("Prompt")]
34+
public ResponsePrompt Prompt { get; set; }
35+
3236
// CUSTOM: Added public default constructor now that there are no required properties.
3337
public ResponseCreationOptions()
3438
{
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.ClientModel.Primitives;
3+
using System.Collections.Generic;
4+
using System.Text.Json;
5+
6+
namespace OpenAI.Responses;
7+
8+
public partial class ResponsePrompt : IJsonModel<ResponsePrompt>
9+
{
10+
void IJsonModel<ResponsePrompt>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
11+
=> CustomSerializationHelpers.SerializeInstance(this, SerializeResponsePrompt, writer, options);
12+
13+
ResponsePrompt IJsonModel<ResponsePrompt>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
14+
=> CustomSerializationHelpers.DeserializeNewInstance(this, DeserializeResponsePrompt, ref reader, options);
15+
16+
BinaryData IPersistableModel<ResponsePrompt>.Write(ModelReaderWriterOptions options)
17+
=> CustomSerializationHelpers.SerializeInstance(this, options);
18+
19+
ResponsePrompt IPersistableModel<ResponsePrompt>.Create(BinaryData data, ModelReaderWriterOptions options)
20+
=> CustomSerializationHelpers.DeserializeNewInstance(this, DeserializeResponsePrompt, data, options);
21+
22+
string IPersistableModel<ResponsePrompt>.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
23+
24+
internal static void SerializeResponsePrompt(ResponsePrompt instance, Utf8JsonWriter writer, ModelReaderWriterOptions options)
25+
{
26+
writer.WriteStartObject();
27+
28+
if (instance.Id != null)
29+
{
30+
writer.WritePropertyName("id");
31+
writer.WriteStringValue(instance.Id);
32+
}
33+
34+
if (instance.Version != null)
35+
{
36+
writer.WritePropertyName("version");
37+
writer.WriteStringValue(instance.Version);
38+
}
39+
40+
if (instance.Variables != null && instance.Variables.Count > 0)
41+
{
42+
writer.WritePropertyName("variables");
43+
writer.WriteStartObject();
44+
foreach (var variable in instance.Variables)
45+
{
46+
writer.WritePropertyName(variable.Key);
47+
JsonSerializer.Serialize(writer, variable.Value, options.Format == "W" ? null : (JsonSerializerOptions)null);
48+
}
49+
writer.WriteEndObject();
50+
}
51+
52+
writer.WriteEndObject();
53+
}
54+
55+
internal static ResponsePrompt DeserializeResponsePrompt(JsonElement element, ModelReaderWriterOptions options = null)
56+
{
57+
if (element.ValueKind == JsonValueKind.Null)
58+
{
59+
return null;
60+
}
61+
62+
string id = null;
63+
string version = null;
64+
Dictionary<string, object> variables = new Dictionary<string, object>();
65+
66+
foreach (var property in element.EnumerateObject())
67+
{
68+
if (property.NameEquals("id"))
69+
{
70+
id = property.Value.GetString();
71+
}
72+
else if (property.NameEquals("version"))
73+
{
74+
version = property.Value.GetString();
75+
}
76+
else if (property.NameEquals("variables"))
77+
{
78+
foreach (var variable in property.Value.EnumerateObject())
79+
{
80+
variables[variable.Name] = JsonSerializer.Deserialize<object>(variable.Value.GetRawText());
81+
}
82+
}
83+
}
84+
85+
var result = new ResponsePrompt();
86+
result.Id = id;
87+
result.Version = version;
88+
89+
if (variables.Count > 0)
90+
{
91+
foreach (var variable in variables)
92+
{
93+
result.Variables[variable.Key] = variable.Value;
94+
}
95+
}
96+
97+
return result;
98+
}
99+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Collections.Generic;
2+
3+
namespace OpenAI.Responses;
4+
5+
[CodeGenType("ResponsesPrompt")]
6+
public partial class ResponsePrompt
7+
{
8+
[CodeGenMember("Id")]
9+
public string Id { get; set; }
10+
11+
[CodeGenMember("Version")]
12+
public string Version { get; set; }
13+
14+
[CodeGenMember("Variables")]
15+
public IDictionary<string, object> Variables { get; }
16+
17+
public ResponsePrompt()
18+
{
19+
Variables = new Dictionary<string, object>();
20+
}
21+
}

tests/Responses/ResponsesTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,57 @@ ResponseToolChoice toolChoice
791791
"""),
792792
false);
793793

794+
[Test]
795+
public void ResponsePromptSerializationWorks()
796+
{
797+
ResponsePrompt prompt = new ResponsePrompt
798+
{
799+
Id = "test-prompt-id",
800+
Version = "v1.0"
801+
};
802+
prompt.Variables["location"] = "San Francisco";
803+
prompt.Variables["unit"] = "celsius";
804+
805+
string json = BinaryData.FromObjectAsJson(prompt).ToString();
806+
JsonDocument document = JsonDocument.Parse(json);
807+
808+
Assert.IsTrue(document.RootElement.TryGetProperty("id", out JsonElement idElement));
809+
Assert.AreEqual("test-prompt-id", idElement.GetString());
810+
811+
Assert.IsTrue(document.RootElement.TryGetProperty("version", out JsonElement versionElement));
812+
Assert.AreEqual("v1.0", versionElement.GetString());
813+
814+
Assert.IsTrue(document.RootElement.TryGetProperty("variables", out JsonElement variablesElement));
815+
Assert.IsTrue(variablesElement.TryGetProperty("location", out JsonElement locationElement));
816+
Assert.AreEqual("San Francisco", locationElement.GetString());
817+
818+
Assert.IsTrue(variablesElement.TryGetProperty("unit", out JsonElement unitElement));
819+
Assert.AreEqual("celsius", unitElement.GetString());
820+
}
821+
822+
[Test]
823+
public void ResponsePromptDeserializationWorks()
824+
{
825+
string json = """
826+
{
827+
"id": "test-prompt-id",
828+
"version": "v1.0",
829+
"variables": {
830+
"location": "San Francisco",
831+
"unit": "celsius"
832+
}
833+
}
834+
""";
835+
836+
ResponsePrompt prompt = BinaryData.FromString(json).ToObjectFromJson<ResponsePrompt>();
837+
838+
Assert.AreEqual("test-prompt-id", prompt.Id);
839+
Assert.AreEqual("v1.0", prompt.Version);
840+
Assert.AreEqual(2, prompt.Variables.Count);
841+
Assert.AreEqual("San Francisco", prompt.Variables["location"].ToString());
842+
Assert.AreEqual("celsius", prompt.Variables["unit"].ToString());
843+
}
844+
794845
private static OpenAIResponseClient GetTestClient(string overrideModel = null)
795846
=> GetTestClient<OpenAIResponseClient>(TestScenario.Responses, overrideModel);
796847
}

0 commit comments

Comments
 (0)