diff --git a/arch/arch_config_schema.yaml b/arch/arch_config_schema.yaml index 5d068701..c3285ebc 100644 --- a/arch/arch_config_schema.yaml +++ b/arch/arch_config_schema.yaml @@ -33,6 +33,8 @@ properties: enum: - http - https + http_host: + type: string additionalProperties: false required: - endpoint diff --git a/arch/envoy.template.yaml b/arch/envoy.template.yaml index 588c6f66..4017d889 100644 --- a/arch/envoy.template.yaml +++ b/arch/envoy.template.yaml @@ -486,14 +486,14 @@ static_resources: typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext sni: api.mistral.ai - {% for internal_clustrer in ["arch_fc", "model_server"] %} - - name: {{ internal_clustrer }} + {% for internal_cluster in ["arch_fc", "model_server"] %} + - name: {{ internal_cluster }} connect_timeout: 5s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN load_assignment: - cluster_name: {{ internal_clustrer }} + cluster_name: {{ internal_cluster }} endpoints: - lb_endpoints: - endpoint: @@ -501,7 +501,7 @@ static_resources: socket_address: address: host.docker.internal port_value: $MODEL_SERVER_PORT - hostname: {{ internal_clustrer }} + hostname: {{ internal_cluster }} {% endfor %} - name: mistral_7b_instruct connect_timeout: 5s @@ -537,7 +537,11 @@ static_resources: socket_address: address: {{ cluster.endpoint }} port_value: {{ cluster.port }} + {% if cluster.http_host %} + hostname: {{ cluster.http_host }} + {% else %} hostname: {{ cluster.endpoint }} + {% endif %} {% if cluster.protocol == "https" %} transport_socket: name: envoy.transport_sockets.tls diff --git a/arch/tools/cli/utils.py b/arch/tools/cli/utils.py index 8e8b234d..cc6ac20b 100644 --- a/arch/tools/cli/utils.py +++ b/arch/tools/cli/utils.py @@ -89,6 +89,18 @@ def get_llm_provider_access_keys(arch_config_file): if acess_key is not None: access_key_list.append(acess_key) + for prompt_target in arch_config_yaml.get("prompt_targets", []): + for k, v in prompt_target.get("endpoint", {}).get("http_headers", {}).items(): + if k.lower() == "authorization": + print( + f"found auth header: {k} for prompt_target: {prompt_target.get('name')}/{prompt_target.get('endpoint').get('name')}" + ) + auth_tokens = v.split(" ") + if len(auth_tokens) > 1: + access_key_list.append(auth_tokens[1]) + else: + access_key_list.append(v) + return access_key_list diff --git a/demos/currency_exchange/arch_config.yaml b/demos/currency_exchange/arch_config.yaml index c27e1ff2..49acdd6a 100644 --- a/demos/currency_exchange/arch_config.yaml +++ b/demos/currency_exchange/arch_config.yaml @@ -48,7 +48,8 @@ prompt_targets: endpoints: frankfurther_api: - endpoint: host.docker.internal:1122 + endpoint: api.frankfurter.dev:443 + protocol: https tracing: random_sampling: 100 diff --git a/demos/stock_exchange/README.md b/demos/stock_exchange/README.md new file mode 100644 index 00000000..856fc027 --- /dev/null +++ b/demos/stock_exchange/README.md @@ -0,0 +1 @@ +This demo shows how you can use a publicly hosted rest api that is protected by an access key. diff --git a/demos/stock_exchange/arch_config.yaml b/demos/stock_exchange/arch_config.yaml new file mode 100644 index 00000000..b0cb97e4 --- /dev/null +++ b/demos/stock_exchange/arch_config.yaml @@ -0,0 +1,71 @@ +version: v0.1 + +listener: + address: 0.0.0.0 + port: 10000 + message_format: huggingface + connect_timeout: 0.005s + +llm_providers: + - name: gpt-4o + access_key: $OPENAI_API_KEY + provider_interface: openai + model: gpt-4o + +system_prompt: | + You are a helpful assistant. + +endpoints: + twelvedata_api: + endpoint: api.twelvedata.com:443 + protocol: https + http_host: api.twelvedata.com + +prompt_guards: + input_guards: + jailbreak: + on_exception: + message: Looks like you're curious about my abilities, but I can only provide assistance for currency exchange. + +prompt_targets: + - name: stock_quote + description: get current stock exchange rate for a given symbol + parameters: + - name: symbol + description: Stock symbol + required: true + type: str + in_path: true + endpoint: + name: twelvedata_api + path: /quote?symbol={symbol} + http_headers: + Authorization: "apikey $TWELVEDATA_API_KEY" + system_prompt: | + You are a helpful stock exchange assistant. You are given stock symbol along with its exchange rate in json format. Your task is to parse the data and present it in a human-readable format. Keep the details to highlevel and be concise. + + - name: stock_quote_time_series + description: get historical stock exchange rate for a given symbol + parameters: + - name: symbol + description: Stock symbol + required: true + type: str + in_path: true + # - name: interval + # description: Time interval + # default: 1h + # type: str + # in_path: true + endpoint: + name: twelvedata_api + path: /time_series?symbol={symbol}&interval=1day + http_headers: + Authorization: "apikey $TWELVEDATA_API_KEY" + system_prompt: | + You are a helpful stock exchange assistant. You are given stock symbol along with its historical data in json format. Your task is to parse the data and present it in a human-readable format. Keep the details to highlevel only and be concise. + + +tracing: + random_sampling: 100 + trace_arch_internal: true diff --git a/demos/stock_exchange/docker-compose.yaml b/demos/stock_exchange/docker-compose.yaml new file mode 100644 index 00000000..32cfbd20 --- /dev/null +++ b/demos/stock_exchange/docker-compose.yaml @@ -0,0 +1,21 @@ +services: + chatbot_ui: + build: + context: ../shared/chatbot_ui + ports: + - "18080:8080" + environment: + # this is only because we are running the sample app in the same docker container environment as archgw + - CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:10000/v1 + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ./arch_config.yaml:/app/arch_config.yaml + + jaeger: + build: + context: ../shared/jaeger + ports: + - "16686:16686" + - "4317:4317" + - "4318:4318" diff --git a/demos/stock_exchange/run_demo.sh b/demos/stock_exchange/run_demo.sh new file mode 100644 index 00000000..eb47dce6 --- /dev/null +++ b/demos/stock_exchange/run_demo.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -e + +# Function to start the demo +start_demo() { + # Step 1: Check if .env file exists + if [ -f ".env" ]; then + echo ".env file already exists. Skipping creation." + else + # Step 2: Create `.env` file and set OpenAI key + if [ -z "$OPENAI_API_KEY" ]; then + echo "Error: OPENAI_API_KEY environment variable is not set for the demo." + exit 1 + fi + + echo "Creating .env file..." + echo "OPENAI_API_KEY=$OPENAI_API_KEY" > .env + echo ".env file created with OPENAI_API_KEY." + fi + + # Step 3: Start Arch + echo "Starting Arch with arch_config.yaml..." + archgw up arch_config.yaml + + # Step 4: Start developer services + echo "Starting Network Agent using Docker Compose..." + docker compose up -d # Run in detached mode +} + +# Function to stop the demo +stop_demo() { + # Step 1: Stop Docker Compose services + echo "Stopping Network Agent using Docker Compose..." + docker compose down + + # Step 2: Stop Arch + echo "Stopping Arch..." + archgw down +} + +# Main script logic +if [ "$1" == "down" ]; then + stop_demo +else + # Default action is to bring the demo up + start_demo +fi