Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test, expect } from '@playwright/test';

test('renders initial message', async ({ page }) => {
await page.goto('http://localhost:9999/langgraph-fastapi/feature/agentic_chat');

await expect(page.getByText('Hi, I\'m an agent. Want to chat?')).toBeVisible();
});

test('responds to user message', async ({ page }) => {
await page.goto('http://localhost:9999/langgraph-fastapi/feature/agentic_chat');

const textarea = page.getByPlaceholder('Type a message...');
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.');
await page.keyboard.press('Enter');

page.locator('.copilotKitInputControls button.copilotKitInputControlButton').click();

await expect(page.locator('.copilotKitMessage')).toHaveCount(3);
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage')).toHaveCount(2);
await expect(page.locator('.copilotKitMessage.copilotKitUserMessage')).toHaveCount(1);
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage').last()).toHaveText('four', { ignoreCase: true });
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test, expect } from '@playwright/test';

test('renders initial message', async ({ page }) => {
await page.goto('http://localhost:9999/langgraph-typescript/feature/agentic_chat');

await expect(page.getByText('Hi, I\'m an agent. Want to chat?')).toBeVisible();
});

test('responds to user message', async ({ page }) => {
await page.goto('http://localhost:9999/langgraph-typescript/feature/agentic_chat');

const textarea = page.getByPlaceholder('Type a message...');
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.');
await page.keyboard.press('Enter');

page.locator('.copilotKitInputControls button.copilotKitInputControlButton').click();

await expect(page.locator('.copilotKitMessage')).toHaveCount(3);
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage')).toHaveCount(2);
await expect(page.locator('.copilotKitMessage.copilotKitUserMessage')).toHaveCount(1);
await expect(page.locator('.copilotKitMessage.copilotKitAssistantMessage').last()).toHaveText('four', { ignoreCase: true });
});
45 changes: 27 additions & 18 deletions typescript-sdk/apps/dojo/scripts/generate-content-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@ import path from "path";
function parseAgentsFile(): Array<{id: string, agentKeys: string[]}> {
const agentsFilePath = path.join(__dirname, '../src/agents.ts');
const agentsContent = fs.readFileSync(agentsFilePath, 'utf8');

const agentConfigs: Array<{id: string, agentKeys: string[]}> = [];

// Split the content to process each agent configuration individually
const agentBlocks = agentsContent.split(/(?=\s*{\s*id:\s*["'])/);

for (const block of agentBlocks) {
// Extract the ID
const idMatch = block.match(/id:\s*["']([^"']+)["']/);
if (!idMatch) continue;

const id = idMatch[1];

// Find the return object by looking for the pattern and then manually parsing balanced braces
const returnMatch = block.match(/agents:\s*async\s*\(\)\s*=>\s*{\s*return\s*{/);
if (!returnMatch) continue;

const startIndex = returnMatch.index! + returnMatch[0].length;
const returnObjectContent = extractBalancedBraces(block, startIndex);


// Extract keys from the return object - only capture keys that are followed by a colon and then 'new'
// This ensures we only get the top-level keys like "agentic_chat: new ..." not nested keys like "url: ..."
const keyRegex = /^\s*(\w+):\s*new\s+\w+/gm;
Expand All @@ -34,18 +34,18 @@ function parseAgentsFile(): Array<{id: string, agentKeys: string[]}> {
while ((keyMatch = keyRegex.exec(returnObjectContent)) !== null) {
keys.push(keyMatch[1]);
}

agentConfigs.push({ id, agentKeys: keys });
}

return agentConfigs;
}

// Helper function to extract content between balanced braces
function extractBalancedBraces(text: string, startIndex: number): string {
let braceCount = 0;
let i = startIndex;

while (i < text.length) {
if (text[i] === '{') {
braceCount++;
Expand All @@ -58,7 +58,7 @@ function extractBalancedBraces(text: string, startIndex: number): string {
}
i++;
}

return '';
}

Expand All @@ -71,23 +71,23 @@ async function getFile(_filePath: string | undefined, _fileName?: string) {
console.warn(`File path is undefined, skipping.`);
return {}
}

const fileName = _fileName ?? _filePath.split('/').pop() ?? ''
const filePath = _fileName ? path.join(_filePath, fileName) : _filePath;

// Check if it's a remote URL
const isRemoteUrl = _filePath.startsWith('http://') || _filePath.startsWith('https://');

let content: string;

try {
if (isRemoteUrl) {
// Convert GitHub URLs to raw URLs for direct file access
let fetchUrl = _filePath;
if (_filePath.includes('github.com') && _filePath.includes('/blob/')) {
fetchUrl = _filePath.replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/');
}

// Fetch remote file content
console.log(`Fetching remote file: ${fetchUrl}`);
const response = await fetch(fetchUrl);
Expand Down Expand Up @@ -177,6 +177,15 @@ const agentFilesMapper: Record<string, (agentKeys: string[]) => Record<string, s
]
}), {})
},
'langgraph-typescript': (agentKeys: string[]) => {
return agentKeys.reduce((acc, agentId) => ({
...acc,
[agentId]: [
path.join(__dirname, integrationsFolderPath, `/langgraph/examples/python/agents/${agentId}/agent.py`),
path.join(__dirname, integrationsFolderPath, `/langgraph/examples/typescript/src/agents/${agentId}/agent.ts`)
]
}), {})
},
'langgraph-fastapi': (agentKeys: string[]) => {
return agentKeys.reduce((acc, agentId) => ({
...acc,
Expand Down Expand Up @@ -228,6 +237,6 @@ async function runGenerateContent() {
path.join(__dirname, "../src/files.json"),
JSON.stringify(result, null, 2)
);

console.log("Successfully generated src/files.json");
})();
7 changes: 5 additions & 2 deletions typescript-sdk/apps/dojo/scripts/prep-dojo-everything.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ const crewai = {
const langgraphFastapi = {
command: 'poetry install',
name: 'LG FastAPI',
cwd: path.join(integrationsRoot, 'langgraph/python/ag_ui_langgraph/examples'),
cwd: path.join(integrationsRoot, 'langgraph/examples/python'),
env: {
POETRY_VIRTUALENVS_IN_PROJECT: "false"
}
}

// Langgraph (Platorm {typescript})
Expand Down Expand Up @@ -115,7 +118,7 @@ async function main() {
serverStarterAllFeatures,
agno,
crewai,
// langgraphFastapi, // Disabled until build fixes
langgraphFastapi,
langgraphPlatformTypescript,
llamaIndex,
mastra,
Expand Down
16 changes: 8 additions & 8 deletions typescript-sdk/apps/dojo/scripts/run-dojo-everything.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,11 @@ const crewai = {
const langgraphFastapi = {
command: 'poetry run dev',
name: 'LG FastAPI',
cwd: path.join(integrationsRoot, 'langgraph/python/ag_ui_langgraph/examples'),
env: {PORT: 8004},
cwd: path.join(integrationsRoot, 'langgraph/examples/python'),
env: {
PORT: 8004,
POETRY_VIRTUALENVS_IN_PROJECT: "false"
},
}

// Langgraph (Platform {python})
Expand Down Expand Up @@ -119,10 +122,8 @@ const dojo = {
AGNO_URL: 'http://localhost:8002',
CREW_AI_URL: 'http://localhost:8003',
LANGGRAPH_FAST_API_URL: 'http://localhost:8004',
// TODO: Move this to run 2 platforms for testing.
LANGGRAPH_URL: 'http://localhost:8005',
// LANGGRAPH_PLATFORM_PYTHON_URL: 'http://localhost:8005',
// LANGGRAPH_PLATFORM_TYPESCRIPT_URL: 'http://localhost:8006',
LANGGRAPH_PYTHON_URL: 'http://localhost:8005',
LANGGRAPH_TYPESCRIPT_URL: 'http://localhost:8006',
LLAMA_INDEX_URL: 'http://localhost:8007',
MASTRA_URL: 'http://localhost:8008',
PYDANTIC_AI_URL: 'http://localhost:8009',
Expand All @@ -135,9 +136,8 @@ const procs = [
serverStarterAllFeatures,
agno,
crewai,
// langgraphFastapi, // Disabled until it runs
langgraphFastapi,
langgraphPlatformPython,
// TODO: Also run the typescript version of langgraph.
langgraphPlatformTypescript,
llamaIndex,
mastra,
Expand Down
48 changes: 41 additions & 7 deletions typescript-sdk/apps/dojo/src/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,32 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
agents: async () => {
return {
agentic_chat: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "agentic_chat",
}),
agentic_generative_ui: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "agentic_generative_ui",
}),
human_in_the_loop: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "human_in_the_loop",
}),
predictive_state_updates: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "predictive_state_updates",
}),
shared_state: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "shared_state",
}),
tool_based_generative_ui: new LangGraphAgent({
deploymentUrl: envVars.langgraphUrl,
deploymentUrl: envVars.langgraphPythonUrl,
graphId: "tool_based_generative_ui",
}),
agentic_chat_reasoning: new LangGraphHttpAgent({
url: `${envVars.langgraphPythonUrl}/agent/agentic_chat_reasoning`,
}),
};
},
},
Expand All @@ -164,11 +167,42 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
url: `${envVars.langgraphFastApiUrl}/agent/tool_based_generative_ui`,
}),
agentic_chat_reasoning: new LangGraphHttpAgent({
url: "http://localhost:8000/agent/agentic_chat_reasoning",
url: `${envVars.langgraphFastApiUrl}/agent/agentic_chat_reasoning`,
}),
};
},
},
{
id: "langgraph-typescript",
agents: async () => {
return {
agentic_chat: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "agentic_chat",
}),
agentic_generative_ui: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "agentic_generative_ui",
}),
human_in_the_loop: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "human_in_the_loop",
}),
predictive_state_updates: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "predictive_state_updates",
}),
shared_state: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "shared_state",
}),
tool_based_generative_ui: new LangGraphAgent({
deploymentUrl: envVars.langgraphTypescriptUrl,
graphId: "tool_based_generative_ui",
})
};
},
},
{
id: "agno",
agents: async () => {
Expand Down
6 changes: 4 additions & 2 deletions typescript-sdk/apps/dojo/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ type envVars = {
serverStarterUrl: string;
serverStarterAllFeaturesUrl: string;
mastraUrl: string;
langgraphUrl: string;
langgraphPythonUrl: string;
langgraphFastApiUrl: string;
langgraphTypescriptUrl: string;
agnoUrl: string;
llamaIndexUrl: string;
crewAiUrl: string;
Expand All @@ -24,8 +25,9 @@ export default function getEnvVars(): envVars {
serverStarterUrl: process.env.SERVER_STARTER_URL || 'http://localhost:8000',
serverStarterAllFeaturesUrl: process.env.SERVER_STARTER_ALL_FEATURES_URL || 'http://localhost:8000',
mastraUrl: process.env.MASTRA_URL || 'http://localhost:4111',
langgraphUrl: process.env.LANGGRAPH_URL || 'http://localhost:2024',
langgraphPythonUrl: process.env.LANGGRAPH_PYTHON_URL || 'http://localhost:2024',
langgraphFastApiUrl: process.env.LANGGRAPH_FAST_API_URL || 'http://localhost:8000',
langgraphTypescriptUrl: process.env.LANGGRAPH_TYPESCRIPT_URL || 'http://localhost:8000',
agnoUrl: process.env.AGNO_URL || 'http://localhost:9001',
llamaIndexUrl: process.env.LLAMA_INDEX_URL || 'http://localhost:9000',
crewAiUrl: process.env.CREW_AI_URL || 'http://localhost:9002',
Expand Down
Loading