Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into add-ag2-submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
davorrunje committed Dec 2, 2024
2 parents d2afdb9 + e0ce500 commit 750da19
Show file tree
Hide file tree
Showing 97 changed files with 2,232 additions and 154 deletions.
9 changes: 6 additions & 3 deletions docs/docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ search:
- [FastAPI + Nats.io](user-guide/adapters/fastapi_nats/index.md)
- [FastAPI Security](user-guide/adapters/fastapi/security.md)
- [API-s](user-guide/api/index.md)
- [Dependency Injection](user-guide/api/dependency_injection/index.md)
- [OpenAPI](user-guide/api/openapi/index.md)
- [Security](user-guide/api/security.md)
- [Testing](user-guide/testing/index.md)
Expand Down Expand Up @@ -59,14 +60,16 @@ search:
- [NatsAdapter](api/fastagency/adapters/nats/base/NatsAdapter.md)
- [NatsProvider](api/fastagency/adapters/nats/base/NatsProvider.md)
- api
- dependency_injection
- [inject_params](api/fastagency/api/dependency_injection/inject_params.md)
- openapi
- [OpenAPI](api/fastagency/api/openapi/OpenAPI.md)
- client
- [OpenAPI](api/fastagency/api/openapi/client/OpenAPI.md)
- [add_to_globals](api/fastagency/api/openapi/client/add_to_globals.md)
- fastapi_code_generator_helpers
- [ArgumentWithDescription](api/fastagency/api/openapi/fastapi_code_generator_helpers/ArgumentWithDescription.md)
- [patch_get_parameter_type](api/fastagency/api/openapi/fastapi_code_generator_helpers/patch_get_parameter_type.md)
- openapi
- [OpenAPI](api/fastagency/api/openapi/openapi/OpenAPI.md)
- [add_to_globals](api/fastagency/api/openapi/openapi/add_to_globals.md)
- patch_datamodel_code_generator
- [patch_apply_discriminator_type](api/fastagency/api/openapi/patch_datamodel_code_generator/patch_apply_discriminator_type.md)
- patch_fastapi_code_generator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
# 0.5 - API
# 2 - Release
# 3 - Contributing
# 5 - Template Page
# 10 - Default
search:
boost: 0.5
---

::: fastagency.api.dependency_injection.inject_params
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ search:
boost: 0.5
---

::: fastagency.api.openapi.client.OpenAPI
::: fastagency.api.openapi.openapi.OpenAPI
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ search:
boost: 0.5
---

::: fastagency.api.openapi.client.add_to_globals
::: fastagency.api.openapi.openapi.add_to_globals
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
141 changes: 141 additions & 0 deletions docs/docs/en/user-guide/api/dependency_injection/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Dependency Injection

[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection){target="_blank"} is a secure way to connect external functions to agents in `AutoGen` without exposing sensitive data such as passwords, tokens, or personal information. This approach ensures that sensitive information remains protected while still allowing agents to perform their tasks effectively, even when working with large language models (LLMs).

In this guide, we’ll explore how to use `FastAgency` to build secure workflows that handle sensitive data safely.

As an example, we’ll create a banking agent that retrieves a user's account balance. The best part is that sensitive data like username and password are never shared with the language model. Instead, it’s securely injected directly into the function at runtime, keeping it safe while maintaining seamless functionality.

Let’s get started!


## Why Use Dependency Injection?

When working with large language models (LLMs), **security is paramount**. There are several types of sensitive information that we want to keep out of the LLM’s reach:

