Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f0ff080
feat: integrate excalidraw-mcp as first-class diagramming feature
GeneralJerel Mar 19, 2026
27e91f7
fix: give excalidraw skill its own section in agent system prompt
GeneralJerel Mar 19, 2026
e20a409
fix: center widget content in iframe
GeneralJerel Mar 19, 2026
7fd3913
fix: resolve hydration mismatch and cap widget height
GeneralJerel Mar 19, 2026
293135a
feat: add zoom controls to widget renderer
GeneralJerel Mar 19, 2026
c585bde
fix: add maxDuration to prevent route timeout during MCP calls
GeneralJerel Mar 19, 2026
99576ed
feat: move zoom controls from widgetRenderer to MCP widget only
GeneralJerel Mar 19, 2026
c50fe38
feat: add markdown canvas editor with LangGraph integration
GeneralJerel Mar 19, 2026
8adf9e5
fix: add MCPAppsMiddleware to document agent for Excalidraw support
GeneralJerel Mar 19, 2026
248b6ac
improve: add visualization instructions to document agent system prompt
GeneralJerel Mar 19, 2026
b898857
feat: integrate excalidraw diagram skill into document agent
GeneralJerel Mar 19, 2026
4d7eb0e
feat: merge document_agent into sample_agent for unified canvas exper…
GeneralJerel Mar 19, 2026
acb9aa6
fix: prevent state updates after component unmount in canvas editor
GeneralJerel Mar 19, 2026
3c84feb
style: refactor canvas page layout - add header, improve padding and …
GeneralJerel Mar 19, 2026
4c34c07
style: rename canvas page to 'Document to Diagram'
GeneralJerel Mar 19, 2026
4b7b73d
ux: improve editor visibility and interaction feedback
GeneralJerel Mar 19, 2026
47c2624
fix: hide placeholder text when editor is focused
GeneralJerel Mar 19, 2026
dda5a86
feat: add 'Get started' button to canvas header
GeneralJerel Mar 19, 2026
2ddc6bb
refactor: simplify and strengthen Excalidraw skill with overlap preve…
GeneralJerel Mar 19, 2026
b8619ce
fix: add isMountedRef checks to all state-updating effects
GeneralJerel Mar 19, 2026
de80d48
feat: add WebSocket document as default content on canvas page
GeneralJerel Mar 19, 2026
45fd46d
fix: replace suggestions with single WebSocket document chip
GeneralJerel Mar 19, 2026
ef85a6d
feat: add more technical document generation prompts
GeneralJerel Mar 19, 2026
036554f
fix: hide suggestions when chat has messages
GeneralJerel Mar 19, 2026
280e8f2
fix: show only 3 prompt suggestions initially
GeneralJerel Mar 19, 2026
0c72925
fix: resolve AbortError and fix suggestion chips visibility
GeneralJerel Mar 19, 2026
6eb355a
feat: add streaming animation to document editor during generation
GeneralJerel Mar 19, 2026
d546f20
fix: fix markdown rendering and improve streaming
GeneralJerel Mar 19, 2026
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
Prev Previous commit
Next Next commit
feat: merge document_agent into sample_agent for unified canvas exper…
…ience

- Add document state field to AgentState in src/todos.py
- Create new src/document.py with write_document tool and HITL confirmation
- Update main.py to include document tools and enable predictive state streaming
- Set config metadata for copilotkit:emit-intermediate-state for live document editing
- Remove separate document_agent from langgraph.json and route.ts
- Update canvas page to use agentId='default' instead of 'document_agent'
- Delete document_agent.py (functionality now in main agent)

The canvas editor now uses the flagship gpt-5.4-2026-03-05 model with all skill files
loaded from the skills/ directory, providing better diagram generation with labeled
elements and professional visualizations.
  • Loading branch information
GeneralJerel committed Mar 19, 2026
commit 4d7eb0e78778a67b338bcf1a1b7c44497ebbf8c2
182 changes: 0 additions & 182 deletions apps/agent/document_agent.py

This file was deleted.

3 changes: 1 addition & 2 deletions apps/agent/langgraph.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
"dependencies": ["."],
"package_manager": "uv",
"graphs": {
"sample_agent": "./main.py:graph",
"document_agent": "./document_agent.py:graph"
"sample_agent": "./main.py:graph"
},
"env": "../../.env"
}
20 changes: 18 additions & 2 deletions apps/agent/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from src.query import query_data
from src.todos import AgentState, todo_tools
from src.document import document_tools
from src.form import generate_form
from skills import load_all_skills, load_skill

Expand All @@ -18,7 +19,7 @@

