From 7d44edda2ff4f06d5a222985fbdbee1f6238b745 Mon Sep 17 00:00:00 2001 From: kaylieee Date: Mon, 16 Mar 2026 20:43:32 -0700 Subject: [PATCH 1/4] add sample --- .../CreateResponseWithStructuredInput.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java diff --git a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java new file mode 100644 index 000000000000..fa75055a12b0 --- /dev/null +++ b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.agents; + +import com.azure.ai.agents.implementation.OpenAIJsonHelper; +import com.azure.ai.agents.models.AgentReference; +import com.azure.ai.agents.models.AgentVersionDetails; +import com.azure.ai.agents.models.PromptAgentDefinition; +import com.azure.ai.agents.models.StructuredInputDefinition; +import com.azure.core.util.Configuration; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.openai.core.JsonValue; +import com.openai.models.responses.Response; +import com.openai.models.responses.ResponseCreateParams; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * This sample demonstrates how to create a response with structured inputs. + * Structured inputs are key-value pairs defined on an agent that get substituted + * into the agent's prompt template at runtime. + */ +public class CreateResponseWithStructuredInput { + public static void main(String[] args) { + String endpoint = Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT"); + String model = Configuration.getGlobalConfiguration().get("FOUNDRY_MODEL_DEPLOYMENT_NAME"); + + AgentsClientBuilder builder = new AgentsClientBuilder() + .credential(new DefaultAzureCredentialBuilder().build()) + .endpoint(endpoint) + .serviceVersion(AgentsServiceVersion.getLatest()); + + AgentsClient agentsClient = builder.buildAgentsClient(); + ResponsesClient responsesClient = builder.buildResponsesClient(); + + // Create an agent with structured input definitions + Map inputDefs = new LinkedHashMap<>(); + inputDefs.put("userName", new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + inputDefs.put("userRole", new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + + AgentVersionDetails agent = agentsClient.createAgentVersion("structured-input-agent", + new PromptAgentDefinition(model) + .setInstructions("You are a helpful assistant. " + + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.") + .setStructuredInputs(inputDefs)); + + // Create a response, passing structured input values + Map extraBody = new LinkedHashMap<>(); + extraBody.put("agent_reference", OpenAIJsonHelper.toJsonValue( + new AgentReference(agent.getName()).setVersion(agent.getVersion()))); + extraBody.put("structured_inputs", JsonValue.from( + Map.of("userName", "Alice Smith", "userRole", "Senior Developer"))); + + Response response = responsesClient.getResponseService().create( + ResponseCreateParams.builder() + .input("Hello! Can you confirm my details?") + .additionalBodyProperties(extraBody) + .build()); + + System.out.println("Response: " + response.output()); + + // Cleanup + agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion()); + } +} From f47a68dc9ae7365c5e1ca2e892de4231c5d32cc4 Mon Sep 17 00:00:00 2001 From: kaylieee Date: Mon, 16 Mar 2026 20:44:50 -0700 Subject: [PATCH 2/4] update env var --- .../com/azure/ai/agents/CreateResponseWithStructuredInput.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java index fa75055a12b0..52a3aa20812d 100644 --- a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java +++ b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java @@ -25,7 +25,7 @@ public class CreateResponseWithStructuredInput { public static void main(String[] args) { String endpoint = Configuration.getGlobalConfiguration().get("FOUNDRY_PROJECT_ENDPOINT"); - String model = Configuration.getGlobalConfiguration().get("FOUNDRY_MODEL_DEPLOYMENT_NAME"); + String model = Configuration.getGlobalConfiguration().get("FOUNDRY_MODEL_NAME"); AgentsClientBuilder builder = new AgentsClientBuilder() .credential(new DefaultAzureCredentialBuilder().build()) From 4e5a008c2d4dafa71c3f119be3e46672bfd11894 Mon Sep 17 00:00:00 2001 From: kaylieee Date: Mon, 16 Mar 2026 21:33:49 -0700 Subject: [PATCH 3/4] fixes from review --- .../CreateResponseWithStructuredInput.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java index 52a3aa20812d..f983075c2319 100644 --- a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java +++ b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java @@ -3,8 +3,6 @@ package com.azure.ai.agents; -import com.azure.ai.agents.implementation.OpenAIJsonHelper; -import com.azure.ai.agents.models.AgentReference; import com.azure.ai.agents.models.AgentVersionDetails; import com.azure.ai.agents.models.PromptAgentDefinition; import com.azure.ai.agents.models.StructuredInputDefinition; @@ -48,11 +46,18 @@ public static void main(String[] args) { .setStructuredInputs(inputDefs)); // Create a response, passing structured input values + Map agentRef = new LinkedHashMap<>(); + agentRef.put("type", "agent_reference"); + agentRef.put("name", agent.getName()); + agentRef.put("version", agent.getVersion()); + + Map structuredInputs = new LinkedHashMap<>(); + structuredInputs.put("userName", "Alice Smith"); + structuredInputs.put("userRole", "Senior Developer"); + Map extraBody = new LinkedHashMap<>(); - extraBody.put("agent_reference", OpenAIJsonHelper.toJsonValue( - new AgentReference(agent.getName()).setVersion(agent.getVersion()))); - extraBody.put("structured_inputs", JsonValue.from( - Map.of("userName", "Alice Smith", "userRole", "Senior Developer"))); + extraBody.put("agent_reference", JsonValue.from(agentRef)); + extraBody.put("structured_inputs", JsonValue.from(structuredInputs)); Response response = responsesClient.getResponseService().create( ResponseCreateParams.builder() From 7b442c3a4b4587cb92a2e40aa38cf137dcbfdcde Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Wed, 18 Mar 2026 01:56:39 +0100 Subject: [PATCH 4/4] `StructuredInputs` samples, tests, README updates (#48440) * Sync methods added and tests * Added async counterpart and test recordings * README updates * CHANGELOG updates --- sdk/ai/azure-ai-agents/CHANGELOG.md | 5 ++ sdk/ai/azure-ai-agents/README.md | 45 +++++++++++ sdk/ai/azure-ai-agents/assets.json | 2 +- .../azure/ai/agents/ResponsesAsyncClient.java | 75 +++++++++++++++++++ .../com/azure/ai/agents/ResponsesClient.java | 74 ++++++++++++++++++ .../CreateResponseWithStructuredInput.java | 41 +++++----- .../com/azure/ai/agents/AgentsAsyncTests.java | 58 +++++++++++++- .../java/com/azure/ai/agents/AgentsTests.java | 51 ++++++++++++- .../azure/ai/agents/StreamingAsyncTests.java | 65 ++++++++++++++++ .../com/azure/ai/agents/StreamingTests.java | 57 ++++++++++++++ 10 files changed, 447 insertions(+), 26 deletions(-) diff --git a/sdk/ai/azure-ai-agents/CHANGELOG.md b/sdk/ai/azure-ai-agents/CHANGELOG.md index 384fe0fe67a4..c4d2b8c93af7 100644 --- a/sdk/ai/azure-ai-agents/CHANGELOG.md +++ b/sdk/ai/azure-ai-agents/CHANGELOG.md @@ -16,6 +16,10 @@ - `createStreamingWithAgent` and `createStreamingWithAgentConversation` on `ResponsesAsyncClient` return `Flux` for asynchronous streaming. - Added `StreamingUtils` implementation helper that bridges OpenAI `StreamResponse` to `IterableStream` and `AsyncStreamResponse` to `Flux`. - Added streaming samples: `SimpleStreamingSync`/`SimpleStreamingAsync`, `FunctionCallStreamingSync`/`FunctionCallStreamingAsync`, and `CodeInterpreterStreamingSync`/`CodeInterpreterStreamingAsync`. +- Added structured input convenience methods to `ResponsesClient` and `ResponsesAsyncClient` for creating responses with agent-defined template parameters: + - `createWithAgentStructuredInput` accepts a `Map` of runtime values that are substituted into the agent's prompt template. + - `createStreamingWithAgentStructuredInput` provides the streaming equivalent, returning `IterableStream` (sync) or `Flux` (async). +- Added `CreateResponseWithStructuredInput` sample demonstrating how to define structured inputs on an agent and pass runtime values when creating a response. ### Breaking Changes @@ -33,6 +37,7 @@ - Added `ToolsTests` and `ToolsAsyncTests` with recorded end-to-end test coverage for OpenAPI, Code Interpreter, Function Call, Web Search, MCP, and File Search tools. - Added `StreamingTests` and `StreamingAsyncTests` with recorded test coverage for streaming responses (simple prompt, function calling, and Code Interpreter scenarios). +- Added structured input test coverage to `AgentsTests`, `AgentsAsyncTests`, `StreamingTests`, and `StreamingAsyncTests`. ## 2.0.0-beta.2 (2026-03-04) diff --git a/sdk/ai/azure-ai-agents/README.md b/sdk/ai/azure-ai-agents/README.md index b269f8955235..02b3eda657b9 100644 --- a/sdk/ai/azure-ai-agents/README.md +++ b/sdk/ai/azure-ai-agents/README.md @@ -623,6 +623,51 @@ See the full samples in [SimpleStreamingAsync.java](https://github.com/Azure/azu --- +### Structured inputs + +Structured inputs allow you to define named parameters on an agent that get substituted into its prompt template at runtime. This is useful when you want the same agent definition to handle different users or contexts by simply changing the input values. + +#### Define structured inputs on an agent + +When creating the agent, declare each structured input with a description and whether it is required. Use `{{inputName}}` placeholders in the instructions to reference them: + +```java com.azure.ai.agents.define_structured_inputs +// Create an agent with structured input definitions +Map structuredInputDefinitions = new LinkedHashMap<>(); +structuredInputDefinitions.put("userName", new StructuredInputDefinition().setDescription("User's name").setRequired(true)); +structuredInputDefinitions.put("userRole", new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + +AgentVersionDetails agent = agentsClient.createAgentVersion("structured-input-agent", + new PromptAgentDefinition(model) + .setInstructions("You are a helpful assistant. " + + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.") + .setStructuredInputs(structuredInputDefinitions)); +``` + +#### Create a response with structured input values + +When creating a response, pass a `Map` whose keys match the structured input names declared on the agent. The values are substituted into the prompt template before the model processes the request: + +```java com.azure.ai.agents.create_response_with_structured_input +// Create a response, passing structured input values that match the agent's definitions +Map structuredInputValues = new LinkedHashMap<>(); +structuredInputValues.put("userName", "Alice Smith"); +structuredInputValues.put("userRole", "Senior Developer"); + +Response response = responsesClient.createWithAgentStructuredInput( + new AgentReference(agent.getName()).setVersion(agent.getVersion()), + structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?") +); +``` + +Streaming is also supported via `createStreamingWithAgentStructuredInput`, which returns an `IterableStream` (sync) or `Flux` (async). + +See the full sample in [CreateResponseWithStructuredInput.java](https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java). + +--- + ### Service API versions The client library targets the latest service API version by default. diff --git a/sdk/ai/azure-ai-agents/assets.json b/sdk/ai/azure-ai-agents/assets.json index f30fca7a76ff..b7110f21c7ff 100644 --- a/sdk/ai/azure-ai-agents/assets.json +++ b/sdk/ai/azure-ai-agents/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/ai/azure-ai-agents", - "Tag": "java/ai/azure-ai-agents_4b3a190a4f" + "Tag": "java/ai/azure-ai-agents_bb4574aecb" } diff --git a/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesAsyncClient.java b/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesAsyncClient.java index 46847f198d95..12d4bafd5b9f 100644 --- a/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesAsyncClient.java +++ b/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesAsyncClient.java @@ -111,6 +111,44 @@ public Mono createWithAgent(AgentReference agentReference) { return createWithAgent(agentReference, new ResponseCreateParams.Builder()); } + /** + * Creates a response using structured input values that are substituted into the agent's prompt template + * at runtime. The keys in the {@code structuredInputs} map must match the structured input names declared + * on the agent's definition (via {@link com.azure.ai.agents.models.StructuredInputDefinition}), and the values should conform to the + * schema and type expectations defined there. + * + *

