feat: Make Safety API an optional dependency for meta-reference agents provider (#4169)

# What does this PR do?

Change Safety API from required to optional dependency, following the
established pattern used for other optional dependencies in Llama Stack.
    
The provider now starts successfully without Safety API configured.
Requests that explicitly include guardrails will receive a clear error
message when Safety API is unavailable.
    
This enables local development and testing without Safety API while
maintaining clear error messages when guardrail features are requested.
    
Closes #4165
    
Signed-off-by: Anik Bhattacharjee <anbhatta@redhat.com>

## Test Plan
<!-- Describe the tests you ran to verify your changes with result
summaries. *Provide clear instructions so the plan can be easily
re-executed.* -->

1. New unit tests added in
`tests/unit/providers/agents/meta_reference/test_safety_optional.py`

2. Integration tests performed with the files in
https://gist.github.com/anik120/c33cef497ec7085e1fe2164e0705b8d6

 (i) test with `test_integration_no_safety_fail.yaml`:
 
Config WITHOUT Safety API, should fail with helpful error since
`required_safety_api` is `true` by default
```
$ uv run llama stack run test_integration_no_safety_fail.yaml 2>&1 | grep -B 5 -A 15 "ValueError.*Safety\|Safety API is 
  required"
File "/Users/anbhatta/go/src/github.com/llamastack/llama-stack/src/llama_stack/providers/inline/agents/meta_reference
  /__init__.py", line 27, in get_provider_impl
      raise ValueError(
      ...<9 lines>...
      )
  ValueError: Safety API is required but not configured.

  To run without safety checks, explicitly set in your configuration:
    providers:
      agents:
        - provider_id: meta-reference
          provider_type: inline::meta-reference
          config:
            require_safety_api: false

  Warning: This disables all safety guardrails for this agents provider.
```

(ii) test with `test_integration_no_safety_works.yaml`

Config WITHOUT Safety API, **but** `require_safety_api=false` is
explicitly set, should succeed

```
$ uv run llama stack run test_integration_no_safety_works.yaml
 INFO     2025-11-16 09:49:10,044 llama_stack.cli.stack.run:169 cli: Using run configuration:                           
   
           /Users/anbhatta/go/src/github.com/llamastack/llama-stack/test_integration_no_safety_works.yaml                
   
  INFO     2025-11-16 09:49:10,052 llama_stack.cli.stack.run:228 cli: HTTPS enabled with certificates:

             Key: None

             Cert: None

  .
  .
  .
  INFO     2025-11-16 09:49:38,528 llama_stack.core.stack:495 core: starting registry refresh task

  INFO     2025-11-16 09:49:38,534 uvicorn.error:62 uncategorized: Application startup complete.

  INFO     2025-11-16 09:49:38,535 uvicorn.error:216 uncategorized: Uvicorn running on http://0.0.0.0:8321 (Press CTRL+C
```


Signed-off-by: Anik Bhattacharjee <anbhatta@redhat.com>

Signed-off-by: Anik Bhattacharjee <anbhatta@redhat.com>
This commit is contained in:
Anik 2025-11-19 13:04:24 -05:00 committed by GitHub
parent d5cd0eea14
commit 4e9633f7c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 227 additions and 6 deletions

View file

@ -23,7 +23,7 @@ async def get_provider_impl(
config,
deps[Api.inference],
deps[Api.vector_io],
deps[Api.safety],
deps.get(Api.safety),
deps[Api.tool_runtime],
deps[Api.tool_groups],
deps[Api.conversations],

View file

@ -41,7 +41,7 @@ class MetaReferenceAgentsImpl(Agents):
config: MetaReferenceAgentsImplConfig,
inference_api: Inference,
vector_io_api: VectorIO,
safety_api: Safety,
safety_api: Safety | None,
tool_runtime_api: ToolRuntime,
tool_groups_api: ToolGroups,
conversations_api: Conversations,

View file

@ -67,7 +67,7 @@ class OpenAIResponsesImpl:
tool_runtime_api: ToolRuntime,
responses_store: ResponsesStore,
vector_io_api: VectorIO, # VectorIO
safety_api: Safety,
safety_api: Safety | None,
conversations_api: Conversations,
):
self.inference_api = inference_api
@ -273,6 +273,14 @@ class OpenAIResponsesImpl:
guardrail_ids = extract_guardrail_ids(guardrails) if guardrails else []
# Validate that Safety API is available if guardrails are requested
if guardrail_ids and self.safety_api is None:
raise ValueError(
"Cannot process guardrails: Safety API is not configured.\n\n"
"To use guardrails, ensure the Safety API is configured in your stack, or remove "
"the 'guardrails' parameter from your request."
)
if conversation is not None:
if previous_response_id is not None:
raise ValueError(

View file

@ -66,6 +66,7 @@ from llama_stack_api import (
OpenAIResponseUsage,
OpenAIResponseUsageInputTokensDetails,
OpenAIResponseUsageOutputTokensDetails,
Safety,
WebSearchToolTypes,
)
@ -111,7 +112,7 @@ class StreamingResponseOrchestrator:
max_infer_iters: int,
tool_executor, # Will be the tool execution logic from the main class
instructions: str | None,
safety_api,
safety_api: Safety | None,
guardrail_ids: list[str] | None = None,
prompt: OpenAIResponsePrompt | None = None,
parallel_tool_calls: bool | None = None,

View file

@ -320,11 +320,15 @@ def is_function_tool_call(
return False
async def run_guardrails(safety_api: Safety, messages: str, guardrail_ids: list[str]) -> str | None:
async def run_guardrails(safety_api: Safety | None, messages: str, guardrail_ids: list[str]) -> str | None:
"""Run guardrails against messages and return violation message if blocked."""
if not messages:
return None
# If safety API is not available, skip guardrails
if safety_api is None:
return None
# Look up shields to get their provider_resource_id (actual model ID)
model_ids = []
# TODO: list_shields not in Safety interface but available at runtime via API routing

View file

@ -30,12 +30,14 @@ def available_providers() -> list[ProviderSpec]:
config_class="llama_stack.providers.inline.agents.meta_reference.MetaReferenceAgentsImplConfig",
api_dependencies=[
Api.inference,
Api.safety,
Api.vector_io,
Api.tool_runtime,
Api.tool_groups,
Api.conversations,
],
optional_api_dependencies=[
Api.safety,
],
description="Meta's reference implementation of an agent system that can use tools, access vector databases, and perform complex reasoning tasks.",
),
]