Skip to content

Commit 0460e87

Browse files
committed
add llamaindex
1 parent 3a60b2c commit 0460e87

File tree

6 files changed

+187
-1
lines changed

6 files changed

+187
-1
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
test("[LlamaIndex] Backend Tool Rendering displays weather cards", async ({ page }) => {
4+
// Set shorter default timeout for this test
5+
test.setTimeout(30000); // 30 seconds total
6+
7+
await page.goto("/llama-index/feature/backend_tool_rendering");
8+
9+
// Verify suggestion buttons are visible
10+
await expect(page.getByRole("button", { name: "Weather in San Francisco" })).toBeVisible({
11+
timeout: 5000,
12+
});
13+
14+
// Click first suggestion and verify weather card appears
15+
await page.getByRole("button", { name: "Weather in San Francisco" }).click();
16+
17+
// Wait for either test ID or fallback to "Current Weather" text
18+
const weatherCard = page.getByTestId("weather-card");
19+
const currentWeatherText = page.getByText("Current Weather");
20+
21+
// Try test ID first, fallback to text
22+
try {
23+
await expect(weatherCard).toBeVisible({ timeout: 10000 });
24+
} catch (e) {
25+
// Fallback to checking for "Current Weather" text
26+
await expect(currentWeatherText.first()).toBeVisible({ timeout: 10000 });
27+
}
28+
29+
// Verify weather content is present (use flexible selectors)
30+
const hasHumidity = await page
31+
.getByText("Humidity")
32+
.isVisible()
33+
.catch(() => false);
34+
const hasWind = await page
35+
.getByText("Wind")
36+
.isVisible()
37+
.catch(() => false);
38+
const hasCityName = await page
39+
.locator("h3")
40+
.filter({ hasText: /San Francisco/i })
41+
.isVisible()
42+
.catch(() => false);
43+
44+
// At least one of these should be true
45+
expect(hasHumidity || hasWind || hasCityName).toBeTruthy();
46+
47+
// Click second suggestion
48+
await page.getByRole("button", { name: "Weather in New York" }).click();
49+
await page.waitForTimeout(2000);
50+
51+
// Verify at least one weather-related element is still visible
52+
const weatherElements = await page.getByText(/Weather|Humidity|Wind|Temperature/i).count();
53+
expect(weatherElements).toBeGreaterThan(0);
54+
});

typescript-sdk/apps/dojo/src/agents.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
281281
shared_state: new LlamaIndexAgent({
282282
url: `${envVars.llamaIndexUrl}/shared_state/run`,
283283
}),
284+
backend_tool_rendering: new LlamaIndexAgent({
285+
url: `${envVars.llamaIndexUrl}/backend_tool_rendering/run`,
286+
}),
284287
};
285288
},
286289
},