For example, if the agent was created with structured inputs {@code "userName"} and {@code "userRole"}, + * the map should contain the corresponding runtime values:

+ *
{@code
+     * Map structuredInputs = new LinkedHashMap<>();
+     * structuredInputs.put("userName", "Alice Smith");
+     * structuredInputs.put("userRole", "Senior Developer");
+     * }
+ * + * @param agentReference The agent reference. + * @param structuredInputs A map of structured input names to their runtime values. The values are + * serialized as JSON and must match the structure expected by the agent's definition. + * @param params The parameters to create the response. + * @return A Mono that emits the created Response. + */ + public Mono createWithAgentStructuredInput(AgentReference agentReference, + Map structuredInputs, ResponseCreateParams.Builder params) { + Objects.requireNonNull(agentReference, "agentReference cannot be null"); + Objects.requireNonNull(structuredInputs, "structuredInputs cannot be null"); + Objects.requireNonNull(params, "params cannot be null"); + + JsonValue agentRefJsonValue = OpenAIJsonHelper.toJsonValue(agentReference); + JsonValue structuredInputsJsonValue = JsonValue.from(structuredInputs); + + Map additionalBodyProperties = new HashMap<>(); + additionalBodyProperties.put("agent_reference", agentRefJsonValue); + additionalBodyProperties.put("structured_inputs", structuredInputsJsonValue); + + params.additionalBodyProperties(additionalBodyProperties); + + return Mono.fromFuture(this.responseServiceAsync.create(params.build())); + } + /** * Creates a streaming response with an agent. * @@ -132,6 +170,43 @@ public Flux createStreamingWithAgent(AgentReference agentRe return StreamingUtils.toFlux(this.responseServiceAsync.createStreaming(params.build())); } + /** + * Creates a streaming response using structured input values that are substituted into the agent's prompt + * template at runtime. The keys in the {@code structuredInputs} map must match the structured input names + * declared on the agent's definition (via {@link com.azure.ai.agents.models.StructuredInputDefinition}), and the values should conform + * to the schema and type expectations defined there. + * + *