- **Passwords or tokens**: These could be exposed through [prompt injection attacks](https://en.wikipedia.org/wiki/Prompt_injection){target="_blank"}.
- **Personal information**: Access to this data might fall under strict regulations, such as the [EU AI Act](https://www.europarl.europa.eu/topics/en/article/20230601STO93804/eu-ai-act-first-regulation-on-artificial-intelligence){target="_blank"}.

Dependency injection offers a robust solution by isolating sensitive data while enabling your agents to function effectively.

## Why Dependency Injection Is Essential

Here’s why dependency injection is a game-changer for secure LLM workflows:

- **Enhanced Security**: Your sensitive data is never directly exposed to the LLM.
- **Simplified Development**: Secure data can be seamlessly accessed by functions without requiring complex configurations.
- **Unmatched Flexibility**: It supports safe integration of diverse workflows, allowing you to scale and adapt with ease.

In this guide, we’ll explore how to set up dependency injection, build secure workflows, and create a protected application step-by-step. Let’s dive in!

---

## Install

We will use [**Cookiecutter**](../../../user-guide/cookiecutter/index.md) for setting up the project. Cookiecutter creates the project folder structure, default workflow, automatically installs all the necessary requirements, and creates a [devcontainer](https://code.visualstudio.com/docs/devcontainers/containers){target="_blank"} that can be used with [Visual Studio Code](https://code.visualstudio.com/){target="_blank"}.

You can setup the project using Cookiecutter by following the [**project setup guide**](../../../user-guide/cookiecutter/index.md).

In this example, we’ll create a **Mesop** application **without authentication**. The generated project will have the following files:

```console
{! docs_src/user_guide/dependency_injection/mesop/folder_structure.txt !}
```

## Complete Workflow Code
The only file you need to modify to run the application is `my_bank_app/my_bank_app/workflow.py`. Simply copy and paste the following content into the file:

<details>
<summary>workflow.py</summary>
```python
{! docs_src/user_guide/dependency_injection/workflow.py !}
```
</details>

## Step-by-Step Guide

### Imports
These imports are similar to the imports section we have already covered, with the only difference being the additional imports of the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) function:

```python hl_lines="7"
{! docs_src/user_guide/dependency_injection/workflow.py [ln:1-8] !}
```

### Define the Bank Savings Function

The `get_balance` function is central to this workflow. It retrieves the user's balance based on the provided **username** and **password**.

The key consideration here is that both username and password should **NEVER** be exposed to the LLM. Instead, they will be securely injected into the `get_balance` function later in the workflow using the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) mechanism, ensuring that sensitive information remains confidential while still allowing the function to access the required data.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:10-23] !}
```


### Configure the Language Model (LLM)
Here, the large language model is configured to use the `gpt-4o-mini` model, and the API key is retrieved from the environment. This setup ensures that both the user and weather agents can interact effectively.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:26-34] !}
```

### Define the Workflow and Agents

The `bank_workflow` handles user interaction and integrates agents to retrieve balance securely.


1. **User Input Collection**:
- At the beginning of the workflow, the user is prompted to provide:
- **Username**: The workflow asks, *"Enter your username:"*.
- **Password**: The workflow then asks, *"Enter your password:"*.

2. **Agent Setup**:
- Two agents are created to handle the workflow:
- **UserProxyAgent**: Simulates the user's perspective, facilitating secure communication.
- **ConversableAgent**: Acts as the banker agent, retrieving the user's balance.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:36-63] !}
```

### Dependency Injection
Username and password provided by the user are stored securely in a **context dictionary (`ctx`)**.
These parameters are **never shared with the LLM** and they are only used internally within the workflow.

Using [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md), the sensitive parameters from the `ctx` dictionary are injected into the `get_balance` function.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:65-69] !}
```

### Register Function with the Agents
In this step, we register the `get_balance_with_params`
```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:70-75] !}
```

