From 8b4908279d47ab740ca0b649b3fefdd1f1bdc3db Mon Sep 17 00:00:00 2001 From: Muthukumaran PK Date: Wed, 1 Apr 2026 14:45:36 -0400 Subject: [PATCH 1/5] feat: make langflow consistent with helm-based agent pattern Add agent.yaml, Makefile, and .env.example to langflow agent for consistency with llamaindex/crewai/vanilla_python agents. Restructure README to match standard sections. Remove Ollama management from scripts (now a manual prerequisite like other agents). Update local-development and adding-a-new-agent docs. Co-Authored-By: Claude Opus 4.6 (1M context) --- agents/langflow/README.md | 11 + .../simple_tool_calling_agent/.env.example | 8 + .../simple_tool_calling_agent/Makefile | 43 ++++ .../simple_tool_calling_agent/README.md | 223 ++++++++---------- .../simple_tool_calling_agent/agent.yaml | 13 + .../cleanup-local.sh | 18 +- .../simple_tool_calling_agent/deploy-local.sh | 64 +---- docs/adding-a-new-agent.md | 14 ++ docs/local-development.md | 11 - 9 files changed, 187 insertions(+), 218 deletions(-) create mode 100644 agents/langflow/README.md create mode 100644 agents/langflow/simple_tool_calling_agent/.env.example create mode 100644 agents/langflow/simple_tool_calling_agent/Makefile create mode 100644 agents/langflow/simple_tool_calling_agent/agent.yaml diff --git a/agents/langflow/README.md b/agents/langflow/README.md new file mode 100644 index 00000000..465edfc6 --- /dev/null +++ b/agents/langflow/README.md @@ -0,0 +1,11 @@ +# Langflow Agents + +Agent templates built with [Langflow](https://docs.langflow.org/)'s visual flow builder. + +> **Note:** Langflow agents are different from other agents in this repo. They do not deploy a custom container — the "agent" is a JSON flow definition imported into an existing Langflow instance. See each agent's README for details. + +## Available Agents + +| Agent | Description | +|-------|-------------| +| [Simple Tool Calling Agent](simple_tool_calling_agent/) | Tool-calling agent that calls external APIs (weather, parks) and reasons over results. Includes Langfuse v3 tracing. | diff --git a/agents/langflow/simple_tool_calling_agent/.env.example b/agents/langflow/simple_tool_calling_agent/.env.example new file mode 100644 index 00000000..fed3ed2d --- /dev/null +++ b/agents/langflow/simple_tool_calling_agent/.env.example @@ -0,0 +1,8 @@ +# PostgreSQL +POSTGRES_USER=langflow +POSTGRES_PASSWORD=langflow +POSTGRES_DB=langflow + +# Langfuse — admin password and encryption key are auto-generated on first run by make init +LANGFUSE_ADMIN_PASSWORD= +LANGFUSE_ENCRYPTION_KEY= diff --git a/agents/langflow/simple_tool_calling_agent/Makefile b/agents/langflow/simple_tool_calling_agent/Makefile new file mode 100644 index 00000000..c05a7884 --- /dev/null +++ b/agents/langflow/simple_tool_calling_agent/Makefile @@ -0,0 +1,43 @@ +SHELL := bash +AGENT_NAME := $(shell python3 -c "import re; print(re.search(r'^name:\s*(.+)', open('agent.yaml').read(), re.M).group(1).strip())") +COMPOSE_FILE := local/podman-compose.yml +ENV_FILE := local/.env + +.PHONY: init run stop clean status logs help + +help: ## Show this help + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}' + +init: ## Create local/.env from .env.example and generate secrets + @if [ ! -f $(ENV_FILE) ]; then \ + cp .env.example $(ENV_FILE) && echo "Created local/.env from .env.example"; \ + else \ + echo "local/.env already exists — skipping"; \ + fi + @if ! grep -q '^LANGFUSE_ADMIN_PASSWORD=.\+' $(ENV_FILE) 2>/dev/null; then \ + GENERATED_PWD=$$(openssl rand -base64 12) && \ + sed -i.bak "s/^LANGFUSE_ADMIN_PASSWORD=.*/LANGFUSE_ADMIN_PASSWORD=$$GENERATED_PWD/" $(ENV_FILE) && \ + rm -f $(ENV_FILE).bak && \ + echo "Generated Langfuse admin password."; \ + fi + @if ! grep -q '^LANGFUSE_ENCRYPTION_KEY=.\+' $(ENV_FILE) 2>/dev/null; then \ + GENERATED_KEY=$$(openssl rand -hex 32) && \ + sed -i.bak "s/^LANGFUSE_ENCRYPTION_KEY=.*/LANGFUSE_ENCRYPTION_KEY=$$GENERATED_KEY/" $(ENV_FILE) && \ + rm -f $(ENV_FILE).bak && \ + echo "Generated Langfuse encryption key."; \ + fi + +run: init ## Start the local Langflow stack (Langflow + PostgreSQL + Langfuse + Ollama) + @./deploy-local.sh + +stop: ## Stop services (data preserved) + @./cleanup-local.sh + +clean: ## Stop services and remove all data + @./cleanup-local.sh --force + +status: ## Show status of running services + @cd local && podman-compose ps + +logs: ## Tail logs from all services + @cd local && podman-compose logs -f diff --git a/agents/langflow/simple_tool_calling_agent/README.md b/agents/langflow/simple_tool_calling_agent/README.md index 853eb42b..1c01fd8c 100644 --- a/agents/langflow/simple_tool_calling_agent/README.md +++ b/agents/langflow/simple_tool_calling_agent/README.md @@ -1,6 +1,6 @@
-# Langflow Simple Tool Calling Agent +# Simple Tool Calling Agent
@@ -8,11 +8,7 @@ ## What this agent does -A tool-calling agent built with Langflow's visual flow builder. It calls external APIs as tools (weather forecasts, national park data) and reasons over the results to answer user questions. Includes Langfuse v3 tracing out of the box. Runs locally via `podman-compose`. - -### Included demo flow - -The shipped flow is an outdoor activity assistant — it checks weather conditions and national park alerts to help decide if conditions are good for outdoor activities. +Tool-calling agent built with Langflow's visual flow builder. It calls external APIs as tools (weather forecasts, national park data) and reasons over the results to answer user questions. Includes Langfuse v3 tracing out of the box. **Example queries:** - *"Can I go walking in Boston tomorrow at 3 PM?"* @@ -26,44 +22,86 @@ The shipped flow is an outdoor activity assistant — it checks weather conditio | NPS Search Parks | NPS API | Search national parks by state | | NPS Park Alerts | NPS API | Active alerts and closures for a park | +> **Note:** Unlike other agents in this repo, Langflow agents do not deploy a custom container. The "agent" is a JSON flow definition imported into an existing Langflow instance. There is no Dockerfile, Helm chart, or FastAPI application. + --- -## Run locally +## Prerequisites -### Prerequisites +- [Podman](https://podman.io/) + [podman-compose](https://github.com/containers/podman-compose) — for running the local stack +- [GNU Make](https://www.gnu.org/software/make/) and a bash-compatible shell — on Windows, use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) (recommended) or [Git Bash](https://git-scm.com/downloads) -- **Podman** + **podman-compose** installed +### Installing Podman - **macOS:** - ```bash - brew install podman # install podman runtime - brew install podman-compose # install compose plugin - podman machine init # create a Linux VM (podman runs containers in a VM on macOS) - podman machine start # start the VM - ``` +**macOS:** +```bash +brew install podman # install podman runtime +brew install podman-compose # install compose plugin +podman machine init # create a Linux VM (podman runs containers in a VM on macOS) +podman machine start # start the VM +``` - **Linux:** - ```bash - sudo dnf install -y podman # install podman runtime - pip install podman-compose # install compose plugin - sudo systemctl start podman # start the podman service - ``` +**Linux:** +```bash +sudo dnf install -y podman # install podman runtime +pip install podman-compose # install compose plugin +sudo systemctl start podman # start the podman service +``` + +## Deploying Locally -### Start the local stack +### Setup ```bash cd agents/langflow/simple_tool_calling_agent -chmod +x deploy-local.sh cleanup-local.sh -./deploy-local.sh +make init # creates local/.env from .env.example, generates Langfuse secrets ``` -This starts: -- **Langflow** on http://localhost:7860 — the agent UI -- **PostgreSQL** — shared database server. Hosts two databases: `langflow` (flows, users, settings) and `langfuse` (metadata). The `langflow` database is created automatically by PostgreSQL; the `langfuse` database is created by `local/init-db.sh` on first startup -- **Ollama** on http://localhost:11434 — local LLM (qwen2.5:7b), runs natively on host for GPU acceleration -- **Langfuse v3** on http://localhost:3000 — tracing (admin@langflow.local / password auto-generated in `local/.env`), backed by ClickHouse, MinIO, and Redis +### Configuration + +#### Pointing to a locally hosted model + +After importing the flow (see [Running the Agent](#running-the-agent)), set these values in the **KServe vLLM** component: + +| Field | Value | +|-------|-------| +| api_base | http://host.containers.internal:8321/v1 | +| model_name | ollama/qwen2.5:7b | +| api_key | not-needed | + +See [Local Development](../../../docs/local-development.md) for Ollama + Llama Stack setup for local model serving. + +**Notes:** +- `api_base` — use `host.containers.internal` instead of `localhost` so containerized Langflow can reach Llama Stack running on the host +- `api_key` — Llama Stack doesn't require authentication, so any non-empty string works +- `model_name` — not all models handle tool calling well. `qwen2.5:7b` and `llama3.1:8b` are known to work + +#### Pointing to a remotely hosted model + +Update the **KServe vLLM** component in the Langflow UI: + +| Field | Value | +|-------|-------| +| api_base | your-model-endpoint/v1 | +| model_name | your-model-id | +| api_key | your-api-key | + +### Tracing + +Langfuse v3 tracing is included in the local stack and starts automatically. No additional setup needed. + +- **Langfuse UI**: http://localhost:3000 +- **Login**: admin@langflow.local / password auto-generated in `local/.env` + +After running the agent, select the **Langflow Agent** project and click **Traces** to see agent executions — LLM calls, tool invocations, inputs, and outputs. -### Import and configure the flow +### Running the Agent + +```bash +make run # starts Langflow + PostgreSQL + Langfuse v3 (ClickHouse, MinIO, Redis) +``` + +#### Import and configure the flow 1. Open http://localhost:7860 2. On first launch, Langflow asks you to create a flow — create a **Blank Flow** (this is just to get past the initial screen) @@ -73,56 +111,35 @@ This starts: | Component | Field | Value | |-----------|-------|-------| - | KServe vLLM | api_base | http://host.containers.internal:11434/v1 | - | KServe vLLM | model_name | qwen2.5:7b | - | KServe vLLM | api_key | dummy | + | KServe vLLM | api_base | http://host.containers.internal:8321/v1 | + | KServe vLLM | model_name | ollama/qwen2.5:7b | + | KServe vLLM | api_key | not-needed | | NPS Search Parks | api_key | Get one free at https://developer.nps.gov | | NPS Park Alerts | api_key | Same NPS key as above | 6. Run the agent from the Langflow UI -> **Note:** Ollama runs natively on your machine (not in a container) to leverage GPU acceleration. On Apple Silicon Macs, this uses Metal for faster inference. Response times vary by hardware — expect 30 seconds to a few minutes per tool call. For faster responses, point the agent to a GPU-backed cluster endpoint (see [Remote model](#remote-model-instead-of-ollama)). - -### Query the agent via API - -Once the flow is running, you can query it via the Langflow API: +#### Stopping the stack ```bash -curl -X POST http://localhost:7860/api/v1/run/ \ - -H "Content-Type: application/json" \ - -d '{"input_value": "What is the best day to hike near Denver?", "output_type": "chat", "input_type": "chat"}' +make stop # stop services, keep data +make clean # stop services, remove all data ``` -Replace `` with the flow ID from the Langflow UI. You can find it in the browser URL bar when you open the flow — e.g., `http://localhost:7860/flow/27e7203d-b2b1-4700-962a-144a66155f14` → the flow ID is `27e7203d-b2b1-4700-962a-144a66155f14`. - -On the cluster, replace `localhost:7860` with your cluster's Langflow route URL. - -### Stop the local stack - -```bash -./cleanup-local.sh # stop services, keep data -./cleanup-local.sh --force # stop services, remove all data -``` - -**What gets preserved vs wiped:** - -| Data | `cleanup-local.sh` | `cleanup-local.sh --force` | -|------|---------------------|----------------------------| -| Downloaded Ollama models (e.g., qwen2.5:7b) | Kept | Kept (stored on host, not in containers) | +| Data | `make stop` | `make clean` | +|------|-------------|--------------| | Imported Langflow flows | Kept | **Deleted** (re-import needed) | | Langfuse traces (ClickHouse + MinIO) | Kept | **Deleted** | | PostgreSQL data | Kept | **Deleted** | | Redis cache | Kept | **Deleted** | -| `.env` and `.ollama-enabled` config | Kept | **Deleted** | +| `local/.env` config | Kept | **Deleted** | ---- - -## Deploy to cluster +## Deploying to Cluster There is nothing to build or deploy — no Dockerfiles, no Helm charts, no k8s manifests. This agent assumes Langflow, Langfuse, and an LLM (LlamaStack/KServe) are already running on the cluster. You just import the flow JSON into the existing Langflow instance and configure it. ### Finding cluster endpoints -Reach out to your cluster admin for the Langflow URL and LlamaStack endpoint/model names. However, if you have `oc` CLI access, you can find them yourself: +Reach out to your cluster admin for the Langflow URL and LlamaStack endpoint/model names. If you have `oc` CLI access, you can find them yourself: ```bash # Langflow UI URL @@ -153,85 +170,29 @@ oc get inferenceservice --all-namespaces - **NPS Park Alerts**: set `api_key` (same NPS key) 4. Run the agent +## API Endpoints ---- - -## Pointing agent to different models - -### Local model (Ollama) - -By default, the local stack runs **qwen2.5:7b** on Ollama. After importing the flow, set these values in the **KServe vLLM** component: - -| Field | Value | -|-------|-------| -| api_base | http://host.containers.internal:11434/v1 | -| model_name | qwen2.5:7b | -| api_key | dummy | - -> Ollama runs natively on your host machine (not in a container) for GPU acceleration. Use `host.containers.internal` so containerized Langflow can reach it. Ollama doesn't require authentication, so api_key can be any non-empty string (e.g., dummy). - -If you want to use a different model: - -1. Pull the model on Ollama: - ```bash - ollama pull - ``` - Or edit `local/.env` to change the default model and restart: - ``` - OLLAMA_MODEL=llama3.1:8b - ``` - Then: `./cleanup-local.sh && ./deploy-local.sh` - -2. Update the **KServe vLLM** component in the Langflow UI: - - | Field | Value | - |-------|-------| - | api_base | http://host.containers.internal:11434/v1 | - | model_name | your-model-name | - -> **Note:** Make sure you have enough CPU/GPU resources locally to run the model. Also, not all models handle tool calling well — for example, smaller models like Llama 3.2 1B may fail at tool calling, causing connection errors when the agent tries to invoke tools. Models like `qwen2.5:7b` and `llama3.1:8b` are known to work well with tool calling. - -### Remote model (instead of Ollama) - -If you primarily work with a remote model endpoint, or don't have enough local CPU/GPU resources to host a model, you can skip installing Ollama entirely by answering **n** when prompted by `deploy-local.sh`. - -Then update the **KServe vLLM** component in the Langflow UI to point to your remote endpoint: +### POST /api/v1/run/\ -| Field | Value | -|-------|-------| -| api_base | your-model-endpoint/v1 | -| model_name | your-model-id | -| api_key | your-api-key | - ---- - -## Viewing traces in Langfuse - -After running the agent, traces are automatically sent to Langfuse. - -**Locally:** -1. Open http://localhost:3000 (login: admin@langflow.local / password auto-generated in `local/.env`) -2. Select the **Langflow Agent** project -3. Click **Traces** in the left sidebar -4. Click on any trace to see the full agent execution — LLM calls, tool invocations, inputs, and outputs +```bash +curl -X POST http://localhost:7860/api/v1/run/ \ + -H "Content-Type: application/json" \ + -d '{"input_value": "What is the best day to hike near Denver?", "output_type": "chat", "input_type": "chat"}' +``` -**On cluster:** -1. Open the Langfuse route on your cluster -2. Select the **Langflow Agent** project -3. Click **Traces** in the left sidebar +Replace `` with the flow ID from the Langflow UI. You can find it in the browser URL bar when you open the flow — e.g., `http://localhost:7860/flow/27e7203d-b2b1-4700-962a-144a66155f14` → the flow ID is `27e7203d-b2b1-4700-962a-144a66155f14`. ---- +On the cluster, replace `localhost:7860` with your cluster's Langflow route URL. -## Exporting flows +## Exporting Flows When exporting a flow from Langflow, API keys and secrets can be embedded in the exported JSON file. To avoid leaking secrets: 1. In the export dialog, **uncheck "Save with API keys"** — this excludes all API keys from the exported file 2. If you already exported with keys included, you can strip them manually by searching for `"api_key"` fields in the JSON and clearing their `"value"` entries ---- - -## APIs Used +## Resources +- [Langflow Documentation](https://docs.langflow.org/) - [Open-Meteo](https://open-meteo.com/) — Weather and air quality (free, no key required) - [National Park Service API](https://developer.nps.gov) — Park search and alerts (free key required) diff --git a/agents/langflow/simple_tool_calling_agent/agent.yaml b/agents/langflow/simple_tool_calling_agent/agent.yaml new file mode 100644 index 00000000..4afa0beb --- /dev/null +++ b/agents/langflow/simple_tool_calling_agent/agent.yaml @@ -0,0 +1,13 @@ +name: langflow-simple-tool-calling-agent +displayName: "Langflow Simple Tool Calling Agent" +framework: langflow +description: "Tool-calling agent built with Langflow's visual flow builder. Calls external APIs as tools and reasons over results." +deploymentModel: flow-import +env: + required: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + optional: + - LANGFUSE_ADMIN_PASSWORD + - LANGFUSE_ENCRYPTION_KEY diff --git a/agents/langflow/simple_tool_calling_agent/cleanup-local.sh b/agents/langflow/simple_tool_calling_agent/cleanup-local.sh index 680748a0..cde6b5b4 100755 --- a/agents/langflow/simple_tool_calling_agent/cleanup-local.sh +++ b/agents/langflow/simple_tool_calling_agent/cleanup-local.sh @@ -7,17 +7,6 @@ LOCAL_DIR="$SCRIPT_DIR/local" cd "$LOCAL_DIR" || { echo "ERROR: Directory $LOCAL_DIR not found."; exit 1; } -stop_ollama() { - if pgrep -f "ollama serve" >/dev/null 2>&1; then - pkill -f "ollama serve" || true - if pgrep -f "ollama serve" >/dev/null 2>&1; then - echo "WARNING: Could not stop Ollama. Stop it manually: pkill -f 'ollama serve'" - else - echo "Ollama stopped." - fi - fi -} - if [ "${1:-}" = "--force" ]; then echo "Stopping services and removing all data..." # Stop containerized services @@ -32,16 +21,11 @@ if [ "${1:-}" = "--force" ]; then done # Remove project network podman network rm local_default || true - # Stop native Ollama - stop_ollama # Clean up config - rm -f "$LOCAL_DIR/.ollama-enabled" rm -f "$LOCAL_DIR/.env" echo "Done. All services stopped and data removed." else echo "Stopping services (data preserved)..." podman-compose down --remove-orphans || true - # Stop native Ollama - stop_ollama - echo "Done. Run './deploy-local.sh' to start again." + echo "Done. Run 'make run' to start again." fi diff --git a/agents/langflow/simple_tool_calling_agent/deploy-local.sh b/agents/langflow/simple_tool_calling_agent/deploy-local.sh index 2cf77f0c..c25783d4 100755 --- a/agents/langflow/simple_tool_calling_agent/deploy-local.sh +++ b/agents/langflow/simple_tool_calling_agent/deploy-local.sh @@ -22,7 +22,7 @@ fi # Copy .env if it doesn't exist if [ ! -f "$LOCAL_DIR/.env" ]; then - cp "$LOCAL_DIR/.env.example" "$LOCAL_DIR/.env" + cp "$SCRIPT_DIR/.env.example" "$LOCAL_DIR/.env" echo "Created .env from .env.example" fi @@ -41,57 +41,6 @@ if ! grep -q '^LANGFUSE_ENCRYPTION_KEY=.\+' "$LOCAL_DIR/.env" 2>/dev/null; then echo "Generated Langfuse encryption key." fi -# Ask about Ollama on first run -OLLAMA_FLAG="$LOCAL_DIR/.ollama-enabled" -if [ ! -f "$OLLAMA_FLAG" ]; then - echo "" - read -p "Do you want to use Ollama as a local LLM? (Y/n) " -n 1 -r - echo "" - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - echo "yes" > "$OLLAMA_FLAG" - else - echo "no" > "$OLLAMA_FLAG" - echo "Ollama disabled. You can point Langflow to an external model endpoint instead." - fi -fi - -USE_OLLAMA=$(cat "$OLLAMA_FLAG") - -# Start Ollama natively (not in a container) for GPU acceleration -if [ "$USE_OLLAMA" = "yes" ]; then - if ! command -v ollama &>/dev/null; then - echo "Ollama is not installed. Installing..." - if [[ "$(uname)" == "Darwin" ]]; then - brew install ollama - else - curl -fsSL https://ollama.com/install.sh | sh - fi - fi - - # Start ollama if not already running - if ! curl -s http://localhost:11434/api/tags &>/dev/null; then - echo "Starting Ollama..." - ollama serve &>/dev/null & - sleep 3 - else - echo "Ollama is already running." - fi - - # Pull model if needed - if [ -f "$LOCAL_DIR/.env" ]; then - OLLAMA_MODEL=$(grep -E '^OLLAMA_MODEL=' "$LOCAL_DIR/.env" | cut -d= -f2- || true) - fi - OLLAMA_MODEL="${OLLAMA_MODEL:-qwen2.5:7b}" - - if ollama list | grep -q "$OLLAMA_MODEL"; then - echo "Ollama model '$OLLAMA_MODEL' already available." - else - echo "Pulling Ollama model: $OLLAMA_MODEL (first time only)..." - ollama pull "$OLLAMA_MODEL" || \ - echo "Warning: Could not pull model. Run manually: ollama pull $OLLAMA_MODEL" - fi -fi - cd "$LOCAL_DIR" || { echo "ERROR: Directory $LOCAL_DIR not found."; exit 1; } # Start containerized services (Langflow, PostgreSQL, Langfuse) @@ -139,18 +88,15 @@ echo "=== Local environment is ready ===" echo "" echo " Langflow UI: http://localhost:7860" echo " Langfuse: http://localhost:3000 (login: admin@langflow.local / password auto-generated in local/.env)" -if [ "$USE_OLLAMA" = "yes" ]; then - echo " Ollama API: http://localhost:11434 (running natively on host)" -fi echo "" echo " Next steps:" echo " 1. Open http://localhost:7860" echo " 2. Import the flow: flows/outdoor-activity-agent.json" -echo " 3. Configure the flow components:" -echo " - KServe vLLM: set api_base=http://host.containers.internal:11434/v1 and model_name=qwen2.5:7b" +echo " 3. Configure the flow components (see README for details):" +echo " - KServe vLLM: set api_base and model_name (Ollama, LlamaStack, or remote endpoint)" echo " - NPS Search Parks: set api_key (get one at https://developer.nps.gov)" echo " - NPS Park Alerts: set api_key (same NPS key)" echo " 4. Run the agent from the Langflow UI" echo "" -echo " To stop: ./cleanup-local.sh" -echo " To stop and wipe data: ./cleanup-local.sh --force" +echo " To stop: make stop" +echo " To stop and wipe data: make clean" diff --git a/docs/adding-a-new-agent.md b/docs/adding-a-new-agent.md index ffb4f71b..dbae0085 100644 --- a/docs/adding-a-new-agent.md +++ b/docs/adding-a-new-agent.md @@ -41,6 +41,20 @@ Every agent must have: | `tests/` | Tests directory | | `examples/` | Example scripts | +### Flow-based agents (e.g., Langflow) + +Some agents do not deploy a custom container. Instead, the "agent" is a flow definition (e.g., JSON) imported into a pre-existing platform instance. These agents should still have: + +| File | Purpose | +|------|---------| +| `agent.yaml` | Same as above, but add `deploymentModel: flow-import` and adjust env vars to match the infrastructure stack | +| `Makefile` | Targets: `init`, `run`, `stop`, `clean`, `status`, `logs`, `help` | +| `.env.example` | Environment variables for the local infrastructure stack | +| `README.md` | Setup, usage, and deployment instructions | +| `flows/` | Flow definition files (JSON, YAML, etc.) | + +These agents do **not** need: `Dockerfile`, `values.yaml`, `.dockerignore`, `pyproject.toml`, `main.py`, `src/`, `tests/`, `examples/`, `playground/`. + ## 4. API Contract All agents must expose these endpoints: diff --git a/docs/local-development.md b/docs/local-development.md index 4ae306af..0cf32db9 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -114,17 +114,6 @@ cd agents/langgraph/react_agent make test ``` -## Building Container Images Locally - -The Makefiles auto-detect [Podman](https://podman.io/) (preferred) or Docker for container builds: - -```bash -make build # builds image locally using podman (or docker) -make push # pushes image to registry -``` - -To install Podman, see [podman.io/docs/installation](https://podman.io/docs/installation). On RHEL/Fedora it is pre-installed. - ## Dependencies All agents use [uv](https://docs.astral.sh/uv/) for dependency management: From 460437075effd075d8397f3420c0247fc13c5300 Mon Sep 17 00:00:00 2001 From: Muthukumaran PK Date: Thu, 2 Apr 2026 03:18:15 -0400 Subject: [PATCH 2/5] fix: restructure langflow README sections and use Llama Stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder sections: Setup → Import → Configuration → Running. Move make run to Setup since it starts infrastructure not the agent. Add Llama Stack as default local model serving (consistent with other agents). Remove container image build section from local-development docs (already in openshift-deployment docs). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../simple_tool_calling_agent/README.md | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/agents/langflow/simple_tool_calling_agent/README.md b/agents/langflow/simple_tool_calling_agent/README.md index 1c01fd8c..4fda514d 100644 --- a/agents/langflow/simple_tool_calling_agent/README.md +++ b/agents/langflow/simple_tool_calling_agent/README.md @@ -55,19 +55,29 @@ sudo systemctl start podman # start the podman service ```bash cd agents/langflow/simple_tool_calling_agent make init # creates local/.env from .env.example, generates Langfuse secrets +make run # starts Langflow + PostgreSQL + Langfuse v3 (ClickHouse, MinIO, Redis) ``` +### Import the flow + +1. Open http://localhost:7860 +2. On first launch, Langflow asks you to create a flow — create a **Blank Flow** (this is just to get past the initial screen) +3. Click the **Langflow icon** (top left) to go to the projects page +4. Click **Upload Flow** and select `flows/outdoor-activity-agent.json` + ### Configuration -#### Pointing to a locally hosted model +Configure the flow components: -After importing the flow (see [Running the Agent](#running-the-agent)), set these values in the **KServe vLLM** component: +| Component | Field | Value | +|-----------|-------|-------| +| KServe vLLM | api_base | http://host.containers.internal:8321/v1 | +| KServe vLLM | model_name | ollama/qwen2.5:7b | +| KServe vLLM | api_key | not-needed | +| NPS Search Parks | api_key | Get one free at https://developer.nps.gov | +| NPS Park Alerts | api_key | Same NPS key as above | -| Field | Value | -|-------|-------| -| api_base | http://host.containers.internal:8321/v1 | -| model_name | ollama/qwen2.5:7b | -| api_key | not-needed | +#### Pointing to a locally hosted model See [Local Development](../../../docs/local-development.md) for Ollama + Llama Stack setup for local model serving. @@ -86,6 +96,10 @@ Update the **KServe vLLM** component in the Langflow UI: | model_name | your-model-id | | api_key | your-api-key | +### Running the Agent + +Run the agent from the Langflow UI by clicking the **Play** button. + ### Tracing Langfuse v3 tracing is included in the local stack and starts automatically. No additional setup needed. @@ -95,29 +109,6 @@ Langfuse v3 tracing is included in the local stack and starts automatically. No After running the agent, select the **Langflow Agent** project and click **Traces** to see agent executions — LLM calls, tool invocations, inputs, and outputs. -### Running the Agent - -```bash -make run # starts Langflow + PostgreSQL + Langfuse v3 (ClickHouse, MinIO, Redis) -``` - -#### Import and configure the flow - -1. Open http://localhost:7860 -2. On first launch, Langflow asks you to create a flow — create a **Blank Flow** (this is just to get past the initial screen) -3. Click the **Langflow icon** (top left) to go to the projects page -4. Click **Upload Flow** and select `flows/outdoor-activity-agent.json` -5. Configure the flow components: - - | Component | Field | Value | - |-----------|-------|-------| - | KServe vLLM | api_base | http://host.containers.internal:8321/v1 | - | KServe vLLM | model_name | ollama/qwen2.5:7b | - | KServe vLLM | api_key | not-needed | - | NPS Search Parks | api_key | Get one free at https://developer.nps.gov | - | NPS Park Alerts | api_key | Same NPS key as above | -6. Run the agent from the Langflow UI - #### Stopping the stack ```bash From ca07b12405ddc3feba4cc0f7ecde6013c71dbf3c Mon Sep 17 00:00:00 2001 From: Muthukumaran PK Date: Thu, 2 Apr 2026 03:38:47 -0400 Subject: [PATCH 3/5] fix: remove env section from langflow agent.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All env vars are either hardcoded defaults in podman-compose.yml or auto-generated by make init — none are user-provided config. Co-Authored-By: Claude Opus 4.6 (1M context) --- agents/langflow/simple_tool_calling_agent/agent.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/agents/langflow/simple_tool_calling_agent/agent.yaml b/agents/langflow/simple_tool_calling_agent/agent.yaml index 4afa0beb..d785e03f 100644 --- a/agents/langflow/simple_tool_calling_agent/agent.yaml +++ b/agents/langflow/simple_tool_calling_agent/agent.yaml @@ -3,11 +3,3 @@ displayName: "Langflow Simple Tool Calling Agent" framework: langflow description: "Tool-calling agent built with Langflow's visual flow builder. Calls external APIs as tools and reasons over results." deploymentModel: flow-import -env: - required: - - POSTGRES_USER - - POSTGRES_PASSWORD - - POSTGRES_DB - optional: - - LANGFUSE_ADMIN_PASSWORD - - LANGFUSE_ENCRYPTION_KEY From 6c1e52ed1046af82d3c2ab660a45c34527c6e8be Mon Sep 17 00:00:00 2001 From: Muthukumaran PK Date: Thu, 2 Apr 2026 03:41:48 -0400 Subject: [PATCH 4/5] fix: remove Ollama reference from Makefile run target Co-Authored-By: Claude Opus 4.6 (1M context) --- agents/langflow/simple_tool_calling_agent/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/langflow/simple_tool_calling_agent/Makefile b/agents/langflow/simple_tool_calling_agent/Makefile index c05a7884..c1d855fe 100644 --- a/agents/langflow/simple_tool_calling_agent/Makefile +++ b/agents/langflow/simple_tool_calling_agent/Makefile @@ -27,7 +27,7 @@ init: ## Create local/.env from .env.example and generate secrets echo "Generated Langfuse encryption key."; \ fi -run: init ## Start the local Langflow stack (Langflow + PostgreSQL + Langfuse + Ollama) +run: init ## Start the local Langflow stack (Langflow + PostgreSQL + Langfuse) @./deploy-local.sh stop: ## Stop services (data preserved) From 9228a9d925778d1e381cb7a722866d0f82750382 Mon Sep 17 00:00:00 2001 From: Muthukumaran PK Date: Fri, 3 Apr 2026 13:38:36 -0400 Subject: [PATCH 5/5] fix: address review comments - Remove unused AGENT_NAME from Makefile - Use COMPOSE_FILE variable in status/logs targets - Remove duplicated init logic from deploy-local.sh (Makefile owns init) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../simple_tool_calling_agent/Makefile | 5 ++--- .../simple_tool_calling_agent/deploy-local.sh | 21 +++---------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/agents/langflow/simple_tool_calling_agent/Makefile b/agents/langflow/simple_tool_calling_agent/Makefile index c1d855fe..0516a59e 100644 --- a/agents/langflow/simple_tool_calling_agent/Makefile +++ b/agents/langflow/simple_tool_calling_agent/Makefile @@ -1,5 +1,4 @@ SHELL := bash -AGENT_NAME := $(shell python3 -c "import re; print(re.search(r'^name:\s*(.+)', open('agent.yaml').read(), re.M).group(1).strip())") COMPOSE_FILE := local/podman-compose.yml ENV_FILE := local/.env @@ -37,7 +36,7 @@ clean: ## Stop services and remove all data @./cleanup-local.sh --force status: ## Show status of running services - @cd local && podman-compose ps + @podman-compose -f $(COMPOSE_FILE) ps logs: ## Tail logs from all services - @cd local && podman-compose logs -f + @podman-compose -f $(COMPOSE_FILE) logs -f diff --git a/agents/langflow/simple_tool_calling_agent/deploy-local.sh b/agents/langflow/simple_tool_calling_agent/deploy-local.sh index c25783d4..afef7f0e 100755 --- a/agents/langflow/simple_tool_calling_agent/deploy-local.sh +++ b/agents/langflow/simple_tool_calling_agent/deploy-local.sh @@ -20,25 +20,10 @@ if ! command -v podman-compose &>/dev/null; then exit 1 fi -# Copy .env if it doesn't exist +# Ensure init has been run if [ ! -f "$LOCAL_DIR/.env" ]; then - cp "$SCRIPT_DIR/.env.example" "$LOCAL_DIR/.env" - echo "Created .env from .env.example" -fi - -# Generate Langfuse secrets if not already set -if ! grep -q '^LANGFUSE_ADMIN_PASSWORD=.\+' "$LOCAL_DIR/.env" 2>/dev/null; then - GENERATED_PWD=$(openssl rand -base64 12) - sed -i.bak "s/^LANGFUSE_ADMIN_PASSWORD=.*/LANGFUSE_ADMIN_PASSWORD=$GENERATED_PWD/" "$LOCAL_DIR/.env" - rm -f "$LOCAL_DIR/.env.bak" - echo "Generated Langfuse admin password." -fi - -if ! grep -q '^LANGFUSE_ENCRYPTION_KEY=.\+' "$LOCAL_DIR/.env" 2>/dev/null; then - GENERATED_KEY=$(openssl rand -hex 32) - sed -i.bak "s/^LANGFUSE_ENCRYPTION_KEY=.*/LANGFUSE_ENCRYPTION_KEY=$GENERATED_KEY/" "$LOCAL_DIR/.env" - rm -f "$LOCAL_DIR/.env.bak" - echo "Generated Langfuse encryption key." + echo "ERROR: local/.env not found. Run 'make init' first." + exit 1 fi cd "$LOCAL_DIR" || { echo "ERROR: Directory $LOCAL_DIR not found."; exit 1; }