weiqingy commented on code in PR #843:
URL: https://github.com/apache/flink-agents/pull/843#discussion_r3647346898


##########
api/src/main/java/org/apache/flink/agents/api/chat/model/BaseChatModelConnection.java:
##########
@@ -55,4 +77,33 @@ public ResourceType getResourceType() {
      */
     public abstract ChatMessage chat(
             List<ChatMessage> messages, List<Tool> tools, Map<String, Object> 
modelParams);
+
+    /**
+     * Process a chat request that carries an output schema, and return a chat 
response.
+     *
+     * <p>{@code outputSchema} is framework-level execution metadata, kept off 
{@code modelParams}
+     * so that it can never reach a provider SDK request as a generation 
parameter. It is either a
+     * POJO {@link Class} or an {@link 
org.apache.flink.agents.api.agents.OutputSchema} (a {@code
+     * RowTypeInfo} wrapper); the two cases are distinguished by the 
connection that consumes it.
+     *
+     * <p>This default implementation <b>ignores</b> {@code outputSchema} and 
delegates to {@link
+     * #chat(List, List, Map)}. Connections without a native structured-output 
translation inherit
+     * it unchanged and need no edits. A connection that does translate a 
schema into a native
+     * provider parameter overrides this overload, and reports its capability 
via {@link
+     * #supportsNativeStructuredOutput(String)}.
+     *
+     * @param messages the input chat messages
+     * @param tools the tools can be called by the model
+     * @param modelParams the additional arguments passed to the model
+     * @param outputSchema the schema the response should conform to, or null 
for an unconstrained
+     *     response
+     * @return the chat response containing model outputs
+     */
+    public ChatMessage chat(

Review Comment:
   Good question, and yes, nothing calls the four-argument `chat` in this PR.
   
   That is the scope here: the mechanism, with no framework path passing a 
schema yet. The setup-level overload is the point where the policy on the setup 
meets the connection-side capability, and where that resolution should live is 
still open. #912 lists it as an open question: "Where should `auto` resolve 
policy into a concrete strategy, given capability is a connection-side 
predicate over the effective model at request-build time?"
   
   #912 is also the consumer. It issues a dedicated structured call at 
`ChatModelAction`'s no-tool-calls branch, so it is the change that both needs 
the setup-level entry point and can actually exercise it. Adding the overload 
here would settle that open question with nothing able to validate the choice, 
and it has to move together with normalizing effective-model resolution across 
Java and Python.
   
   If you would rather see the complete path in one PR, I am happy to pull it 
forward here instead.



##########
api/src/main/java/org/apache/flink/agents/api/chat/model/BaseChatModelConnection.java:
##########
@@ -55,4 +77,33 @@ public ResourceType getResourceType() {
      */
     public abstract ChatMessage chat(
             List<ChatMessage> messages, List<Tool> tools, Map<String, Object> 
modelParams);
+
+    /**
+     * Process a chat request that carries an output schema, and return a chat 
response.
+     *
+     * <p>{@code outputSchema} is framework-level execution metadata, kept off 
{@code modelParams}
+     * so that it can never reach a provider SDK request as a generation 
parameter. It is either a
+     * POJO {@link Class} or an {@link 
org.apache.flink.agents.api.agents.OutputSchema} (a {@code
+     * RowTypeInfo} wrapper); the two cases are distinguished by the 
connection that consumes it.
+     *
+     * <p>This default implementation <b>ignores</b> {@code outputSchema} and 
delegates to {@link
+     * #chat(List, List, Map)}. Connections without a native structured-output 
translation inherit
+     * it unchanged and need no edits. A connection that does translate a 
schema into a native
+     * provider parameter overrides this overload, and reports its capability 
via {@link
+     * #supportsNativeStructuredOutput(String)}.
+     *
+     * @param messages the input chat messages
+     * @param tools the tools can be called by the model
+     * @param modelParams the additional arguments passed to the model
+     * @param outputSchema the schema the response should conform to, or null 
for an unconstrained
+     *     response
+     * @return the chat response containing model outputs
+     */
+    public ChatMessage chat(
+            List<ChatMessage> messages,
+            List<Tool> tools,
+            Map<String, Object> modelParams,
+            @Nullable Object outputSchema) {
+        return chat(messages, tools, modelParams);

Review Comment:
   Agreed, fixed in `aead976`.
   
   The default overload now throws `UnsupportedOperationException` for a 
non-null `outputSchema` and still delegates to the three-argument overload for 
null, so a connection that translates a schema overrides it and nothing changes 
for schemaless calls.
   
   Python needed a different shape for the same contract. `chat` is abstract 
there, so there is no inherited body that could refuse a schema. A guard on the 
connection base raises `NotImplementedError`, and every connection without a 
native translation calls it as the first statement of `chat`, before any client 
access. The connection subclass walk in `test_output_schema_param_declared.py` 
now asserts the rejection as well, so a connection added later is held to the 
same contract.
   
   One thing worth flagging since it is not visible from the diff: the throw 
has no production caller in either language yet, so it stays dormant until the 
native path lands. Java's only connection call is the three-argument one in 
`BaseChatModelSetup`, and on the Python side `chat_model_action.py` calls 
`chat` without a schema and applies the prompt fallback separately.



##########
python/flink_agents/api/chat_models/chat_model.py:
##########
@@ -153,6 +254,14 @@ class BaseChatModelSetup(Resource):
     skill_discovery_prompt: str | None = None
     allowed_commands: List[str] = Field(default_factory=list)
     allowed_script_dirs: List[str] = Field(default_factory=list)
+    structured_output_strategy: StructuredOutputStrategy = Field(

Review Comment:
   Good catch, fixed in `e537e4d`.
   
   Python now normalizes an explicit null to `AUTO`, matching Java. I went that 
direction rather than rejecting in both because Java cannot reject it: 
`getArgument` is a plain map lookup (`ResourceDescriptor.java:93-96`), so an 
absent key and an explicit null reach `fromArgument` identically, and rejecting 
the one would reject the other.
   
   Only null normalizes. An empty string, `0`, `False` and an unrecognized name 
all still raise, and the case-insensitive resolution of both the lowercase 
values and the Java enum names is unchanged.
   
   I also added the Java test for an explicitly null argument. The neighbouring 
strategy tests build their descriptors with `Map.of`, which rejects a null 
value, so that case could not be expressed there and the behavior this parity 
fix relies on was not pinned on the Java side.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to