### Enable Agent Interaction and Chat
Here, the user agent initiates a chat with the banker agent, which retrieves the user's balance. The conversation is summarized using a method provided by the LLM.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:77-84] !}
```

## Run Application

You can run this chapter's FastAgency application using the following command:

```console
gunicorn my_bank_app.deployment.main:app
```

## Output
At the beginning, the user is asked to provide the **username** and **password**.

![User Input](./images/user_input.png)

Once the user provide them, the agent executes the `get_balance` function with both parameters securely injected into the function using the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) mechanism, ensuring these parameters are not exposed to the LLM.

The agent processes the request, retrieves the user's balance, and provides a summary of the results without compromising sensitive data.

![Result](./images/result.png)
10 changes: 8 additions & 2 deletions docs/docs/en/user-guide/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ Currently, FastAgency supports importing API functionality from [**OpenAPI**](ht

## API Features in FastAgency

### 1. **[OpenAPI Import](./openapi/index.md)**
### 1. **[Dependency Injection](./dependency_injection/index.md)**
FastAgency offers a secure way to manage sensitive data using dependency injection. With the [**`inject_params`**](../../api/fastagency/api/dependency_injection/inject_params.md) function, sensitive information, such as tokens, is injected directly into functions without being exposed to the LLM. This ensures that sensitive data remains private while allowing agents to perform the required tasks. The process helps maintain data security and confidentiality while still enabling the proper execution of functions within the workflow.

[Learn more about Dependency Injection →](./dependency_injection/index.md)


### 2. **[OpenAPI Import](./openapi/index.md)**
FastAgency can automatically generate API functions from OpenAPI specifications, streamlining the process of connecting agents to external services. With just a few lines of code, you can import an API specification, and FastAgency will handle the function generation and LLM integration, making it simple for agents to call external APIs.

[Learn more about OpenAPI Import →](./openapi/index.md)

### 2. **[API Security](./security.md)**
### 3. **[API Security](./security.md)**
FastAgency supports different types of security for REST APIs, including OAuth, API keys, and more. This ensures that your API integrations are secure and can handle sensitive data. Our API security mechanisms are flexible, allowing you to configure and manage secure communication between your agents and external APIs.

[Learn more about API Security →](./security.md)
Expand Down
1 change: 1 addition & 0 deletions docs/docs/navigation_template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ search:
- [FastAPI + Nats.io](user-guide/adapters/fastapi_nats/index.md)
- [FastAPI Security](user-guide/adapters/fastapi/security.md)
- [API-s](user-guide/api/index.md)
- [Dependency Injection](user-guide/api/dependency_injection/index.md)
- [OpenAPI](user-guide/api/openapi/index.md)
- [Security](user-guide/api/security.md)
- [Testing](user-guide/testing/index.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
upstream nats_fastapi_backend {
# Enable sticky sessions with IP hash
ip_hash;


}

upstream fastapi_backend {
# Enable sticky sessions with IP hash
ip_hash;


}

upstream mesop_backend {
# Enable sticky sessions with IP hash
ip_hash;
Expand All @@ -18,9 +32,47 @@ map $fly_machine_id $sticky_action {
default "replay"; # Cookie exists but doesn't match - need to replay
}

# Main server block
# Fastapi server block
server {
listen $FASTAPI_PORT;
server_name localhost;

# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";

location / {
# Handle cookie setting
if ($sticky_action = "set_cookie") {
add_header Set-Cookie "fly-machine-id=$FLY_MACHINE_ID; Max-Age=518400; Path=/";
}

# Handle replay
if ($sticky_action = "replay") {
add_header Fly-Replay "instance=$fly_machine_id";
return 307;
}

proxy_pass http://fastapi_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_buffering off;

# WSGI support
proxy_set_header X-Forwarded-Host $server_name;

# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Mesop server block
server {
listen $SERVICE_PORT;
listen $MESOP_PORT;
server_name localhost;

# Security headers
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
#!/bin/bash

# Accept env variable for PORT


FASTAPI_PORT=${FASTAPI_PORT:-8008}


export NATS_FASTAPI_PORT=${NATS_FASTAPI_PORT:-8000}
export FASTAPI_PORT=${FASTAPI_PORT:-8008}
export MESOP_PORT=${MESOP_PORT:-8888}
export SERVICE_PORT=$MESOP_PORT

# Default number of workers if not set
WORKERS=${WORKERS:-1}
Expand All @@ -20,10 +16,23 @@ echo "Fly machine ID: $FLY_MACHINE_ID"
# Generate nginx config
for ((i=1; i<$WORKERS+1; i++))
do
PORT=$((SERVICE_PORT + i))
PORT=$((MESOP_PORT + i))
sed -i "19i\ server 127.0.0.1:$PORT;" nginx.conf.template
done

for ((i=1; i<$WORKERS+1; i++))
do
PORT=$((FASTAPI_PORT + i))
sed -i "12i\ server 127.0.0.1:$PORT;" nginx.conf.template
done

for ((i=1; i<$WORKERS+1; i++))
do
PORT=$((NATS_FASTAPI_PORT + i))
sed -i "5i\ server 127.0.0.1:$PORT;" nginx.conf.template
done
envsubst '${SERVICE_PORT},${FLY_MACHINE_ID}' < nginx.conf.template >/etc/nginx/conf.d/default.conf

envsubst '${NATS_FASTAPI_PORT},${FASTAPI_PORT},${MESOP_PORT},${FLY_MACHINE_ID}' < nginx.conf.template >/etc/nginx/conf.d/default.conf
echo "Nginx config:"
cat /etc/nginx/conf.d/default.conf

Expand All @@ -32,14 +41,20 @@ nginx -g "daemon off;" &


# Run uvicorn server
uvicorn my_fastagency_app.deployment.main_1_fastapi:app --host 0.0.0.0 --port $FASTAPI_PORT > /dev/stdout 2>&1 &
# Start multiple single-worker uvicorn instances on consecutive ports
for ((i=1; i<$WORKERS+1; i++))
do
PORT=$((FASTAPI_PORT + i))
echo "Starting fastapi uvicorn on port $PORT"
uvicorn my_fastagency_app.deployment.main_1_fastapi:app --workers=1 --host 0.0.0.0 --port $PORT > /dev/stdout 2>&1 &
done


# Run gunicorn server
# Start multiple single-worker gunicorn instances on consecutive ports
for ((i=1; i<$WORKERS+1; i++))
do
PORT=$((SERVICE_PORT + i))
PORT=$((MESOP_PORT + i))
echo "Starting gunicorn on port $PORT"
gunicorn --workers=1 my_fastagency_app.deployment.main_2_mesop:app --bind 0.0.0.0:$PORT > /dev/stdout 2>&1 &
done
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,30 @@ primary_region = 'ams'
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

[[services]]
http_checks = []
internal_port = 8008
processes = ["app"]
protocol = "tcp"
script_checks = []

[services.concurrency]
type = "connections"

[[services.ports]]
handlers = ["tls", "http"]
port = 8008
[[services]]
http_checks = []
internal_port = 8888
processes = ["app"]
protocol = "tcp"
script_checks = []

[services.concurrency]
type = "connections"

[[services.ports]]
handlers = ["tls", "http"]
port = 8888
Loading

0 comments on commit 750da19

Please sign in to comment.