typescript-sdk/integrations/llamaindex/server-py/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dependencies = [
1515
"jsonpatch>=1.33",
1616
"uvicorn>=0.27.0",
1717
"fastapi>=0.100.0",
18+
"httpx>=0.24.0",
1819
]
1920
authors = [
2021
{ name = "Logan Markewich", email = "[email protected]" },

typescript-sdk/integrations/llamaindex/server-py/server/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
from .routers.human_in_the_loop import human_in_the_loop_router
77
from .routers.agentic_generative_ui import agentic_generative_ui_router
88
from .routers.shared_state import shared_state_router
9+
from .routers.backend_tool_rendering import backend_tool_rendering_router
910

1011
app = FastAPI(title="AG-UI Llama-Index Endpoint")
1112

1213
app.include_router(agentic_chat_router, prefix="/agentic_chat")
1314
app.include_router(human_in_the_loop_router, prefix="/human_in_the_loop")
1415
app.include_router(agentic_generative_ui_router, prefix="/agentic_generative_ui")
15-
app.include_router(shared_state_router, prefix="/shared_state")
1616

17+
app.include_router(shared_state_router, prefix="/shared_state")
18+
app.include_router(backend_tool_rendering_router, prefix="/backend_tool_rendering")
1719
def main():
1820

1921
"""Main function to start the FastAPI server."""
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""Backend Tool Rendering feature."""
2+
3+
from __future__ import annotations
4+
5+
from datetime import datetime
6+
import json
7+
from textwrap import dedent
8+
from zoneinfo import ZoneInfo
9+
10+
import httpx
11+
from llama_index.llms.openai import OpenAI
12+
from llama_index.protocols.ag_ui.router import get_ag_ui_workflow_router
13+
14+
15+
def get_weather_condition(code: int) -> str:
16+
"""Map weather code to human-readable condition.
17+
18+
Args:
19+
code: WMO weather code.
20+
21+
Returns:
22+
Human-readable weather condition string.
23+
"""
24+
conditions = {
25+
0: "Clear sky",
26+
1: "Mainly clear",
27+
2: "Partly cloudy",
28+
3: "Overcast",
29+
45: "Foggy",
30+
48: "Depositing rime fog",
31+
51: "Light drizzle",
32+
53: "Moderate drizzle",
33+
55: "Dense drizzle",
34+
56: "Light freezing drizzle",
35+
57: "Dense freezing drizzle",
36+
61: "Slight rain",
37+
63: "Moderate rain",
38+
65: "Heavy rain",
39+
66: "Light freezing rain",
40+
67: "Heavy freezing rain",
41+
71: "Slight snow fall",
42+
73: "Moderate snow fall",
43+
75: "Heavy snow fall",
44+
77: "Snow grains",
45+
80: "Slight rain showers",
46+
81: "Moderate rain showers",
47+
82: "Violent rain showers",
48+
85: "Slight snow showers",
49+
86: "Heavy snow showers",
50+
95: "Thunderstorm",
51+
96: "Thunderstorm with slight hail",
52+
99: "Thunderstorm with heavy hail",
53+
}
54+
return conditions.get(code, "Unknown")
55+
56+
57+
async def get_weather(location: str) -> str:
58+
"""Get current weather for a location.
59+
60+
Args:
61+
location: City name.
62+
63+
Returns:
64+
Dictionary with weather information including temperature, feels like,
65+
humidity, wind speed, wind gust, conditions, and location name.
66+
"""
67+
async with httpx.AsyncClient() as client:
68+
# Geocode the location
69+
geocoding_url = (
70+
f"https://geocoding-api.open-meteo.com/v1/search?name={location}&count=1"
71+
)
72+
geocoding_response = await client.get(geocoding_url)
73+
geocoding_data = geocoding_response.json()
74+
75+
if not geocoding_data.get("results"):
76+
raise ValueError(f"Location '{location}' not found")
77+
78+
result = geocoding_data["results"][0]
79+
latitude = result["latitude"]
80+
longitude = result["longitude"]
81+
name = result["name"]
82+
83+
# Get weather data
84+
weather_url = (
85+
f"https://api.open-meteo.com/v1/forecast?"
86+
f"latitude={latitude}&longitude={longitude}"
87+
f"&current=temperature_2m,apparent_temperature,relative_humidity_2m,"
88+
f"wind_speed_10m,wind_gusts_10m,weather_code"
89+
)
90+
weather_response = await client.get(weather_url)
91+
weather_data = weather_response.json()
92+
93+
current = weather_data["current"]
94+
95+
return json.dumps({
96+
"temperature": current["temperature_2m"],
97+
"feelsLike": current["apparent_temperature"],
98+
"humidity": current["relative_humidity_2m"],
99+
"windSpeed": current["wind_speed_10m"],
100+
"windGust": current["wind_gusts_10m"],
101+
"conditions": get_weather_condition(current["weather_code"]),
102+
"location": name,
103+
})
104+
105+
106+
# Create the router with weather tools
107+
backend_tool_rendering_router = get_ag_ui_workflow_router(
108+
llm=OpenAI(model="gpt-4o-mini"),
109+
backend_tools=[get_weather],
110+
system_prompt=dedent(
111+
"""
112+
You are a helpful weather assistant that provides accurate weather information.
113+
114+
Your primary function is to help users get weather details for specific locations. When responding:
115+
- Always ask for a location if none is provided
116+
- If the location name isn’t in English, please translate it
117+
- If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York")
118+
- Include relevant details like humidity, wind conditions, and precipitation
119+
- Keep responses concise but informative
120+
121+
Use the get_weather tool to fetch current weather data.
122+
"""
123+
),
124+
)

typescript-sdk/integrations/llamaindex/server-py/uv.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)