For example, if the agent was created with structured inputs {@code "userName"} and {@code "userRole"}, + * the map should contain the corresponding runtime values:

+ *
{@code
+     * Map structuredInputs = new LinkedHashMap<>();
+     * structuredInputs.put("userName", "Alice Smith");
+     * structuredInputs.put("userRole", "Senior Developer");
+     * }
+ * + * @param agentReference The agent reference. + * @param structuredInputs A map of structured input names to their runtime values. The values are + * serialized as JSON and must match the structure expected by the agent's definition. + * @param params The parameters to create the response. + * @return A Flux of ResponseStreamEvent. + */ + public Flux createStreamingWithAgentStructuredInput(AgentReference agentReference, + Map structuredInputs, ResponseCreateParams.Builder params) { + Objects.requireNonNull(agentReference, "agentReference cannot be null"); + Objects.requireNonNull(structuredInputs, "structuredInputs cannot be null"); + Objects.requireNonNull(params, "params cannot be null"); + + JsonValue agentRefJsonValue = OpenAIJsonHelper.toJsonValue(agentReference); + JsonValue structuredInputsJsonValue = JsonValue.from(structuredInputs); + + Map additionalBodyProperties = new HashMap<>(); + additionalBodyProperties.put("agent_reference", agentRefJsonValue); + additionalBodyProperties.put("structured_inputs", structuredInputsJsonValue); + + params.additionalBodyProperties(additionalBodyProperties); + return StreamingUtils.toFlux(this.responseServiceAsync.createStreaming(params.build())); + } + /** * Creates a streaming response with an agent conversation. * diff --git a/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesClient.java b/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesClient.java index a93aa57e7109..b6f4609b284c 100644 --- a/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesClient.java +++ b/sdk/ai/azure-ai-agents/src/main/java/com/azure/ai/agents/ResponsesClient.java @@ -110,6 +110,43 @@ public Response createWithAgent(AgentReference agentReference) { return createWithAgent(agentReference, new ResponseCreateParams.Builder()); } + /** + * Creates a response using structured input values that are substituted into the agent's prompt template + * at runtime. The keys in the {@code structuredInputs} map must match the structured input names declared + * on the agent's definition (via {@link com.azure.ai.agents.models.StructuredInputDefinition}), and the values should conform to the + * schema and type expectations defined there. + * + *