agent = create_agent(
model=ChatOpenAI(model="gpt-5.4-2026-03-05"),
tools=[query_data, *todo_tools, generate_form],
tools=[query_data, *todo_tools, *document_tools, generate_form],
middleware=[CopilotKitMiddleware()],
state_schema=AgentState,
system_prompt=f"""
Expand Down Expand Up @@ -59,7 +60,22 @@
tools instead of `widgetRenderer`. Follow the skill below exactly:

{_excalidraw_skill_text}

## Document Editing

When the user asks to write, edit, create, or modify a document, use the `write_document` tool.
Always write the complete document, even when making small changes. After writing, the user will
see a confirmation dialog to review and accept or reject your changes. Be concise and follow
their specific instructions for content and format.
""",
)

graph = agent
graph = agent.with_config({
"metadata": {
"copilotkit:emit-intermediate-state": [{
"state_key": "document",
"tool": "write_document",
"tool_argument": "document",
}]
}
})
34 changes: 34 additions & 0 deletions apps/agent/src/document.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import uuid
from langchain.tools import tool, ToolRuntime
from langchain.messages import ToolMessage, AIMessage
from langgraph.types import Command


@tool
def write_document(document: str, runtime: ToolRuntime) -> Command:
"""
Write or update a document. Use markdown formatting.
Do not use italic or strike-through - reserved for diffs.
Write the complete document, even when making small edits.
Keep document changes minimal - don't rewrite everything.
"""
return Command(update={
"document": document,
"messages": [
ToolMessage(
content="Document written.",
tool_call_id=runtime.tool_call_id
),
AIMessage(
content="",
tool_calls=[{
"id": str(uuid.uuid4()),
"name": "confirm_changes",
"args": {},
}]
),
],
})


document_tools = [write_document]
3 changes: 2 additions & 1 deletion apps/agent/src/todos.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from langchain.tools import ToolRuntime, tool
from langchain.messages import ToolMessage
from langgraph.types import Command
from typing import TypedDict, Literal
from typing import TypedDict, Literal, Optional
import uuid

class Todo(TypedDict):
Expand All @@ -14,6 +14,7 @@ class Todo(TypedDict):

class AgentState(BaseAgentState):
todos: list[Todo]
document: Optional[str] = None

@tool
def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
Expand Down
21 changes: 1 addition & 20 deletions apps/app/src/app/api/copilotkit/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,17 @@ defaultAgent.use(
})
);

// 3. Define the document agent for the canvas editor
const documentAgent = new LangGraphAgent({
deploymentUrl: process.env.LANGGRAPH_DEPLOYMENT_URL || "http://localhost:8123",
graphId: "document_agent",
langsmithApiKey: process.env.LANGSMITH_API_KEY || "",
});

// Wire up MCP apps middleware for document agent
documentAgent.use(
new MCPAppsMiddleware({
mcpServers: [{
type: "http",
url: process.env.MCP_SERVER_URL || "https://mcp.excalidraw.com",
serverId: "example_mcp_app",
}],
})
);

// Allow long-running agent + MCP tool calls
export const maxDuration = 300;

// 4. Define the route and CopilotRuntime for the agents
// Define the route and CopilotRuntime for the agent
export const POST = async (req: NextRequest) => {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
endpoint: "/api/copilotkit",
serviceAdapter: new ExperimentalEmptyAdapter(),
runtime: new CopilotRuntime({
agents: {
default: defaultAgent,
document_agent: documentAgent,
},
a2ui: { injectA2UITool: true },
}),
Expand Down
10 changes: 5 additions & 5 deletions apps/app/src/app/canvas/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function CanvasPage() {

{/* Right: Chat Panel */}
<div className="w-[400px] overflow-hidden rounded-lg" style={{ background: "var(--surface-primary)", boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08)" }}>
{mounted && <CopilotChat agentId="document_agent" className="h-full flex flex-col" />}
{mounted && <CopilotChat agentId="default" className="h-full flex flex-col" />}
</div>
</div>
</CopilotKit>
Expand Down Expand Up @@ -95,7 +95,7 @@ const DocumentEditor = () => {
});

const { agent } = useAgent({
agentId: "document_agent",
agentId: "default",
updates: [UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged],
});

Expand Down Expand Up @@ -156,7 +156,7 @@ const DocumentEditor = () => {
// Human-in-the-loop: confirm_changes (legacy)
useHumanInTheLoop(
{
agentId: "document_agent",
agentId: "default",
name: "confirm_changes",
render: ({ args, respond, status }) => (
<ConfirmChanges
Expand All @@ -181,8 +181,8 @@ const DocumentEditor = () => {
// Human-in-the-loop: write_document (primary)
useHumanInTheLoop(
{
agentId: "document_agent",
name: "write_document",
agentId: "default",
name: "confirm_changes",
description: "Present the proposed changes to the user for review",
parameters: z.object({
document: z.string().describe("The full updated document in markdown format"),
Expand Down