Canvas: Implement agent sidebar on the overview tab
Change-Id: I1f2fb874cb98247c73bebf364f4669ad5170c4a0
diff --git a/apps/canvas/config/src/graph.ts b/apps/canvas/config/src/graph.ts
index 3c66fbd..c36dbcf 100644
--- a/apps/canvas/config/src/graph.ts
+++ b/apps/canvas/config/src/graph.ts
@@ -339,3 +339,4 @@
export type ServiceInfo = z.infer<typeof serviceInfoSchema>;
export type Env = z.infer<typeof envSchema>;
export type Access = z.infer<typeof accessSchema>;
+export type AgentAccess = Required<Extract<Access, { type: "https" }>>;
diff --git a/apps/canvas/config/src/index.ts b/apps/canvas/config/src/index.ts
index 453416d..f8db8fe 100644
--- a/apps/canvas/config/src/index.ts
+++ b/apps/canvas/config/src/index.ts
@@ -49,6 +49,7 @@
envSchema,
accessSchema,
Access,
+ AgentAccess,
} from "./graph.js";
export { generateDodoConfig, configToGraph } from "./config.js";
diff --git a/apps/canvas/front/src/Overview.tsx b/apps/canvas/front/src/Overview.tsx
index 8ed2c0c..1c86aae 100644
--- a/apps/canvas/front/src/Overview.tsx
+++ b/apps/canvas/front/src/Overview.tsx
@@ -1,9 +1,11 @@
import React, { useMemo } from "react";
-import { useStateStore, AppNode, NodeType } from "@/lib/state";
+import { useStateStore, useLeadAgent } from "@/lib/state";
import { NodeDetails } from "./components/node-details";
import { Actions } from "./components/actions";
import { Canvas } from "./components/canvas";
import { Separator } from "./components/ui/separator";
+import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "./components/ui/resizable";
+import { AppNode, NodeType } from "config";
const sections: { title: string; nodes: NodeType[] }[] = [
{
@@ -21,6 +23,30 @@
];
export function Overview(): React.ReactNode {
+ const leadAgent = useLeadAgent();
+ if (leadAgent) {
+ return (
+ <ResizablePanelGroup direction="horizontal" className="w-full h-full">
+ <ResizablePanel defaultSize={25}>
+ <iframe
+ key={leadAgent.name}
+ src={`${leadAgent.address}?m`}
+ title={leadAgent.agentName}
+ className="w-full h-full"
+ />
+ </ResizablePanel>
+ <ResizableHandle withHandle />
+ <ResizablePanel defaultSize={75} className="!overflow-y-auto !overflow-x-hidden">
+ <OverviewImpl />
+ </ResizablePanel>
+ </ResizablePanelGroup>
+ );
+ } else {
+ return <OverviewImpl />;
+ }
+}
+
+function OverviewImpl(): React.ReactNode {
const store = useStateStore();
const nodes = useMemo(() => {
return store.nodes.filter((n) => n.type !== "network" && n.type !== "github" && n.type !== undefined);
diff --git a/apps/canvas/front/src/components/ChatManager.tsx b/apps/canvas/front/src/components/ChatManager.tsx
index d5db0f3..4731c42 100644
--- a/apps/canvas/front/src/components/ChatManager.tsx
+++ b/apps/canvas/front/src/components/ChatManager.tsx
@@ -26,7 +26,7 @@
return (
<ChatBubble
key={agent.name}
- agentName={agent.name}
+ agentName={agent.agentName}
agentUrl={agent.address}
initialPosition={initialPosition}
/>
diff --git a/apps/canvas/front/src/lib/state.ts b/apps/canvas/front/src/lib/state.ts
index e0a858a..cd5f29c 100644
--- a/apps/canvas/front/src/lib/state.ts
+++ b/apps/canvas/front/src/lib/state.ts
@@ -14,7 +14,7 @@
import type { DeepPartial } from "react-hook-form";
import { v4 as uuidv4 } from "uuid";
import { create } from "zustand";
-import { AppNode, Env, NodeType, VolumeNode, GatewayTCPData, envSchema, Access } from "config";
+import { AppNode, Env, NodeType, VolumeNode, GatewayTCPData, envSchema, AgentAccess } from "config";
export function nodeLabel(n: AppNode): string {
try {
@@ -270,12 +270,17 @@
return useStateStore(envSelector);
}
-export function useAgents(): Extract<Access, { type: "https" }>[] {
+export function useAgents(): AgentAccess[] {
return useStateStore(envSelector).access.filter(
- (acc): acc is Extract<Access, { type: "https" }> => acc.type === "https" && acc.agentName != null,
+ (acc): acc is AgentAccess => acc.type === "https" && acc.agentName != null,
);
}
+export function useLeadAgent(): AgentAccess | undefined {
+ const agents = useAgents();
+ return agents.find((a) => a.agentName === "dodo") || agents[0];
+}
+
export function useGithubService(): boolean {
return useStateStore(envSelector).integrations.github;
}