Repository navigation
fix(core): add ToolUseBlock.getSuggestedRules() implementation #2916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c76e425
c5e3d05
3ca4fca
e9e9288
47dc241
0d56921
6188142
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,8 +18,11 @@ | |
| import com.fasterxml.jackson.annotation.JsonCreator; | ||
| import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import io.agentscope.core.permission.PermissionRule; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
|
|
@@ -51,6 +54,7 @@ public final class ToolUseBlock extends ContentBlock { | |
| private final String content; // Raw content for streaming tool calls | ||
| private final Map<String, Object> metadata; // Provider-specific metadata | ||
| private final ToolCallState state; | ||
| private final List<PermissionRule> suggestedRules; // Rules suggested when gated by ASK | ||
|
|
||
| /** | ||
| * Creates a new tool use block with metadata (convenience constructor). | ||
|
|
@@ -62,7 +66,7 @@ public final class ToolUseBlock extends ContentBlock { | |
| */ | ||
| public ToolUseBlock( | ||
| String id, String name, Map<String, Object> input, Map<String, Object> metadata) { | ||
| this(id, name, input, null, metadata, null); | ||
| this(id, name, input, null, metadata, null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -73,7 +77,7 @@ public ToolUseBlock( | |
| * @param input Input parameters for the tool (will be defensively copied) | ||
| */ | ||
| public ToolUseBlock(String id, String name, Map<String, Object> input) { | ||
| this(id, name, input, null, null, null); | ||
| this(id, name, input, null, null, null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -91,7 +95,7 @@ public ToolUseBlock( | |
| Map<String, Object> input, | ||
| String content, | ||
| Map<String, Object> metadata) { | ||
| this(id, name, input, content, metadata, null); | ||
| this(id, name, input, content, metadata, null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -104,14 +108,36 @@ public ToolUseBlock( | |
| * @param metadata Provider-specific metadata (will be defensively copied) | ||
| * @param state The tool call state, defaults to PENDING if null | ||
| */ | ||
| public ToolUseBlock( | ||
| String id, | ||
| String name, | ||
| Map<String, Object> input, | ||
| String content, | ||
| Map<String, Object> metadata, | ||
| ToolCallState state) { | ||
| this(id, name, input, content, metadata, state, null); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new tool use block with all fields. | ||
| * | ||
| * @param id Unique identifier for this tool call | ||
| * @param name Name of the tool to execute | ||
| * @param input Input parameters for the tool (will be defensively copied) | ||
| * @param content Raw content for streaming tool calls | ||
| * @param metadata Provider-specific metadata (will be defensively copied) | ||
| * @param state The tool call state, defaults to PENDING if null | ||
| * @param suggestedRules Permission rules suggested for this call (will be defensively copied) | ||
| */ | ||
| @JsonCreator | ||
| public ToolUseBlock( | ||
| @JsonProperty("id") String id, | ||
| @JsonProperty("name") String name, | ||
| @JsonProperty("input") Map<String, Object> input, | ||
| @JsonProperty("content") String content, | ||
| @JsonProperty("metadata") Map<String, Object> metadata, | ||
| @JsonProperty("state") ToolCallState state) { | ||
| @JsonProperty("state") ToolCallState state, | ||
| @JsonProperty("suggested_rules") List<PermissionRule> suggestedRules) { | ||
| this.id = id; | ||
| this.name = name; | ||
| // Defensive copy to prevent external modifications | ||
|
|
@@ -125,6 +151,10 @@ public ToolUseBlock( | |
| ? Collections.emptyMap() | ||
| : Collections.unmodifiableMap(new HashMap<>(metadata)); | ||
| this.state = state != null ? state : ToolCallState.PENDING; | ||
| this.suggestedRules = | ||
| suggestedRules == null | ||
| ? Collections.emptyList() | ||
| : Collections.unmodifiableList(new ArrayList<>(suggestedRules)); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -184,6 +214,23 @@ public ToolCallState getState() { | |
| return state; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the permission rules suggested for this tool call. | ||
| * | ||
| * <p>Populated when the permission engine gates this call with | ||
| * {@link io.agentscope.core.permission.PermissionBehavior#ASK}: the owning tool derives | ||
| * candidate rules from the actual invocation via | ||
| * {@link io.agentscope.core.tool.ToolBase#generateSuggestions}. Passing them back in a | ||
| * {@code ConfirmResult} registers them with the engine, so future matching calls resolve | ||
| * without another prompt. | ||
| * | ||
| * @return The suggested rules, or an empty list when none were suggested | ||
| */ | ||
| @JsonProperty("suggested_rules") | ||
| public List<PermissionRule> getSuggestedRules() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two small things: (1) the name |
||
| return suggestedRules; | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether this tool call is executed by the provider on the server side (marked via | ||
| * {@link #METADATA_SERVER_TOOL}). | ||
|
|
@@ -202,7 +249,43 @@ public boolean isServerTool() { | |
| * @return A new ToolUseBlock with the updated state | ||
| */ | ||
| public ToolUseBlock withState(ToolCallState state) { | ||
| return new ToolUseBlock(this.id, this.name, this.input, this.content, this.metadata, state); | ||
| return new ToolUseBlock( | ||
| this.id, | ||
| this.name, | ||
| this.input, | ||
| this.content, | ||
| this.metadata, | ||
| state, | ||
| this.suggestedRules); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a copy of this block with the given suggested rules. | ||
| * | ||
| * @param suggestedRules The suggested permission rules | ||
| * @return A new ToolUseBlock with the updated suggested rules | ||
| */ | ||
| public ToolUseBlock withSuggestedRules(List<PermissionRule> suggestedRules) { | ||
| return new ToolUseBlock( | ||
| this.id, | ||
| this.name, | ||
| this.input, | ||
| this.content, | ||
| this.metadata, | ||
| this.state, | ||
| suggestedRules); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a copy of this block with the given suggested rules. | ||
| * @param state The new state | ||
| * @param suggestedRules The suggested permission rules | ||
| * @return A new ToolUseBlock with the updated suggested rules and state | ||
| */ | ||
| public ToolUseBlock withStateAndSuggestedRules( | ||
| ToolCallState state, List<PermissionRule> suggestedRules) { | ||
| return new ToolUseBlock( | ||
| this.id, this.name, this.input, this.content, this.metadata, state, suggestedRules); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -224,6 +307,7 @@ public static class Builder { | |
| private String content; | ||
| private Map<String, Object> metadata; | ||
| private ToolCallState state; | ||
| private List<PermissionRule> suggestedRules; | ||
|
|
||
| /** | ||
| * Sets the unique identifier for the tool call. | ||
|
|
@@ -294,13 +378,24 @@ public Builder state(ToolCallState state) { | |
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the permission rules suggested for this tool call. | ||
| * | ||
| * @param suggestedRules The suggested permission rules | ||
| * @return This builder for chaining | ||
| */ | ||
| public Builder suggestedRules(List<PermissionRule> suggestedRules) { | ||
| this.suggestedRules = suggestedRules; | ||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Builds a new ToolUseBlock with the configured properties. | ||
| * | ||
| * @return A new ToolUseBlock instance | ||
| */ | ||
| public ToolUseBlock build() { | ||
| return new ToolUseBlock(id, name, input, content, metadata, state); | ||
| return new ToolUseBlock(id, name, input, content, metadata, state, suggestedRules); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Collectors.toMapthrows NPE when the value mapper returns null. TodayToolUseBlock#getSuggestedRulesnormalises null to an empty list so this is safe, but it is only safe because of a guarantee one class away — an explicit loop (orObjects.requireNonNullElseGet) keeps this from breaking if a legacy/deserialized block ever yields null.