eemario opened a new pull request, #1206:
URL: https://github.com/apache/flink-agents/pull/1206

   <!--
   * Thank you very much for contributing to Flink Agents.
   * Please add the relevant components in the PR title. E.g., [api], 
[runtime], [java], [python], [hotfix], etc.
   -->
   
   <!-- Please link the PR to the relevant issue(s). Hotfix doesn't need this. 
-->
   Linked issue: #1139
   
   ### Purpose of change
   
   A ReActAgent instance can now be registered directly as an `AGENT` resource 
and runs as an in-process internal sub-agent. The caller resolves it with 
`ctx.get_resource(name, ResourceType.AGENT)`, calls `submit(ctx, input)`, and 
awaits a Result holding the child's accumulated output; alternatively the 
parent's chat model calls it as a `_subagent_` tool, driven by the agent's 
declared description and input schema. Java and Python are at parity.
   
   The preceding internal sub-agent work runs an arbitrary registered Agent as 
a child but carries no metadata a parent model could use to delegate to it, its 
Python caller path had not been exercised end to end, and a child running its 
own reasoning/tool loop could not read back its first round inside the isolated 
memory view. This change closes those three gaps.
   
   #### Runtime flow
   
   1. **Input normalization.** ReActAgent's start action accepts a String 
(bound to the declared input key), a Map/dict whose single key equals the input 
key (the value becomes the user message), or the existing Row/POJO forms.
   2. **Metadata declaration.** ReActAgent implements 
`SubagentMetadataProvider` (Java interface / Python mixin) exposing a 
`(description, input_schema, input key)` triple with overridable defaults. The 
AGENT-resource compilation point in AgentPlan serializes the triple into the 
child's InternalSubagentSetup, symmetrically in both languages.
   3. **Invocation.** Caller-driven `submit`/`await` and model-driven 
`_subagent_<name>` tool calls both funnel into the existing internal sub-agent 
envelope; the child's framework-driven loop (chat_model_action / 
tool_call_action) runs inside the child scope with isolated memory, and the 
child's OutputEvents accumulate into the caller's Result.
   4. **Isolated memory view per call.** The child's memory view is created 
once per sub-agent call and shared by every action task of that call; the 
isolated store keeps its own writes for the call's lifetime (they never reach 
the caller's persistent state), so a multi-round reasoning/tool loop reads back 
its own earlier rounds.
   
   #### Key decisions
   
   - Metadata is read through the `SubagentMetadataProvider` capability 
interface rather than `instanceof ReActAgent` — any agent type can declare 
sub-agent metadata, and neither the plan nor the runtime layer depends on the 
concrete ReActAgent class.
   - Overridable defaults instead of required fields: caller-driven use needs 
no description or input schema, while model-driven delegation should override 
them; defaults do not soften any fail-fast validation.
   - The per-call memory view (replacing the per-action-task view) keeps the 
isolation contract: child writes die with the call and are excluded from the 
caller's persistent state, which is what makes sharing them across the loop 
safe.
   
   
   ### Behavioral Semantics
   
   #### Interaction decisions
   
   | | caller-driven | model-driven |
   |---|---|---|
   | String input | bound to the input key, becomes the user message | not 
applicable (the model supplies Map arguments) |
   | Map input, single key = input key | value becomes the user message | the 
shape the delegation path constructs |
   | Child registers its own tools | multi-round loop stays inside the child 
scope | same, tool schemas offered to the child's model |
   | No metadata declared | works with defaults | `_subagent_` tool carries 
empty schema; callers should override |
   
   #### Behavioral contracts
   
   - A caller-driven ReActAgent child runs its full reasoning/tool loop inside 
the child scope, and the caller's Result holds the child's final answer text.
   - A child carrying its own tools completes a multi-round loop: round N's 
tool results are readable in round N+1, the tool schemas offered to the child's 
model are exactly the child's registered tools, and tool results enter the 
conversation as TOOL-role messages.
   - A model-driven delegation exposes the declared description and input 
schema as the `_subagent_` tool schema, and the child receives the model's 
arguments as its input.
   - A failing child is reported through `Result.error` and the job proceeds.
   
   #### Failure behavior
   
   - A Map input with no prompt whose keys do not match the input-key form 
raises, as before — other Map shapes remain explicitly unsupported.
   - A child action failure surfaces as `SubagentResult.error` in the caller's 
Result (existing semantics, now covered end to end).
   - The child's memory view is per call and is not persisted across 
checkpoints; recovering an in-flight call replays the parent action per the 
existing recovery semantics, and persisting child-scope memory remains an open 
design question.
   
   ### Tests
   
   | Contract | Tests |
   |---|---|
   | Caller-driven child accumulates its loop output | 
`ReActAgentSubagentTest#callerDrivenCallRunsTheReActLoopInsideTheChildScope`; 
`test_caller_driven_react_subagent` |
   | Model-driven delegation routes to the child and closes the loop | 
`ReActAgentSubagentTest#modelDrivenDelegationRoutesToTheBareChildAndClosesTheLoop`;
 `test_model_driven_react_subagent_delegation` |
   | Child tool loop reads its own writes; schemas and TOOL messages as 
declared | `ReActAgentSubagentTest#toolCallLoopRunsInsideTheChildScope`; 
`test_child_tool_call_loop_runs_inside_the_child_scope` |
   | Existing internal sub-agent behavior unchanged (echo/failure/nested/relay) 
| `InternalSubagentCallTest` (4 tests); Python `internal_subagent_test.py` (3 
tests) |
   
   Coverage by risk: the memory-lifecycle change is pinned end to end in both 
languages by the tool-loop tests, which fail without it; the metadata plumbing 
is exercised by the model-driven tests reading real tool schemas. 
   **Not verified:** cross-language invocation (Java caller → Python-compiled 
child and vice versa — a separate tracked task); recovery of an in-flight 
child's memory across checkpoints (open design question, stated above); 
model-side schema violations (only the happy delegation path is e2e'd).
   
   
   ### API
   
   - New public surface: `SubagentMetadataProvider` (Java interface, Python 
mixin); ReActAgent constructors gain optional `description` / `input_schema` 
parameters in both languages.
   - Behavioral addition: the ReActAgent start action now accepts String and 
single-key-Map inputs where it previously raised for both; existing 
Row/POJO/prompt behavior is unchanged.
   - Internal sub-agent runtime change: the child memory view moved from 
per-action-task to per-call and the isolated store no longer discards its own 
writes on persist. Single-round children (all previously existing tests) cannot 
observe the difference — their writes die with the call either way. The Python 
caller-path config lookup bug fix changes no root-level behavior.
   - Unchanged: external SubagentSetup delegation, YAML-descriptor agents, and 
all previously existing internal sub-agent behavior.
   
   
   ### Documentation
   
   <!-- Do not remove this section. Check the proper box only. -->
   
   - [ ] `doc-needed` <!-- Your PR changes impact docs -->
   - [ ] `doc-not-needed` <!-- Your PR changes do not impact docs -->
   - [x] `doc-included` <!-- Your PR already contains the necessary 
documentation updates -->
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   <!-- Do not remove this section. Check the proper box only. -->
   
   - [x] Yes
   - [ ] No
   
   Generated-by: Qoder


-- 
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