diff --git a/typescript-sdk/apps/dojo/package.json b/typescript-sdk/apps/dojo/package.json
index 50b90a16..5efc52ab 100644
--- a/typescript-sdk/apps/dojo/package.json
+++ b/typescript-sdk/apps/dojo/package.json
@@ -14,6 +14,7 @@
"@ag-ui/llamaindex": "workspace:*",
"@ag-ui/mastra": "workspace:*",
"@ag-ui/middleware-starter": "workspace:*",
+ "@ag-ui/pydantic-ai": "workspace:*",
"@ag-ui/server-starter": "workspace:*",
"@ag-ui/server-starter-all-features": "workspace:*",
"@ag-ui/vercel-ai-sdk": "workspace:*",
diff --git a/typescript-sdk/apps/dojo/src/agents.ts b/typescript-sdk/apps/dojo/src/agents.ts
index 0222e59c..b3437a94 100644
--- a/typescript-sdk/apps/dojo/src/agents.ts
+++ b/typescript-sdk/apps/dojo/src/agents.ts
@@ -10,6 +10,7 @@ import { LangGraphAgent } from "@ag-ui/langgraph";
import { AgnoAgent } from "@ag-ui/agno";
import { LlamaIndexAgent } from "@ag-ui/llamaindex";
import { CrewAIAgent } from "@ag-ui/crewai";
+import { PydanticAIAgent } from "@ag-ui/pydantic-ai";
export const agentsIntegrations: AgentIntegrationConfig[] = [
{
@@ -20,6 +21,31 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
};
},
},
+ {
+ id: "pydantic-ai",
+ agents: async () => {
+ return {
+ agentic_chat: new PydanticAIAgent({
+ url: "http://localhost:9000/agentic_chat",
+ }),
+ agentic_generative_ui: new PydanticAIAgent({
+ url: "http://localhost:9000/agentic_generative_ui",
+ }),
+ human_in_the_loop: new PydanticAIAgent({
+ url: "http://localhost:9000/human_in_the_loop",
+ }),
+ predictive_state_updates: new PydanticAIAgent({
+ url: "http://localhost:9000/predictive_state_updates",
+ }),
+ shared_state: new PydanticAIAgent({
+ url: "http://localhost:9000/shared_state",
+ }),
+ tool_based_generative_ui: new PydanticAIAgent({
+ url: "http://localhost:9000/tool_based_generative_ui",
+ }),
+ };
+ },
+ },
{
id: "server-starter",
agents: async () => {
diff --git a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_chat/page.tsx b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_chat/page.tsx
index 164bc489..1eccbd55 100644
--- a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_chat/page.tsx
+++ b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_chat/page.tsx
@@ -70,6 +70,10 @@ const Chat = () => {
],
handler: ({ background }) => {
setBackground(background);
+ return {
+ status: "success",
+ message: `Background changed to ${background}`,
+ };
},
});
diff --git a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_generative_ui/page.tsx b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_generative_ui/page.tsx
index 120e7223..c44cd0b1 100644
--- a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_generative_ui/page.tsx
+++ b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_generative_ui/page.tsx
@@ -42,7 +42,7 @@ const Chat = () => {
return (
-
+
{state.steps.map((step, index) => {
if (step.status === "completed") {
return (
@@ -55,7 +55,7 @@ const Chat = () => {
index === state.steps.findIndex((s) => s.status === "pending")
) {
return (
-
+
{step.description}
diff --git a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/human_in_the_loop/page.tsx b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/human_in_the_loop/page.tsx
index 5b88a130..0b674d10 100644
--- a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/human_in_the_loop/page.tsx
+++ b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/human_in_the_loop/page.tsx
@@ -99,6 +99,7 @@ const Chat = () => {
});
useCopilotAction({
name: "generate_task_steps",
+ description: "Generates a list of steps for the user to perform",
parameters: [
{
name: "steps",
diff --git a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/predictive_state_updates/page.tsx b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/predictive_state_updates/page.tsx
index 78e95c5e..c96f1e95 100644
--- a/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/predictive_state_updates/page.tsx
+++ b/typescript-sdk/apps/dojo/src/app/[integrationId]/feature/predictive_state_updates/page.tsx
@@ -128,23 +128,36 @@ const DocumentEditor = () => {
}, [text]);
useCopilotAction({
- name: "confirm_changes",
- renderAndWaitForResponse: ({ args, respond, status }) => (
-
{
- editor?.commands.setContent(fromMarkdown(currentDocument));
- setAgentState({ document: currentDocument });
- }}
- onConfirm={() => {
- editor?.commands.setContent(fromMarkdown(agentState?.document || ""));
- setCurrentDocument(agentState?.document || "");
- setAgentState({ document: agentState?.document || "" });
- }}
- />
- ),
+ name: "write_document",
+ description: `Present the proposed changes to the user for review`,
+ parameters: [
+ {
+ name: "document",
+ type: "string",
+ description: "The full updated document in markdown format",
+ },
+ ],
+ renderAndWaitForResponse({ args, status, respond }) {
+ if (status === "executing") {
+ return (
+ {
+ editor?.commands.setContent(fromMarkdown(currentDocument));
+ setAgentState({ document: currentDocument });
+ }}
+ onConfirm={() => {
+ editor?.commands.setContent(fromMarkdown(agentState?.document || ""));
+ setCurrentDocument(agentState?.document || "");
+ setAgentState({ document: agentState?.document || "" });
+ }}
+ />
+ );
+ }
+ return <>>;
+ },
});
return (
diff --git a/typescript-sdk/apps/dojo/src/config.ts b/typescript-sdk/apps/dojo/src/config.ts
index 14a90fa6..64b71921 100644
--- a/typescript-sdk/apps/dojo/src/config.ts
+++ b/typescript-sdk/apps/dojo/src/config.ts
@@ -23,12 +23,6 @@ export const featureConfig: FeatureConfig[] = [
description: "Chat with your Copilot and call frontend tools",
tags: ["Chat", "Tools", "Streaming"],
}),
- createFeatureConfig({
- id: "human_in_the_loop",
- name: "Human in the loop",
- description: "Plan a task together and direct the Copilot to take the right steps",
- tags: ["HITL", "Interactivity"],
- }),
createFeatureConfig({
id: "agentic_generative_ui",
name: "Agentic Generative UI",
@@ -36,10 +30,16 @@ export const featureConfig: FeatureConfig[] = [
tags: ["Generative ui (agent)", "Long running task"],
}),
createFeatureConfig({
- id: "tool_based_generative_ui",
- name: "Tool Based Generative UI",
- description: "Haiku generator that uses tool based generative UI.",
- tags: ["Generative ui (action)", "Tools"],
+ id: "human_in_the_loop",
+ name: "Human in the loop",
+ description: "Plan a task together and direct the Copilot to take the right steps",
+ tags: ["HITL", "Interactivity"],
+ }),
+ createFeatureConfig({
+ id: "predictive_state_updates",
+ name: "Predictive State Updates",
+ description: "Use collaboration to edit a document in real time with your Copilot",
+ tags: ["State", "Streaming", "Tools"],
}),
createFeatureConfig({
id: "shared_state",
@@ -48,10 +48,10 @@ export const featureConfig: FeatureConfig[] = [
tags: ["Agent State", "Collaborating"],
}),
createFeatureConfig({
- id: "predictive_state_updates",
- name: "Predictive State Updates",
- description: "Use collaboration to edit a document in real time with your Copilot",
- tags: ["State", "Streaming", "Tools"],
+ id: "tool_based_generative_ui",
+ name: "Tool Based Generative UI",
+ description: "Haiku generator that uses tool based generative UI.",
+ tags: ["Generative ui (action)", "Tools"],
}),
];
diff --git a/typescript-sdk/apps/dojo/src/menu.ts b/typescript-sdk/apps/dojo/src/menu.ts
index b9060d6d..3f73ba8f 100644
--- a/typescript-sdk/apps/dojo/src/menu.ts
+++ b/typescript-sdk/apps/dojo/src/menu.ts
@@ -6,6 +6,18 @@ export const menuIntegrations: MenuIntegrationConfig[] = [
name: "Middleware Starter",
features: ["agentic_chat"],
},
+ {
+ id: "pydantic-ai",
+ name: "Pydantic AI",
+ features: [
+ "agentic_chat",
+ "human_in_the_loop",
+ "agentic_generative_ui",
+ "tool_based_generative_ui",
+ "shared_state",
+ "predictive_state_updates",
+ ],
+ },
{
id: "server-starter",
name: "Server Starter",
diff --git a/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py
index 325f0014..ffb10570 100644
--- a/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py
+++ b/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py
@@ -127,22 +127,9 @@ async def chat_node(state: AgentState, config: RunnableConfig):
"content": "Document written.",
"tool_call_id": tool_call_id
}
-
- # Add confirmation tool call
- confirm_tool_call = {
- "role": "assistant",
- "content": "",
- "tool_calls": [{
- "id": str(uuid.uuid4()),
- "function": {
- "name": "confirm_changes",
- "arguments": "{}"
- }
- }]
- }
-
- messages = messages + [tool_response, confirm_tool_call]
-
+
+ messages = messages + [tool_response]
+
# Return Command to route to end
return Command(
goto=END,
diff --git a/typescript-sdk/integrations/pydantic-ai/.env-sample b/typescript-sdk/integrations/pydantic-ai/.env-sample
new file mode 100644
index 00000000..6d5290d1
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/.env-sample
@@ -0,0 +1,4 @@
+## OpenAI API Settings
+# Get your Open AI API Key by following these instructions -
+# https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key
+OPENAI_API_KEY="sk-proj-...."
diff --git a/typescript-sdk/integrations/pydantic-ai/.npmignore b/typescript-sdk/integrations/pydantic-ai/.npmignore
new file mode 100644
index 00000000..aaacf159
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/.npmignore
@@ -0,0 +1,12 @@
+.turbo
+.DS_Store
+.git
+.gitignore
+.idea
+.vscode
+.env
+__tests__
+src
+tsup.config.ts
+tsconfig.json
+jest.config.js
diff --git a/typescript-sdk/integrations/pydantic-ai/README.md b/typescript-sdk/integrations/pydantic-ai/README.md
new file mode 100644
index 00000000..099f8aa5
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/README.md
@@ -0,0 +1,163 @@
+# PydanticAI
+
+Implementation of the AG-UI protocol for PydanticAI.
+
+## Prerequisites
+
+This example uses a PydanticAI agent using an OpenAI model and the AG-UI dojo.
+
+1. An [OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key)
+2. A clone of the [AG-UI protocol repository](https://github.com/ag-ui-protocol/ag-ui)
+
+## Running
+
+To run this integration you need to:
+
+1. Make a copy of `.env-sample` as `.env` in the `typescript-sdk/integrations/pydantic-ai` directory
+2. Open it in your editor and set `OPENAI_API_KEY` to a valid OpenAI key
+3. Open terminal in the `typescript-sdk/integrations/pydantic-ai` of the `ag-ui` repo
+4. Install the `pydantic-ai-examples` package, for example:
+
+ ```shell
+ pip install pydantic-ai-examples
+ ```
+
+ or:
+
+ ```shell
+ uv venv
+ uv add pydantic-ai-examples
+ ```
+
+5. Run the example dojo server
+
+ ```shell
+ python -m pydantic_ai_ag_ui_examples.dojo_server
+ ```
+
+6. Open another terminal in root directory of the `ag-ui` repository clone
+7. Start the integration ag-ui dojo:
+
+ ```shell
+ cd typescript-sdk
+ pnpm install && pnpm run dev
+ ```
+
+8. Finally visit [http://localhost:3000/pydantic-ai](http://localhost:3000/pydantic-ai)
+
+## Feature Demos
+
+### [Agentic Chat](http://localhost:3000/pydantic-ai/feature/agentic_chat)
+
+This demonstrates a basic agent interaction including PydanticAI server side
+tools and AG-UI client side tools.
+
+#### Agent Tools
+
+- `time` - PydanticAI tool to check the current time for a time zone
+- `background` - AG-UI tool to set the background color of the client window
+
+#### Agent Prompts
+
+```text
+What is the time in New York?
+```
+
+```text
+Change the background to blue
+```
+
+A complex example which mixes both AG-UI and PydanticAI tools:
+
+```text
+Perform the following steps, waiting for the response of each step before continuing:
+1. Get the time
+2. Set the background to red
+3. Get the time
+4. Report how long the background set took by diffing the two times
+```
+
+### [Agentic Generative UI](http://localhost:3000/pydantic-ai/feature/agentic_generative_ui)
+
+Demonstrates a long running task where the agent sends updates to the frontend
+to let the user know what's happening.
+
+#### Plan Prompts
+
+```text
+Create a plan for breakfast and execute it
+```
+
+### [Human in the Loop](http://localhost:3000/pydantic-ai/feature/human_in_the_loop)
+
+Demonstrates simple human in the loop workflow where the agent comes up with a
+plan and the user can approve it using checkboxes.
+
+#### Task Planning Tools
+
+- `generate_task_steps` - AG-UI tool to generate and confirm steps
+
+#### Task Planning Prompt
+
+```text
+Generate a list of steps for cleaning a car for me to review
+```
+
+### [Predictive State Updates](http://localhost:3000/pydantic-ai/feature/predictive_state_updates)
+
+Demonstrates how to use the predictive state updates feature to update the state
+of the UI based on agent responses, including user interaction via user
+confirmation.
+
+#### Story Tools
+
+- `write_document` - AG-UI tool to write the document to a window
+- `document_predict_state` - PydanticAI tool that enables document state
+ prediction for the `write_document` tool
+
+This also shows how to use custom instructions based on shared state information.
+
+#### Story Example
+
+Starting document text
+
+```markdown
+Bruce was a good dog,
+```
+
+Agent prompt
+
+```text
+Help me complete my story about bruce the dog, is should be no longer than a sentence.
+```
+
+### [Shared State](http://localhost:3000/pydantic-ai/feature/shared_state)
+
+Demonstrates how to use the shared state between the UI and the agent.
+
+State sent to the agent is detected by a function based instruction. This then
+validates the data using a custom pydantic model before using to create the
+instructions for the agent to follow and send to the client using a AG-UI tool.
+
+#### Recipe Tools
+
+- `display_recipe` - AG-UI tool to display the recipe in a graphical format
+
+#### Recipe Example
+
+1. Customise the basic settings of your recipe
+2. Click `Improve with AI`
+
+### [Tool Based Generative UI](http://localhost:3000/pydantic-ai/feature/tool_based_generative_ui)
+
+Demonstrates customised rendering for tool output with used confirmation.
+
+#### Haiku Tools
+
+- `generate_haiku` - AG-UI tool to display a haiku in English and Japanese
+
+#### Haiku Prompt
+
+```text
+Generate a haiku about formula 1
+```
diff --git a/typescript-sdk/integrations/pydantic-ai/jest.config.js b/typescript-sdk/integrations/pydantic-ai/jest.config.js
new file mode 100644
index 00000000..a0db5c6f
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/jest.config.js
@@ -0,0 +1,9 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+ preset: "ts-jest",
+ testEnvironment: "node",
+ testMatch: ["**/*.test.ts"],
+ moduleNameMapper: {
+ "^@/(.*)$": "/src/$1",
+ },
+};
diff --git a/typescript-sdk/integrations/pydantic-ai/package.json b/typescript-sdk/integrations/pydantic-ai/package.json
new file mode 100644
index 00000000..a5be4e33
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "@ag-ui/pydantic-ai",
+ "author": "Steven Hartland ",
+ "version": "0.0.1",
+ "main": "./dist/index.js",
+ "module": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
+ "sideEffects": false,
+ "files": [
+ "dist/**"
+ ],
+ "scripts": {
+ "build": "tsup",
+ "dev": "tsup --watch",
+ "clean": "rm -rf dist .turbo node_modules",
+ "typecheck": "tsc --noEmit",
+ "test": "jest",
+ "link:global": "pnpm link --global",
+ "unlink:global": "pnpm unlink --global"
+ },
+ "dependencies": {
+ "@ag-ui/client": "workspace:*"
+ },
+ "peerDependencies": {
+ "rxjs": "7.8.1"
+ },
+ "devDependencies": {
+ "@types/jest": "^29.5.14",
+ "@types/node": "^20.11.19",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.1.2",
+ "tsup": "^8.0.2",
+ "typescript": "^5.3.3"
+ }
+}
diff --git a/typescript-sdk/integrations/pydantic-ai/src/index.ts b/typescript-sdk/integrations/pydantic-ai/src/index.ts
new file mode 100644
index 00000000..f3a3190a
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/src/index.ts
@@ -0,0 +1,3 @@
+import { HttpAgent } from "@ag-ui/client";
+
+export class PydanticAIAgent extends HttpAgent {}
diff --git a/typescript-sdk/integrations/pydantic-ai/tsconfig.json b/typescript-sdk/integrations/pydantic-ai/tsconfig.json
new file mode 100644
index 00000000..d12ec063
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "target": "es2017",
+ "module": "esnext",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "moduleResolution": "node",
+ "skipLibCheck": true,
+ "strict": true,
+ "jsx": "react-jsx",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ },
+ "stripInternal": true
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/typescript-sdk/integrations/pydantic-ai/tsup.config.ts b/typescript-sdk/integrations/pydantic-ai/tsup.config.ts
new file mode 100644
index 00000000..12b69b8f
--- /dev/null
+++ b/typescript-sdk/integrations/pydantic-ai/tsup.config.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from "tsup";
+
+export default defineConfig({
+ entry: ["src/index.ts"],
+ format: ["cjs", "esm"],
+ dts: true,
+ splitting: false,
+ sourcemap: true,
+ clean: true,
+ minify: true,
+});
diff --git a/typescript-sdk/pnpm-lock.yaml b/typescript-sdk/pnpm-lock.yaml
index cf343ab1..a81c616b 100644
--- a/typescript-sdk/pnpm-lock.yaml
+++ b/typescript-sdk/pnpm-lock.yaml
@@ -50,6 +50,9 @@ importers:
'@ag-ui/proto':
specifier: workspace:*
version: link:../../packages/proto
+ '@ag-ui/pydantic-ai':
+ specifier: workspace:*
+ version: link:../../integrations/pydantic-ai
'@ag-ui/server-starter':
specifier: workspace:*
version: link:../../integrations/server-starter
@@ -412,6 +415,34 @@ importers:
specifier: ^5.3.3
version: 5.8.2
+ integrations/pydantic-ai:
+ dependencies:
+ '@ag-ui/client':
+ specifier: workspace:*
+ version: link:../../packages/client
+ rxjs:
+ specifier: 7.8.1
+ version: 7.8.1
+ devDependencies:
+ '@types/jest':
+ specifier: ^29.5.14
+ version: 29.5.14
+ '@types/node':
+ specifier: ^20.11.19
+ version: 20.17.50
+ jest:
+ specifier: ^29.7.0
+ version: 29.7.0(@types/node@20.17.50)
+ ts-jest:
+ specifier: ^29.1.2
+ version: 29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50))(typescript@5.8.2)
+ tsup:
+ specifier: ^8.0.2
+ version: 8.5.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.2)(yaml@2.8.0)
+ typescript:
+ specifier: ^5.3.3
+ version: 5.8.2
+
integrations/server-starter:
dependencies:
'@ag-ui/client':