mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix: pass workspace context to tool guard (#617)
This commit is contained in:
parent
dd7e561e48
commit
e88be95cd2
@ -483,6 +483,12 @@ public class ToolExecutionExecutor {
|
||||
ChatOrigin origin,
|
||||
Set<String> loadedSkills) {
|
||||
ChatOrigin safeOrigin = origin != null ? origin : ChatOrigin.EMPTY;
|
||||
if (isBlank(safeOrigin.conversationId()) && !isBlank(conversationId)) {
|
||||
safeOrigin = safeOrigin.withConversationId(conversationId);
|
||||
}
|
||||
if (isBlank(safeOrigin.workspaceBasePath()) && !isBlank(workspaceBasePath)) {
|
||||
safeOrigin = safeOrigin.withWorkspace(safeOrigin.workspaceId(), workspaceBasePath);
|
||||
}
|
||||
// Reset per-turn audit dedupe state. A retried denied tool inside the
|
||||
// same turn writes a single audit row; the set is repopulated by the
|
||||
// denial branch below.
|
||||
@ -1297,6 +1303,10 @@ public class ToolExecutionExecutor {
|
||||
return GuardDecision.allowed();
|
||||
}
|
||||
|
||||
private static boolean isBlank(String value) {
|
||||
return value == null || value.isBlank();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny an approval-required tool when the run is non-interactive (no human can
|
||||
* approve), returning an actionable message so the agent falls back to a
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
package vip.mate.agent.graph.executor;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.ai.chat.messages.AssistantMessage;
|
||||
import org.springframework.ai.chat.model.ToolContext;
|
||||
import org.springframework.ai.tool.ToolCallback;
|
||||
import org.springframework.ai.tool.definition.ToolDefinition;
|
||||
import org.springframework.ai.tool.metadata.ToolMetadata;
|
||||
import vip.mate.agent.AgentToolSet;
|
||||
import vip.mate.agent.context.ChatOrigin;
|
||||
import vip.mate.tool.guard.model.GuardEvaluation;
|
||||
import vip.mate.tool.guard.model.ToolInvocationContext;
|
||||
import vip.mate.tool.guard.service.ToolGuardService;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ToolExecutionExecutorWorkspaceGuardContextTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("guard evaluation receives state workspaceBasePath when origin has no base path (#617)")
|
||||
void guardUsesWorkspaceBasePathArgumentWhenOriginIsBlank(@TempDir Path workspaceRoot) {
|
||||
ToolGuardService guardService = mock(ToolGuardService.class);
|
||||
when(guardService.evaluate(any(ToolInvocationContext.class), eq(true)))
|
||||
.thenReturn(GuardEvaluation.allow("write_file"));
|
||||
ToolExecutionExecutor executor = new ToolExecutionExecutor(
|
||||
AgentToolSet.fromCallbacks(List.of(), List.of(stub("write_file"))),
|
||||
guardService,
|
||||
null,
|
||||
null);
|
||||
|
||||
executor.execute(
|
||||
List.of(new AssistantMessage.ToolCall(
|
||||
"call_1", "function", "write_file",
|
||||
"{\"filePath\":\"deck.md\",\"content\":\"# Deck\"}")),
|
||||
"conv-617",
|
||||
"agent-617",
|
||||
false,
|
||||
"alice",
|
||||
workspaceRoot.toString(),
|
||||
ChatOrigin.web("conv-617", "alice", 1L, null));
|
||||
|
||||
ArgumentCaptor<ToolInvocationContext> captor = ArgumentCaptor.forClass(ToolInvocationContext.class);
|
||||
verify(guardService).evaluate(captor.capture(), eq(true));
|
||||
assertThat(captor.getValue().workspaceBasePath()).isEqualTo(workspaceRoot.toString());
|
||||
}
|
||||
|
||||
private static ToolCallback stub(String name) {
|
||||
ToolDefinition def = ToolDefinition.builder()
|
||||
.name(name)
|
||||
.description("test tool " + name)
|
||||
.inputSchema("{\"type\":\"object\",\"properties\":{}}")
|
||||
.build();
|
||||
ToolMetadata md = ToolMetadata.builder().returnDirect(false).build();
|
||||
return new ToolCallback() {
|
||||
@Override public ToolDefinition getToolDefinition() { return def; }
|
||||
@Override public ToolMetadata getToolMetadata() { return md; }
|
||||
@Override public String call(String arguments) { return "ok"; }
|
||||
@Override public String call(String arguments, ToolContext toolContext) { return "ok"; }
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user