Skip to content
Open
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
3 changes: 2 additions & 1 deletion apps/agent/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

from src.query import query_data
from src.todos import AgentState, todo_tools
from src.form import generate_form

agent = create_agent(
model=ChatOpenAI(model="gpt-5-mini", reasoning={"effort": "low", "summary": "concise"}),
tools=[query_data, *todo_tools],
tools=[query_data, *todo_tools, generate_form],
middleware=[CopilotKitMiddleware()],
state_schema=AgentState,
system_prompt="""
Expand Down
191 changes: 191 additions & 0 deletions apps/agent/src/form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import json
from langchain.tools import tool

@tool
def generate_form() -> str:
"""
Generates a login form for the user to sign in.
"""
components = [
{
"id": "root",
"component": {
"Card": {
"child": "main-column"
}
}
},
{
"id": "main-column",
"component": {
"Column": {
"children": {
"explicitList": [
"header",
"email-field",
"password-field",
"login-btn",
"divider",
"signup-text"
]
},
"gap": "medium"
}
}
},
{
"id": "header",
"component": {
"Column": {
"children": {
"explicitList": [
"title",
"subtitle"
]
},
"alignment": "center"
}
}
},
{
"id": "title",
"component": {
"Text": {
"text": {
"literalString": "Welcome back"
},
"usageHint": "h2"
}
}
},
{
"id": "subtitle",
"component": {
"Text": {
"text": {
"literalString": "Sign in to your account"
},
"usageHint": "caption"
}
}
},
{
"id": "email-field",
"component": {
"TextField": {
"value": {
"path": "/email"
},
"placeholder": {
"literalString": "Email address"
},
"label": {
"literalString": "Email"
},
"action": "updateEmail"
}
}
},
{
"id": "password-field",
"component": {
"TextField": {
"value": {
"path": "/password"
},
"placeholder": {
"literalString": "Password"
},
"label": {
"literalString": "Password"
},
"action": "updatePassword"
}
}
},
{
"id": "login-btn-text",
"component": {
"Text": {
"text": {
"literalString": "Sign in"
}
}
}
},
{
"id": "login-btn",
"component": {
"Button": {
"child": "login-btn-text",
"action": "login"
}
}
},
{
"id": "divider",
"component": {
"Divider": {}
}
},
{
"id": "signup-text",
"component": {
"Row": {
"children": {
"explicitList": [
"no-account",
"signup-link"
]
},
"distribution": "center",
"gap": "small"
}
}
},
{
"id": "no-account",
"component": {
"Text": {
"text": {
"literalString": "Don't have an account?"
},
"usageHint": "caption"
}
}
},
{
"id": "signup-link-text",
"component": {
"Text": {
"text": {
"literalString": "Sign up"
}
}
}
},
{
"id": "signup-link",
"component": {
"Button": {
"child": "signup-link-text",
"action": "signup"
}
}
}
]

return json.dumps([
{
"surfaceUpdate": {
"surfaceId": "login-form",
"components": components
}
},
{
"beginRendering": {
"surfaceId": "login-form",
"root": "root"
}
}
])
8 changes: 5 additions & 3 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"lint": "eslint ."
},
"dependencies": {
"@ag-ui/a2ui-middleware": "^0.0.2",
"@ag-ui/mcp-apps-middleware": "^0.0.3",
"@copilotkit/react-core": "1.52.0-next.6",
"@copilotkit/react-ui": "1.52.0-next.6",
"@copilotkit/runtime": "1.52.0-next.6",
"@copilotkit/a2ui-renderer": "^1.52.1",
"@copilotkit/react-core": "1.52.1",
"@copilotkit/react-ui": "1.52.1",
"@copilotkit/runtime": "1.52.1",
Comment on lines +14 to +17
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely needs updating to w/e version fixes the other issues

"next": "16.1.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
Expand Down
24 changes: 13 additions & 11 deletions apps/app/src/app/api/copilotkit/ag-ui-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
import { A2UIMiddleware } from "@ag-ui/a2ui-middleware";
//import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";

export const aguiMiddleware = [
new MCPAppsMiddleware({
mcpServers: [
{
type: "http",
url:
process.env.MCP_SERVER_URL ||"https://mcp.excalidraw.com",
serverId: "example_mcp_app",
},
],
}),
// new MCPAppsMiddleware({
// mcpServers: [
// {
// type: "http",
// url:
// process.env.MCP_SERVER_URL || "https://mcp.excalidraw.com",
// serverId: "example_mcp_app",
// },
// ],
// }),
Comment on lines +5 to +14
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the fix to multiple middlewares this will allow us to uncomment this out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also use the new runtime properties for this instead of the middlewares at all.

new A2UIMiddleware(),
];
8 changes: 7 additions & 1 deletion apps/app/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { CopilotKit } from "@copilotkit/react-core";
import "@copilotkit/react-core/v2/styles.css";
import { ThemeProvider } from "@/hooks/use-theme";

import { createA2UIMessageRenderer } from "@copilotkit/a2ui-renderer";
import { theme } from "@/lib/a2ui-theme.css";

const A2UIMessageRenderer = createA2UIMessageRenderer({ theme });
const activityRenderers = [A2UIMessageRenderer];
Comment on lines +9 to +13
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we need none of this code and it is instead hot-swappable. The default should be A2UI "just works" if your agent returns it. The middleware takes care of most of this, if we add that into runtime it'll just work by default.

The other end is the UI, if we make this the default (with a disable) then things become quite simple.


export default function RootLayout({
children,
}: Readonly<{
Expand All @@ -15,7 +21,7 @@ export default function RootLayout({
<html lang="en">
<body className={`antialiased`}>
<ThemeProvider>
<CopilotKit runtimeUrl="/api/copilotkit">{children}</CopilotKit>
<CopilotKit runtimeUrl="/api/copilotkit" renderActivityMessages={activityRenderers}>{children}</CopilotKit>
</ThemeProvider>
</body>
</html>
Expand Down
Loading
Loading