For example, if the agent was created with structured inputs {@code "userName"} and {@code "userRole"}, + * the map should contain the corresponding runtime values:

+ *
{@code
+     * Map structuredInputs = new LinkedHashMap<>();
+     * structuredInputs.put("userName", "Alice Smith");
+     * structuredInputs.put("userRole", "Senior Developer");
+     * }
+ * + * @param agentReference The agent reference. + * @param structuredInputs A map of structured input names to their runtime values. The values are + * serialized as JSON and must match the structure expected by the agent's definition. + * @param params The parameters to create the response. + * @return The created Response. + */ + public Response createWithAgentStructuredInput(AgentReference agentReference, Map structuredInputs, + ResponseCreateParams.Builder params) { + Objects.requireNonNull(agentReference, "agentReference cannot be null"); + Objects.requireNonNull(structuredInputs, "structuredInputs cannot be null"); + + JsonValue agentRefJsonValue = OpenAIJsonHelper.toJsonValue(agentReference); + JsonValue structuredInputsJsonValue = JsonValue.from(structuredInputs); + + Map additionalBodyProperties = new HashMap<>(); + additionalBodyProperties.put("agent_reference", agentRefJsonValue); + additionalBodyProperties.put("structured_inputs", structuredInputsJsonValue); + + params.additionalBodyProperties(additionalBodyProperties); + + return this.responseService.create(params.build()); + } + /** * Creates a streaming response with an agent. * @@ -131,6 +168,43 @@ public IterableStream createStreamingWithAgent(AgentReferen return StreamingUtils.toIterableStream(this.responseService.createStreaming(params.build())); } + /** + * Creates a streaming response using structured input values that are substituted into the agent's prompt + * template at runtime. The keys in the {@code structuredInputs} map must match the structured input names + * declared on the agent's definition (via {@link com.azure.ai.agents.models.StructuredInputDefinition}), and the values should conform + * to the schema and type expectations defined there. + * + *

