Skip to content

Commit 6eedfa5

Browse files
authored
Fix up some langgraph docs and scripts in the dojo (ag-ui-protocol#271)
* Run langgraph fastapi now with new commands * autofmt * fix langgraph python examples readme to support platform and fastapi * Add typescript langgraph to dojo agents fix missed envvar update * Add reasoning example to lg platform python * fix url to reasoning dojo for fastapi * fix concurrently running fastapi and python lg platform * Add test suites for langgraph fastapi and typescript
1 parent ee20236 commit 6eedfa5

File tree

9 files changed

+375
-39
lines changed

9 files changed

+375
-39
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('renders initial message', async ({ page }) => {
4+
await page.goto('http://localhost:9999/langgraph-fastapi/feature/agentic_chat');
5+
6+
await expect(page.getByText('Hi, I\'m an agent. Want to chat?')).toBeVisible();
7+
});
8+
9+
test('responds to user message', async ({ page }) => {
10+
await page.goto('http://localhost:9999/langgraph-fastapi/feature/agentic_chat');
11+
12+
const textarea = page.getByPlaceholder('Type a message...');
13+
textarea.fill('How many sides are in a square? Please answer in one word. Do not use any punctuation, just the number in word form.');
14+
await page.keyboard.press('Enter');
15+
16+
page.locator('.copilotKitInputControls button.copilotKitInputControlButton').click();
17+
18+
await expect(page.locator('.copilotKitMessage')).toHaveCount(3);
19+
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage')).toHaveCount(2);
20+
await expect(page.locator('.copilotKitMessage.copilotKitUserMessage')).toHaveCount(1);
21+
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage').last()).toHaveText('four', { ignoreCase: true });
22+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('renders initial message', async ({ page }) => {
4+
await page.goto('http://localhost:9999/langgraph-typescript/feature/agentic_chat');
5+
6+
await expect(page.getByText('Hi, I\'m an agent. Want to chat?')).toBeVisible();
7+
});
8+
9+
test('responds to user message', async ({ page }) => {
10+
await page.goto('http://localhost:9999/langgraph-typescript/feature/agentic_chat');
11+
12+
const textarea = page.getByPlaceholder('Type a message...');
13+
textarea.fill('How many sides are in a square? Please answer in one word. Do not use any punctuation, just the number in word form.');
14+
await page.keyboard.press('Enter');
15+
16+
page.locator('.copilotKitInputControls button.copilotKitInputControlButton').click();
17+
18+
await expect(page.locator('.copilotKitMessage')).toHaveCount(3);
19+
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage')).toHaveCount(2);
20+
await expect(page.locator('.copilotKitMessage.copilotKitUserMessage')).toHaveCount(1);
21+
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage').last()).toHaveText('four', { ignoreCase: true });
22+
});

typescript-sdk/apps/dojo/scripts/generate-content-json.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ import path from "path";
55
function parseAgentsFile(): Array<{id: string, agentKeys: string[]}> {
66
const agentsFilePath = path.join(__dirname, '../src/agents.ts');
77
const agentsContent = fs.readFileSync(agentsFilePath, 'utf8');
8-
8+
99
const agentConfigs: Array<{id: string, agentKeys: string[]}> = [];
10-
10+
1111
// Split the content to process each agent configuration individually
1212
const agentBlocks = agentsContent.split(/(?=\s*{\s*id:\s*["'])/);
13-
13+
1414
for (const block of agentBlocks) {
1515
// Extract the ID
1616
const idMatch = block.match(/id:\s*["']([^"']+)["']/);
1717
if (!idMatch) continue;
18-
18+
1919
const id = idMatch[1];
20-
20+
2121
// Find the return object by looking for the pattern and then manually parsing balanced braces
2222
const returnMatch = block.match(/agents:\s*async\s*\(\)\s*=>\s*{\s*return\s*{/);
2323
if (!returnMatch) continue;
24-
24+
2525
const startIndex = returnMatch.index! + returnMatch[0].length;
2626
const returnObjectContent = extractBalancedBraces(block, startIndex);
27-
28-
27+
28+
2929
// Extract keys from the return object - only capture keys that are followed by a colon and then 'new'
3030
// This ensures we only get the top-level keys like "agentic_chat: new ..." not nested keys like "url: ..."
3131
const keyRegex = /^\s*(\w+):\s*new\s+\w+/gm;
@@ -34,18 +34,18 @@ function parseAgentsFile(): Array<{id: string, agentKeys: string[]}> {
3434
while ((keyMatch = keyRegex.exec(returnObjectContent)) !== null) {
3535
keys.push(keyMatch[1]);
3636
}
37-
37+
3838
agentConfigs.push({ id, agentKeys: keys });
3939
}
40-
40+
4141
return agentConfigs;
4242
}
4343

4444
// Helper function to extract content between balanced braces
4545
function extractBalancedBraces(text: string, startIndex: number): string {
4646
let braceCount = 0;
4747
let i = startIndex;
48-
48+
4949
while (i < text.length) {
5050
if (text[i] === '{') {
5151
braceCount++;
@@ -58,7 +58,7 @@ function extractBalancedBraces(text: string, startIndex: number): string {
5858
}
5959
i++;
6060
}
61-
61+
6262
return '';
6363
}
6464

@@ -71,23 +71,23 @@ async function getFile(_filePath: string | undefined, _fileName?: string) {
7171
console.warn(`File path is undefined, skipping.`);
7272
return {}
7373
}
74-
74+
7575
const fileName = _fileName ?? _filePath.split('/').pop() ?? ''
7676
const filePath = _fileName ? path.join(_filePath, fileName) : _filePath;
77-
77+
7878
// Check if it's a remote URL
7979
const isRemoteUrl = _filePath.startsWith('http://') || _filePath.startsWith('https://');
80-
80+
8181
let content: string;
82-
82+
8383
try {
8484
if (isRemoteUrl) {
8585
// Convert GitHub URLs to raw URLs for direct file access
8686
let fetchUrl = _filePath;
8787
if (_filePath.includes('github.com') && _filePath.includes('/blob/')) {
8888
fetchUrl = _filePath.replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/');
8989
}
90-
90+
9191
// Fetch remote file content
9292
console.log(`Fetching remote file: ${fetchUrl}`);
9393
const response = await fetch(fetchUrl);
@@ -177,6 +177,15 @@ const agentFilesMapper: Record<string, (agentKeys: string[]) => Record<string, s
177177
]
178178
}), {})
179179
},
180+
'langgraph-typescript': (agentKeys: string[]) => {
181+
return agentKeys.reduce((acc, agentId) => ({
182+
...acc,
183+
[agentId]: [
184+
path.join(__dirname, integrationsFolderPath, `/langgraph/examples/python/agents/${agentId}/agent.py`),
185+
path.join(__dirname, integrationsFolderPath, `/langgraph/examples/typescript/src/agents/${agentId}/agent.ts`)
186+
]
187+
}), {})
188+
},
180189
'langgraph-fastapi': (agentKeys: string[]) => {
181190
return agentKeys.reduce((acc, agentId) => ({
182191
...acc,
@@ -228,6 +237,6 @@ async function runGenerateContent() {
228237
path.join(__dirname, "../src/files.json"),
229238
JSON.stringify(result, null, 2)
230239
);
231-
240+
232241
console.log("Successfully generated src/files.json");
233242
})();

typescript-sdk/apps/dojo/scripts/prep-dojo-everything.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ const crewai = {
6161
const langgraphFastapi = {
6262
command: 'poetry install',
6363
name: 'LG FastAPI',
64-
cwd: path.join(integrationsRoot, 'langgraph/python/ag_ui_langgraph/examples'),
64+
cwd: path.join(integrationsRoot, 'langgraph/examples/python'),
65+
env: {
66+
POETRY_VIRTUALENVS_IN_PROJECT: "false"
67+
}
6568
}
6669

6770
// Langgraph (Platorm {typescript})
@@ -115,7 +118,7 @@ async function main() {
115118
serverStarterAllFeatures,
116119
agno,
117120
crewai,
118-
// langgraphFastapi, // Disabled until build fixes
121+
langgraphFastapi,
119122
langgraphPlatformTypescript,
120123
llamaIndex,
121124
mastra,

typescript-sdk/apps/dojo/scripts/run-dojo-everything.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ const crewai = {
6363
const langgraphFastapi = {
6464
command: 'poetry run dev',
6565
name: 'LG FastAPI',
66-
cwd: path.join(integrationsRoot, 'langgraph/python/ag_ui_langgraph/examples'),
67-
env: {PORT: 8004},
66+
cwd: path.join(integrationsRoot, 'langgraph/examples/python'),
67+
env: {
68+
PORT: 8004,
69+
POETRY_VIRTUALENVS_IN_PROJECT: "false"
70+
},
6871
}
6972

7073
// Langgraph (Platform {python})
@@ -119,10 +122,8 @@ const dojo = {
119122
AGNO_URL: 'http://localhost:8002',
120123
CREW_AI_URL: 'http://localhost:8003',
121124
LANGGRAPH_FAST_API_URL: 'http://localhost:8004',
122-
// TODO: Move this to run 2 platforms for testing.
123-
LANGGRAPH_URL: 'http://localhost:8005',
124-
// LANGGRAPH_PLATFORM_PYTHON_URL: 'http://localhost:8005',
125-
// LANGGRAPH_PLATFORM_TYPESCRIPT_URL: 'http://localhost:8006',
125+
LANGGRAPH_PYTHON_URL: 'http://localhost:8005',
126+
LANGGRAPH_TYPESCRIPT_URL: 'http://localhost:8006',
126127
LLAMA_INDEX_URL: 'http://localhost:8007',
127128
MASTRA_URL: 'http://localhost:8008',
128129
PYDANTIC_AI_URL: 'http://localhost:8009',
@@ -135,9 +136,8 @@ const procs = [
135136
serverStarterAllFeatures,
136137
agno,
137138
crewai,
138-
// langgraphFastapi, // Disabled until it runs
139+
langgraphFastapi,
139140
langgraphPlatformPython,
140-
// TODO: Also run the typescript version of langgraph.
141141
langgraphPlatformTypescript,
142142
llamaIndex,
143143
mastra,

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

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,29 +115,32 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
115115
agents: async () => {
116116
return {
117117
agentic_chat: new LangGraphAgent({
118-
deploymentUrl: envVars.langgraphUrl,
118+
deploymentUrl: envVars.langgraphPythonUrl,
119119
graphId: "agentic_chat",
120120
}),
121121
agentic_generative_ui: new LangGraphAgent({
122-
deploymentUrl: envVars.langgraphUrl,
122+
deploymentUrl: envVars.langgraphPythonUrl,
123123
graphId: "agentic_generative_ui",
124124
}),
125125
human_in_the_loop: new LangGraphAgent({
126-
deploymentUrl: envVars.langgraphUrl,
126+
deploymentUrl: envVars.langgraphPythonUrl,
127127
graphId: "human_in_the_loop",
128128
}),
129129
predictive_state_updates: new LangGraphAgent({
130-
deploymentUrl: envVars.langgraphUrl,
130+
deploymentUrl: envVars.langgraphPythonUrl,
131131
graphId: "predictive_state_updates",
132132
}),
133133
shared_state: new LangGraphAgent({
134-
deploymentUrl: envVars.langgraphUrl,
134+
deploymentUrl: envVars.langgraphPythonUrl,
135135
graphId: "shared_state",
136136
}),
137137
tool_based_generative_ui: new LangGraphAgent({
138-
deploymentUrl: envVars.langgraphUrl,
138+
deploymentUrl: envVars.langgraphPythonUrl,
139139
graphId: "tool_based_generative_ui",
140140
}),
141+
agentic_chat_reasoning: new LangGraphHttpAgent({
142+
url: `${envVars.langgraphPythonUrl}/agent/agentic_chat_reasoning`,
143+
}),
141144
};
142145
},
143146
},
@@ -164,11 +167,42 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
164167
url: `${envVars.langgraphFastApiUrl}/agent/tool_based_generative_ui`,
165168
}),
166169
agentic_chat_reasoning: new LangGraphHttpAgent({
167-
url: "http://localhost:8000/agent/agentic_chat_reasoning",
170+
url: `${envVars.langgraphFastApiUrl}/agent/agentic_chat_reasoning`,
168171
}),
169172
};
170173
},
171174
},
175+
{
176+
id: "langgraph-typescript",
177+
agents: async () => {
178+
return {
179+
agentic_chat: new LangGraphAgent({
180+
deploymentUrl: envVars.langgraphTypescriptUrl,
181+
graphId: "agentic_chat",
182+
}),
183+
agentic_generative_ui: new LangGraphAgent({
184+
deploymentUrl: envVars.langgraphTypescriptUrl,
185+
graphId: "agentic_generative_ui",
186+
}),
187+
human_in_the_loop: new LangGraphAgent({
188+
deploymentUrl: envVars.langgraphTypescriptUrl,
189+
graphId: "human_in_the_loop",
190+
}),
191+
predictive_state_updates: new LangGraphAgent({
192+
deploymentUrl: envVars.langgraphTypescriptUrl,
193+
graphId: "predictive_state_updates",
194+
}),
195+
shared_state: new LangGraphAgent({
196+
deploymentUrl: envVars.langgraphTypescriptUrl,
197+
graphId: "shared_state",
198+
}),
199+
tool_based_generative_ui: new LangGraphAgent({
200+
deploymentUrl: envVars.langgraphTypescriptUrl,
201+
graphId: "tool_based_generative_ui",
202+
})
203+
};
204+
},
205+
},
172206
{
173207
id: "agno",
174208
agents: async () => {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ type envVars = {
22
serverStarterUrl: string;
33
serverStarterAllFeaturesUrl: string;
44
mastraUrl: string;
5-
langgraphUrl: string;
5+
langgraphPythonUrl: string;
66
langgraphFastApiUrl: string;
7+
langgraphTypescriptUrl: string;
78
agnoUrl: string;
89
llamaIndexUrl: string;
910
crewAiUrl: string;
@@ -24,8 +25,9 @@ export default function getEnvVars(): envVars {
2425
serverStarterUrl: process.env.SERVER_STARTER_URL || 'http://localhost:8000',
2526
serverStarterAllFeaturesUrl: process.env.SERVER_STARTER_ALL_FEATURES_URL || 'http://localhost:8000',
2627
mastraUrl: process.env.MASTRA_URL || 'http://localhost:4111',
27-
langgraphUrl: process.env.LANGGRAPH_URL || 'http://localhost:2024',
28+
langgraphPythonUrl: process.env.LANGGRAPH_PYTHON_URL || 'http://localhost:2024',
2829
langgraphFastApiUrl: process.env.LANGGRAPH_FAST_API_URL || 'http://localhost:8000',
30+
langgraphTypescriptUrl: process.env.LANGGRAPH_TYPESCRIPT_URL || 'http://localhost:8000',
2931
agnoUrl: process.env.AGNO_URL || 'http://localhost:9001',
3032
llamaIndexUrl: process.env.LLAMA_INDEX_URL || 'http://localhost:9000',
3133
crewAiUrl: process.env.CREW_AI_URL || 'http://localhost:9002',

0 commit comments

Comments
 (0)