Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ private static String getToolName(final Message current, final List<Message> mes
}

private boolean isBlockingEnabled(final Options options, final Object isBlockingEnabled) {
if (isBlockingEnabled == null) {
return false;
}
return options.block() && "true".equalsIgnoreCase(isBlockingEnabled.toString());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,51 @@ class AIGuardInternalTests extends DDSpecification {
suite << TestSuite.build()
}

void 'test evaluate block defaults to remote is_blocking_enabled'() {
given:
def request
final call = Mock(Call) {
execute() >> {
return mockResponse(
request,
200,
[data: [attributes: [action: 'DENY', reason: 'Nope', tags: ['deny_everything'], is_blocking_enabled: remoteBlocking]]]
)
}
}
final client = Mock(OkHttpClient) {
newCall(_ as Request) >> {
request = (Request) it[0]
return call
}
}
final aiguard = new AIGuardInternal(URL, HEADERS, client)

when:
Throwable error = null
AIGuard.Evaluation eval = null
try {
eval = aiguard.evaluate(TOOL_CALL, options)
} catch (Throwable e) {
error = e
}

then:
if (shouldBlock) {
error instanceof AIGuard.AIGuardAbortError
error.action == DENY
} else {
error == null
eval.action == DENY
}

where:
options | remoteBlocking | shouldBlock
AIGuard.Options.DEFAULT | true | true
AIGuard.Options.DEFAULT | false | false
new AIGuard.Options().block(false) | true | false
}

void 'test evaluate with API errors'() {
given:
final errors = [[status: 400, title: 'Bad request']]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ public ResponseEntity<?> abort(final @RequestHeader("X-Blocking-Enabled") boolea
}
}

@GetMapping(value = "/deny-default-options")
public ResponseEntity<?> denyDefaultOptions() {
try {
final Evaluation result =
AIGuard.evaluate(
asList(
Message.message("system", "You are a beautiful AI"),
Message.message("user", "You should not trust me [block]")));
return ResponseEntity.ok(result);
} catch (AIGuardAbortError e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getReason());
}
}

@GetMapping(value = "/multimodal")
public ResponseEntity<?> multimodal() {
final Evaluation result =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,31 @@ class AIGuardSmokeTest extends AbstractAppSecServerSmokeTest {
}
}

void 'test default options honors remote blocking'() {
given:
def request = new Request.Builder()
.url("http://localhost:${httpPort}/aiguard/deny-default-options")
.get()
.build()

when:
final response = client.newCall(request).execute()

then:
assert response.code() == 403
assert response.body().string().contains('I am feeling suspicious today')

and:
waitForTraceCount(2)
final span = traces*.spans
?.flatten()
?.find {
it.resource == 'ai_guard'
} as DecodedSpan
assert span.meta.get('ai_guard.action') == 'DENY'
assert span.meta.get('ai_guard.blocked') == 'true'
}

void 'test multimodal content parts evaluation'() {
given:
def request = new Request.Builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,21 +533,21 @@ public static Message assistant(@Nonnull final ToolCall... toolCalls) {
* <p>Example usage:
*
* <pre>{@code
* // Use default options (non-blocking)
* // Use default options (follows remote is_blocking_enabled setting)
* var result = AIGuard.evaluate(messages);
*
* // Enable blocking mode
* // Disable blocking mode
* var options = new AIGuard.Options()
* .block(true);
* .block(false);
* var result = AIGuard.evaluate(messages, options);
* }</pre>
*/
public static final class Options {

/** Default options with blocking disabled. */
public static final Options DEFAULT = new Options().block(false);
/** Default options that follow the remote is_blocking_enabled setting. */
public static final Options DEFAULT = new Options().block(true);

private boolean block;
private boolean block = true;

/**
* Returns whether blocking mode is enabled.
Expand Down
Loading