For example, if the agent was created with structured inputs {@code "userName"} and {@code "userRole"}, + * the map should contain the corresponding runtime values:

+ *
{@code
+     * Map structuredInputs = new LinkedHashMap<>();
+     * structuredInputs.put("userName", "Alice Smith");
+     * structuredInputs.put("userRole", "Senior Developer");
+     * }
+ * + * @param agentReference The agent reference. + * @param structuredInputs A map of structured input names to their runtime values. The values are + * serialized as JSON and must match the structure expected by the agent's definition. + * @param params The parameters to create the response. + * @return An IterableStream of ResponseStreamEvent. + */ + public IterableStream createStreamingWithAgentStructuredInput(AgentReference agentReference, + Map structuredInputs, ResponseCreateParams.Builder params) { + Objects.requireNonNull(agentReference, "agentReference cannot be null"); + Objects.requireNonNull(structuredInputs, "structuredInputs cannot be null"); + Objects.requireNonNull(params, "params cannot be null"); + + JsonValue agentRefJsonValue = OpenAIJsonHelper.toJsonValue(agentReference); + JsonValue structuredInputsJsonValue = JsonValue.from(structuredInputs); + + Map additionalBodyProperties = new HashMap<>(); + additionalBodyProperties.put("agent_reference", agentRefJsonValue); + additionalBodyProperties.put("structured_inputs", structuredInputsJsonValue); + + params.additionalBodyProperties(additionalBodyProperties); + return StreamingUtils.toIterableStream(this.responseService.createStreaming(params.build())); + } + /** * Creates a streaming response with an agent conversation. * diff --git a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java index f983075c2319..d44e3934d2d3 100644 --- a/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java +++ b/sdk/ai/azure-ai-agents/src/samples/java/com/azure/ai/agents/CreateResponseWithStructuredInput.java @@ -3,12 +3,12 @@ package com.azure.ai.agents; +import com.azure.ai.agents.models.AgentReference; import com.azure.ai.agents.models.AgentVersionDetails; import com.azure.ai.agents.models.PromptAgentDefinition; import com.azure.ai.agents.models.StructuredInputDefinition; import com.azure.core.util.Configuration; import com.azure.identity.DefaultAzureCredentialBuilder; -import com.openai.core.JsonValue; import com.openai.models.responses.Response; import com.openai.models.responses.ResponseCreateParams; @@ -33,37 +33,32 @@ public static void main(String[] args) { AgentsClient agentsClient = builder.buildAgentsClient(); ResponsesClient responsesClient = builder.buildResponsesClient(); + // BEGIN: com.azure.ai.agents.define_structured_inputs // Create an agent with structured input definitions - Map inputDefs = new LinkedHashMap<>(); - inputDefs.put("userName", new StructuredInputDefinition().setDescription("User's name").setRequired(true)); - inputDefs.put("userRole", new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + Map structuredInputDefinitions = new LinkedHashMap<>(); + structuredInputDefinitions.put("userName", new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + structuredInputDefinitions.put("userRole", new StructuredInputDefinition().setDescription("User's role").setRequired(true)); AgentVersionDetails agent = agentsClient.createAgentVersion("structured-input-agent", new PromptAgentDefinition(model) .setInstructions("You are a helpful assistant. " + "The user's name is {{userName}} and their role is {{userRole}}. " + "Greet them and confirm their details.") - .setStructuredInputs(inputDefs)); + .setStructuredInputs(structuredInputDefinitions)); + // END: com.azure.ai.agents.define_structured_inputs - // Create a response, passing structured input values - Map agentRef = new LinkedHashMap<>(); - agentRef.put("type", "agent_reference"); - agentRef.put("name", agent.getName()); - agentRef.put("version", agent.getVersion()); + // BEGIN: com.azure.ai.agents.create_response_with_structured_input + // Create a response, passing structured input values that match the agent's definitions + Map structuredInputValues = new LinkedHashMap<>(); + structuredInputValues.put("userName", "Alice Smith"); + structuredInputValues.put("userRole", "Senior Developer"); - Map structuredInputs = new LinkedHashMap<>(); - structuredInputs.put("userName", "Alice Smith"); - structuredInputs.put("userRole", "Senior Developer"); - - Map extraBody = new LinkedHashMap<>(); - extraBody.put("agent_reference", JsonValue.from(agentRef)); - extraBody.put("structured_inputs", JsonValue.from(structuredInputs)); - - Response response = responsesClient.getResponseService().create( - ResponseCreateParams.builder() - .input("Hello! Can you confirm my details?") - .additionalBodyProperties(extraBody) - .build()); + Response response = responsesClient.createWithAgentStructuredInput( + new AgentReference(agent.getName()).setVersion(agent.getVersion()), + structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?") + ); + // END: com.azure.ai.agents.create_response_with_structured_input System.out.println("Response: " + response.output()); diff --git a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsAsyncTests.java b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsAsyncTests.java index 6a83cd59fb78..ed6db87b68d2 100644 --- a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsAsyncTests.java +++ b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsAsyncTests.java @@ -5,6 +5,7 @@ import com.azure.ai.agents.models.AgentReference; import com.azure.ai.agents.models.PromptAgentDefinition; +import com.azure.ai.agents.models.StructuredInputDefinition; import com.azure.core.http.HttpClient; import com.openai.models.conversations.Conversation; import com.openai.models.responses.EasyInputMessage; @@ -18,10 +19,15 @@ import reactor.test.StepVerifier; import static com.azure.ai.agents.TestUtils.DISPLAY_NAME_WITH_ARGUMENTS; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class AgentsAsyncTests extends ClientTestBase { @@ -159,4 +165,54 @@ private Mono cleanupPromptAgentTest(AgentsAsyncClient agentsClient, // Deleting response causes a 500 in service, but keep the request for parity with sync tests. Mono.fromFuture(responsesClient.getResponseServiceAsync().delete(responseId)).then()); } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.agents.TestUtils#getTestParameters") + public void structuredInputTest(HttpClient httpClient, AgentsServiceVersion serviceVersion) { + AgentsAsyncClient agentsClient = getAgentsAsyncClient(httpClient, serviceVersion); + ResponsesAsyncClient responsesClient = getResponsesAsyncClient(httpClient, serviceVersion); + String agentModel = "gpt-4o"; + + // Create an agent with structured input definitions + Map structuredInputDefinitions = new LinkedHashMap<>(); + structuredInputDefinitions.put("userName", + new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + structuredInputDefinitions.put("userRole", + new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + + StepVerifier.create( + agentsClient + .createAgentVersion(AGENT_NAME, + new PromptAgentDefinition(agentModel).setInstructions("You are a helpful assistant. " + + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.").setStructuredInputs(structuredInputDefinitions)) + .flatMap(createdAgent -> { + assertNotNull(createdAgent); + assertNotNull(createdAgent.getId()); + assertEquals(AGENT_NAME, createdAgent.getName()); + + Map structuredInputValues = new LinkedHashMap<>(); + structuredInputValues.put("userName", "Alice Smith"); + structuredInputValues.put("userRole", "Senior Developer"); + + return responsesClient + .createWithAgentStructuredInput( + new AgentReference(createdAgent.getName()).setVersion(createdAgent.getVersion()), + structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?")) + .flatMap(response -> agentsClient + .deleteAgentVersion(createdAgent.getName(), createdAgent.getVersion()) + .thenReturn(response)); + })) + .assertNext(response -> { + assertNotNull(response); + assertTrue(response.id().startsWith("resp")); + assertTrue(response.status().isPresent()); + assertEquals(ResponseStatus.COMPLETED, response.status().get()); + assertFalse(response.output().isEmpty()); + assertTrue(response.output().get(0).isMessage()); + assertFalse(response.output().get(0).asMessage().content().isEmpty()); + }) + .verifyComplete(); + } } diff --git a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsTests.java b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsTests.java index f1599675af9a..2178934bd9f3 100644 --- a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsTests.java +++ b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/AgentsTests.java @@ -10,6 +10,7 @@ import com.azure.ai.agents.models.DeleteAgentResponse; import com.azure.ai.agents.models.DeleteAgentVersionResponse; import com.azure.ai.agents.models.PromptAgentDefinition; +import com.azure.ai.agents.models.StructuredInputDefinition; import com.azure.core.http.HttpClient; import com.openai.models.conversations.Conversation; import com.openai.models.responses.EasyInputMessage; @@ -21,7 +22,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import static com.azure.ai.agents.TestUtils.DISPLAY_NAME_WITH_ARGUMENTS; import static org.junit.jupiter.api.Assertions.*; @@ -205,4 +209,49 @@ public void promptAgentTest(HttpClient httpClient, AgentsServiceVersion serviceV // // Deleting response causes a 500 // // responsesClient.getOpenAIClient().delete(response.id()); // } + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.agents.TestUtils#getTestParameters") + public void structuredInputTest(HttpClient httpClient, AgentsServiceVersion serviceVersion) { + AgentsClient agentsClient = getAgentsSyncClient(httpClient, serviceVersion); + ResponsesClient responsesClient = getResponsesSyncClient(httpClient, serviceVersion); + String agentModel = "gpt-4o"; + + // Create an agent with structured input definitions + Map structuredInputDefinitions = new LinkedHashMap<>(); + structuredInputDefinitions.put("userName", + new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + structuredInputDefinitions.put("userRole", + new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + + AgentVersionDetails createdAgent = agentsClient.createAgentVersion(AGENT_NAME, + new PromptAgentDefinition(agentModel).setInstructions( + "You are a helpful assistant. " + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.") + .setStructuredInputs(structuredInputDefinitions)); + + assertNotNull(createdAgent); + assertNotNull(createdAgent.getId()); + assertEquals(AGENT_NAME, createdAgent.getName()); + + // Create a response, passing structured input values that match the agent's definitions + Map structuredInputValues = new LinkedHashMap<>(); + structuredInputValues.put("userName", "Alice Smith"); + structuredInputValues.put("userRole", "Senior Developer"); + + Response response = responsesClient.createWithAgentStructuredInput( + new AgentReference(createdAgent.getName()).setVersion(createdAgent.getVersion()), structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?")); + + assertNotNull(response); + assertTrue(response.id().startsWith("resp")); + assertTrue(response.status().isPresent()); + assertEquals(ResponseStatus.COMPLETED, response.status().get()); + assertFalse(response.output().isEmpty()); + assertTrue(response.output().get(0).isMessage()); + assertFalse(response.output().get(0).asMessage().content().isEmpty()); + + // Clean up + agentsClient.deleteAgentVersion(createdAgent.getName(), createdAgent.getVersion()); + } } diff --git a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingAsyncTests.java b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingAsyncTests.java index 1b70df8fdb09..08d65fcdf1fd 100644 --- a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingAsyncTests.java +++ b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingAsyncTests.java @@ -8,6 +8,7 @@ import com.azure.ai.agents.models.CodeInterpreterTool; import com.azure.ai.agents.models.FunctionTool; import com.azure.ai.agents.models.PromptAgentDefinition; +import com.azure.ai.agents.models.StructuredInputDefinition; import com.azure.core.http.HttpClient; import com.azure.core.util.BinaryData; import com.openai.helpers.ResponseAccumulator; @@ -204,6 +205,70 @@ public void codeInterpreterStreamingProducesCodeEvents(HttpClient httpClient, Ag .verifyComplete(); } + // ======================================================================== + // Structured input streaming + // ======================================================================== + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.agents.TestUtils#getTestParameters") + public void structuredInputStreamingProducesTextDeltas(HttpClient httpClient, AgentsServiceVersion serviceVersion) { + AgentsAsyncClient agentsClient = getAgentsAsyncClient(httpClient, serviceVersion); + ResponsesAsyncClient responsesClient = getResponsesAsyncClient(httpClient, serviceVersion); + + Map structuredInputDefinitions = new LinkedHashMap<>(); + structuredInputDefinitions.put("userName", + new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + structuredInputDefinitions.put("userRole", + new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + + AtomicReference agentRef = new AtomicReference<>(); + + StepVerifier + .create(agentsClient + .createAgentVersion("structured-input-streaming-async-test-agent", + new PromptAgentDefinition(AGENT_MODEL).setInstructions("You are a helpful assistant. " + + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.").setStructuredInputs(structuredInputDefinitions)) + .flatMap(agent -> { + agentRef.set(agent); + + AgentReference agentReference = new AgentReference(agent.getName()).setVersion(agent.getVersion()); + + Map structuredInputValues = new LinkedHashMap<>(); + structuredInputValues.put("userName", "Alice Smith"); + structuredInputValues.put("userRole", "Senior Developer"); + + ResponseAccumulator accumulator = ResponseAccumulator.create(); + List textDeltas = new ArrayList<>(); + + Flux events + = responsesClient.createStreamingWithAgentStructuredInput(agentReference, structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?")); + + return events.doOnNext(event -> { + accumulator.accumulate(event); + event.outputTextDelta().ifPresent(textEvent -> textDeltas.add(textEvent.delta())); + }).then(Mono.fromCallable(() -> { + assertFalse(textDeltas.isEmpty(), "Should have received at least one text delta"); + + Response response = accumulator.response(); + assertNotNull(response.id()); + assertTrue(response.status().isPresent()); + assertEquals(ResponseStatus.COMPLETED, response.status().get()); + + String streamedText = String.join("", textDeltas); + assertFalse(streamedText.isEmpty()); + return response; + })); + }) + .flatMap(response -> { + AgentVersionDetails agent = agentRef.get(); + return agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion()).thenReturn(response); + })) + .assertNext(response -> assertNotNull(response.id())) + .verifyComplete(); + } + // ======================================================================== // Helpers // ======================================================================== diff --git a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingTests.java b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingTests.java index d1aab10da950..055aabc93687 100644 --- a/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingTests.java +++ b/sdk/ai/azure-ai-agents/src/test/java/com/azure/ai/agents/StreamingTests.java @@ -8,6 +8,7 @@ import com.azure.ai.agents.models.CodeInterpreterTool; import com.azure.ai.agents.models.FunctionTool; import com.azure.ai.agents.models.PromptAgentDefinition; +import com.azure.ai.agents.models.StructuredInputDefinition; import com.azure.core.http.HttpClient; import com.azure.core.util.BinaryData; import com.azure.core.util.IterableStream; @@ -184,6 +185,62 @@ public void codeInterpreterStreamingProducesCodeEvents(HttpClient httpClient, Ag } } + // ======================================================================== + // Structured input streaming + // ======================================================================== + + @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) + @MethodSource("com.azure.ai.agents.TestUtils#getTestParameters") + public void structuredInputStreamingProducesTextDeltas(HttpClient httpClient, AgentsServiceVersion serviceVersion) { + AgentsClient agentsClient = getAgentsSyncClient(httpClient, serviceVersion); + ResponsesClient responsesClient = getResponsesSyncClient(httpClient, serviceVersion); + + // Create an agent with structured input definitions + Map structuredInputDefinitions = new LinkedHashMap<>(); + structuredInputDefinitions.put("userName", + new StructuredInputDefinition().setDescription("User's name").setRequired(true)); + structuredInputDefinitions.put("userRole", + new StructuredInputDefinition().setDescription("User's role").setRequired(true)); + + AgentVersionDetails agent = agentsClient.createAgentVersion("structured-input-streaming-test-agent", + new PromptAgentDefinition(AGENT_MODEL).setInstructions( + "You are a helpful assistant. " + "The user's name is {{userName}} and their role is {{userRole}}. " + + "Greet them and confirm their details.") + .setStructuredInputs(structuredInputDefinitions)); + + try { + AgentReference agentReference = new AgentReference(agent.getName()).setVersion(agent.getVersion()); + + Map structuredInputValues = new LinkedHashMap<>(); + structuredInputValues.put("userName", "Alice Smith"); + structuredInputValues.put("userRole", "Senior Developer"); + + ResponseAccumulator accumulator = ResponseAccumulator.create(); + List textDeltas = new ArrayList<>(); + + IterableStream events + = responsesClient.createStreamingWithAgentStructuredInput(agentReference, structuredInputValues, + ResponseCreateParams.builder().input("Hello! Can you confirm my details?")); + + for (ResponseStreamEvent event : events) { + accumulator.accumulate(event); + event.outputTextDelta().ifPresent(textEvent -> textDeltas.add(textEvent.delta())); + } + + assertFalse(textDeltas.isEmpty(), "Should have received at least one text delta"); + + Response response = accumulator.response(); + assertNotNull(response.id()); + assertTrue(response.status().isPresent()); + assertEquals(ResponseStatus.COMPLETED, response.status().get()); + + String streamedText = String.join("", textDeltas); + assertFalse(streamedText.isEmpty()); + } finally { + agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion()); + } + } + // ======================================================================== // Helpers // ========================================================================