Skip to content

feat: permission-aware tool calling + progress display#3

Merged
Sj295 merged 1 commit into
mainfrom
feat/streaming-permission-progress
Jul 17, 2026
Merged

feat: permission-aware tool calling + progress display#3
Sj295 merged 1 commit into
mainfrom
feat/streaming-permission-progress

Conversation

@Sj295

@Sj295 Sj295 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Adds two features that make the agent more usable:

1. Permission-aware tool calling

  • ToolCallbackAdapter gains an optional PermissionChecker interface
  • Checked before tool.call() -- deny returns isError:true JSON without executing the tool
  • Checker exceptions fail-open (logged but not blocking)
  • AppConfiguration wires PermissionCheckerImpl into the adapter via @lazy injection
  • Deny rules in settings.json now actually block tool execution in the Spring AI tool-calling loop

2. Tool execution progress display

  • AgentInvoker gains ToolProgressCallback interface (onStart/onComplete/onError)
  • ClaudeCodeJavaApplication registers a callback showing spinner during agent processing
  • Spinner is cleared on completion/error

Test Results

  • 256 tests pass (252 existing + 4 new)
  • New PermissionAwareAdapterTest: verifies deny blocks execution, allow permits, checker exception fails-open

Note on streaming

Spring AI 2.0.0's ToolCallAdvisor.adviseStream is unimplemented (throws UnsupportedOperationException). True token-by-token streaming would require either removing ToolCallAdvisor (losing advisor-level tool interception) or implementing a custom streaming-capable advisor. For now, the progress spinner provides user feedback during the blocking .call() path which correctly handles the tool-calling loop.

Copilot AI review requested due to automatic review settings July 17, 2026 10:49
@Sj295
Sj295 merged commit a745d1e into main Jul 17, 2026
1 check passed
@Sj295
Sj295 deleted the feat/streaming-permission-progress branch July 17, 2026 10:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the REPL agent experience by (1) enforcing permission rules before tools execute inside Spring AI’s tool-calling loop, and (2) providing a simple progress indicator during blocking agent invocation.

Changes:

  • Add an optional permission-check callback to ToolCallbackAdapter and wire it from AppConfiguration so deny rules can block tool execution.
  • Introduce AgentInvoker.ToolProgressCallback and register a REPL spinner callback in ClaudeCodeJavaApplication.
  • Add a new unit test verifying allow/deny/fail-open behavior for the adapter’s permission checker.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ccc-tools/src/main/java/com/ccj/tools/adapter/ToolCallbackAdapter.java Adds optional permission-check hook before delegating to tool.call(...).
ccc-test/src/test/java/com/ccj/test/PermissionAwareAdapterTest.java Adds tests covering permission-check allow/deny and checker exception behavior.
ccc-app/src/main/java/com/ccj/app/invoker/AgentInvoker.java Adds tool progress callback wiring around the blocking .call() path.
ccc-app/src/main/java/com/ccj/app/ClaudeCodeJavaApplication.java Registers a terminal spinner callback for agent processing.
ccc-app/src/main/java/com/ccj/app/AppConfiguration.java Wires PermissionCheckerImpl into tool callbacks (permission-aware tool execution).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 11 to +12
import java.util.Optional;
import java.util.function.Consumer;
Comment on lines +99 to +108
com.ccj.core.tool.PermissionResult result = permissionChecker.check(tool, input, ctx);
if (result instanceof com.ccj.core.tool.PermissionResult.Deny d) {
return d.message();
}
// Allow 和 Ask 都放行(Ask 在 REPL 层处理,此处简化为允许)
return null;
} catch (Exception e) {
log.warn("Permission check failed for {}: {}", tool.name(), e.getMessage());
return null; // 出错时允许(fail-open)
}
Comment on lines +38 to +40
/** 权限检查器接口(可选)。设置后在每次工具调用前检查权限。 */
@FunctionalInterface
public interface PermissionChecker {
Comment on lines +52 to 56
public ToolCallbackAdapter(Tool tool, ToolUseContext contextTemplate, PermissionChecker permissionChecker) {
this.tool = tool;
this.contextTemplate = contextTemplate;
this.permissionChecker = permissionChecker;
}
}
} catch (Exception e) {
// 权限检查器异常:fail-open(记录但不阻断)
log.warn("Permission checker exception for {}: {}", tool.name(), e.getMessage());
Sj295 added a commit that referenced this pull request Jul 17, 2026
fix: address all Copilot review issues (PR #1, #2, #3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants