Skip to content

Commit 72753d3

Browse files
Merge branch 'ag-ui-protocol:main' into kotlinsdk
2 parents bc22ef6 + eae2316 commit 72753d3

File tree

112 files changed

+21215
-376
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+21215
-376
lines changed

.github/workflows/dojo-e2e.yml

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,64 @@ on:
88

99
jobs:
1010
e2e:
11-
name: E2E Tests
12-
runs-on: depot-ubuntu-latest-8
11+
name: ${{ matrix.suite }}
12+
runs-on: depot-ubuntu-24.04
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
include:
17+
- suite: adk-middleware
18+
test_path: tests/adkMiddlewareTests
19+
services: ["dojo","adk-middleware"]
20+
wait_on: http://localhost:9999,tcp:localhost:8010
21+
- suite: agno
22+
test_path: tests/agnoTests
23+
services: ["dojo","agno"]
24+
wait_on: http://localhost:9999,tcp:localhost:8002
25+
- suite: crew-ai
26+
test_path: tests/crewAITests
27+
services: ["dojo","crew-ai"]
28+
wait_on: http://localhost:9999,tcp:localhost:8003
29+
- suite: langgraph
30+
test_path: tests/langgraphTests
31+
services: ["dojo","langgraph-platform-python","langgraph-platform-typescript"]
32+
wait_on: http://localhost:9999,tcp:localhost:8005,tcp:localhost:8006
33+
- suite: langgraph-fastapi
34+
test_path: tests/langgraphFastAPITests
35+
services: ["dojo","langgraph-fastapi"]
36+
wait_on: http://localhost:9999,tcp:localhost:8004
37+
- suite: llama-index
38+
test_path: tests/llamaIndexTests
39+
services: ["dojo","llama-index"]
40+
wait_on: http://localhost:9999,tcp:localhost:8007
41+
- suite: mastra
42+
test_path: tests/mastraTests
43+
services: ["dojo","mastra"]
44+
wait_on: http://localhost:9999,tcp:localhost:8008
45+
- suite: mastra-agent-local
46+
test_path: tests/mastraAgentLocalTests
47+
services: ["dojo"]
48+
wait_on: http://localhost:9999
49+
- suite: middleware-starter
50+
test_path: tests/middlewareStarterTests
51+
services: ["dojo"]
52+
wait_on: http://localhost:9999
53+
- suite: pydantic-ai
54+
test_path: tests/pydanticAITests
55+
services: ["dojo","pydantic-ai"]
56+
wait_on: http://localhost:9999,tcp:localhost:8009
57+
- suite: server-starter
58+
test_path: tests/serverStarterTests
59+
services: ["dojo","server-starter"]
60+
wait_on: http://localhost:9999,tcp:localhost:8000
61+
- suite: server-starter-all
62+
test_path: tests/serverStarterAllFeaturesTests
63+
services: ["dojo","server-starter-all"]
64+
wait_on: http://localhost:9999,tcp:localhost:8001
65+
- suite: vercel-ai-sdk
66+
test_path: tests/vercelAISdkTests
67+
services: ["dojo"]
68+
wait_on: http://localhost:9999
1369

1470
steps:
1571
- name: Checkout code
@@ -25,6 +81,33 @@ jobs:
2581
with:
2682
version: 10.13.1
2783

84+
# Now that pnpm is available, cache its store to speed installs
85+
- name: Resolve pnpm store path
86+
id: pnpm-store
87+
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
88+
89+
- name: Cache pnpm store
90+
uses: actions/cache@v4
91+
with:
92+
path: ${{ env.STORE_PATH }}
93+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
94+
restore-keys: |
95+
${{ runner.os }}-pnpm-store-
96+
97+
# Cache Python tool caches and virtualenvs; restore only to avoid long saves
98+
- name: Cache Python dependencies (restore-only)
99+
id: cache-python
100+
uses: actions/cache/restore@v4
101+
with:
102+
path: |
103+
~/.cache/pip
104+
~/.cache/pypoetry
105+
~/.cache/uv
106+
**/.venv
107+
key: ${{ runner.os }}-pydeps-${{ hashFiles('**/poetry.lock', '**/pyproject.toml') }}
108+
restore-keys: |
109+
${{ runner.os }}-pydeps-
110+
28111
- name: Install Poetry
29112
uses: snok/install-poetry@v1
30113
with:
@@ -35,21 +118,14 @@ jobs:
35118
- name: Install uv
36119
uses: astral-sh/setup-uv@v6
37120

38-
- name: Setup pnpm cache
39-
uses: actions/cache@v4
40-
with:
41-
path: ~/.local/share/pnpm/store
42-
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
43-
restore-keys: |
44-
${{ runner.os }}-pnpm-store-
45-
46121
- name: Install dependencies
47122
working-directory: typescript-sdk
48123
run: pnpm install --frozen-lockfile
49124

50125
- name: Prepare dojo for e2e
51126
working-directory: typescript-sdk/apps/dojo
52-
run: node ./scripts/prep-dojo-everything.js -e2e
127+
if: ${{ join(matrix.services, ',') != '' }}
128+
run: node ./scripts/prep-dojo-everything.js --only ${{ join(matrix.services, ',') }}
53129

54130
- name: Install e2e dependencies
55131
working-directory: typescript-sdk/apps/dojo/e2e
@@ -61,6 +137,7 @@ jobs:
61137
env:
62138
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
63139
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
140+
if: ${{ contains(join(matrix.services, ','), 'langgraph-fastapi') || contains(join(matrix.services, ','), 'langgraph-platform-python') || contains(join(matrix.services, ','), 'langgraph-platform-typescript') }}
64141
run: |
65142
echo "OPENAI_API_KEY=${OPENAI_API_KEY}" > examples/python/.env
66143
echo "LANGSMITH_API_KEY=${LANGSMITH_API_KEY}" >> examples/python/.env
@@ -74,33 +151,29 @@ jobs:
74151
env:
75152
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
76153
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
154+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
155+
if: ${{ join(matrix.services, ',') != '' && contains(join(matrix.services, ','), 'dojo') }}
77156
with:
78157
run: |
79-
node ../scripts/run-dojo-everything.js
158+
node ../scripts/run-dojo-everything.js --only ${{ join(matrix.services, ',') }}
80159
working-directory: typescript-sdk/apps/dojo/e2e
81-
wait-on: |
82-
http://localhost:9999
83-
tcp:localhost:8000
84-
tcp:localhost:8001
85-
tcp:localhost:8002
86-
tcp:localhost:8003
87-
tcp:localhost:8004
88-
tcp:localhost:8005
89-
tcp:localhost:8006
90-
tcp:localhost:8007
91-
tcp:localhost:8008
92-
tcp:localhost:8009
93-
94-
- name: Run tests
160+
wait-on: ${{ matrix.wait_on }}
161+
wait-for: 300000
162+
163+
- name: Run tests – ${{ matrix.suite }}
95164
working-directory: typescript-sdk/apps/dojo/e2e
96165
env:
97166
BASE_URL: http://localhost:9999
98-
run: pnpm test
167+
PLAYWRIGHT_SUITE: ${{ matrix.suite }}
168+
run: |
169+
pnpm test -- ${{ matrix.test_path }}
99170
100-
- name: Upload traces
171+
- name: Upload traces – ${{ matrix.suite }}
101172
if: always() # Uploads artifacts even if tests fail
102173
uses: actions/upload-artifact@v4
103174
with:
104-
name: playwright-traces
105-
path: typescript-sdk/apps/dojo/e2e/test-results/
175+
name: ${{ matrix.suite }}-playwright-traces
176+
path: |
177+
typescript-sdk/apps/dojo/e2e/test-results/${{ matrix.suite }}/**/*
178+
typescript-sdk/apps/dojo/e2e/playwright-report/**/*
106179
retention-days: 7

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
**/.claude/settings.local.json
12
.vscode/
23
.idea/

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@ AG-UI is complementary to the other 2 top agentic protocols
6767
- AG-UI brings agents into user-facing applications
6868

6969
<div align="center">
70-
<img src="https://github.com/user-attachments/assets/0c1ec566-050b-4ef8-ab89-15be41abe64f" />
70+
<img width="2048" height="1182" alt="The Agent Protocol Stack" src="https://github.com/user-attachments/assets/41138f71-50be-4812-98aa-20e0ad595716" />
7171
</div>
72-
7372

7473
## 🚀 Features
7574

docs/quickstart/server.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Open `apps/dojo/package.json` and add the package `@ag-ui/openai-server`:
174174
Now let's see your work in action. First, start your Python server:
175175

176176
```bash
177-
cd integrations/openai/server/python
177+
cd integrations/openai-server/server/python
178178
poetry install && poetry run dev
179179
```
180180

@@ -197,7 +197,7 @@ world!** for now.
197197
Here's what's happening with that stub server:
198198

199199
```python
200-
# integrations/openai/server/python/example_server/__init__.py
200+
# integrations/openai-server/server/python/example_server/__init__.py
201201
@app.post("/")
202202
async def agentic_chat_endpoint(input_data: RunAgentInput, request: Request):
203203
"""Agentic chat endpoint"""
@@ -268,7 +268,7 @@ OpenAI.
268268
First, we need the OpenAI SDK:
269269

270270
```bash
271-
cd integrations/openai/server/python
271+
cd integrations/openai-server/server/python
272272
poetry add openai
273273
```
274274

python-sdk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "ag-ui-protocol"
3-
version = "0.1.8"
3+
version = "0.1.9"
44
description = ""
55
authors = ["Markus Ecker <[email protected]>"]
66
readme = "README.md"

typescript-sdk/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ packages/proto/src/generated
4444
**/**/.langgraph_api
4545

4646
# Python
47+
venv
4748
__pycache__/
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { Page, Locator, expect } from '@playwright/test';
2+
3+
export class HumanInLoopPage {
4+
readonly page: Page;
5+
readonly planTaskButton: Locator;
6+
readonly chatInput: Locator;
7+
readonly sendButton: Locator;
8+
readonly agentGreeting: Locator;
9+
readonly plan: Locator;
10+
readonly performStepsButton: Locator;
11+
readonly agentMessage: Locator;
12+
readonly userMessage: Locator;
13+
14+
constructor(page: Page) {
15+
this.page = page;
16+
this.planTaskButton = page.getByRole('button', { name: 'Human in the loop Plan a task' });
17+
this.agentGreeting = page.getByText("Hi, I'm an agent specialized in helping you with your tasks. How can I help you?");
18+
this.chatInput = page.getByRole('textbox', { name: 'Type a message...' });
19+
this.sendButton = page.locator('[data-test-id="copilot-chat-ready"]');
20+
this.plan = page.getByTestId('select-steps');
21+
this.performStepsButton = page.getByRole('button', { name: 'Confirm' });
22+
this.agentMessage = page.locator('.copilotKitAssistantMessage');
23+
this.userMessage = page.locator('.copilotKitUserMessage');
24+
}
25+
26+
async openChat() {
27+
await this.agentGreeting.isVisible();
28+
}
29+
30+
async sendMessage(message: string) {
31+
await this.chatInput.click();
32+
await this.chatInput.fill(message);
33+
await this.sendButton.click();
34+
}
35+
36+
async selectItemsInPlanner() {
37+
await expect(this.plan).toBeVisible({ timeout: 10000 });
38+
await this.plan.click();
39+
}
40+
41+
async getPlannerOnClick(name: string | RegExp) {
42+
return this.page.getByRole('button', { name });
43+
}
44+
45+
async uncheckItem(identifier: number | string): Promise<string> {
46+
const plannerContainer = this.page.getByTestId('select-steps');
47+
const items = plannerContainer.getByTestId('step-item');
48+
49+
let item;
50+
if (typeof identifier === 'number') {
51+
item = items.nth(identifier);
52+
} else {
53+
item = items.filter({
54+
has: this.page.getByTestId('step-text').filter({ hasText: identifier })
55+
}).first();
56+
}
57+
const stepTextElement = item.getByTestId('step-text');
58+
const text = await stepTextElement.innerText();
59+
await item.click();
60+
61+
return text;
62+
}
63+
64+
async isStepItemUnchecked(target: number | string): Promise<boolean> {
65+
const plannerContainer = this.page.getByTestId('select-steps');
66+
const items = plannerContainer.getByTestId('step-item');
67+
68+
let item;
69+
if (typeof target === 'number') {
70+
item = items.nth(target);
71+
} else {
72+
item = items.filter({
73+
has: this.page.getByTestId('step-text').filter({ hasText: target })
74+
}).first();
75+
}
76+
const checkbox = item.locator('input[type="checkbox"]');
77+
return !(await checkbox.isChecked());
78+
}
79+
80+
async performSteps() {
81+
await this.performStepsButton.click();
82+
}
83+
84+
async assertAgentReplyVisible(expectedText: RegExp) {
85+
await expect(this.agentMessage.last().getByText(expectedText)).toBeVisible();
86+
}
87+
88+
async assertUserMessageVisible(message: string) {
89+
await expect(this.page.getByText(message)).toBeVisible();
90+
}
91+
}

0 commit comments

Comments
 (0)