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
91 changes: 91 additions & 0 deletions interface/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,42 @@ export interface IngestDeleteResponse {
success: boolean;
}

// -- Filesystem Types --

export interface FilesystemEntry {
name: string;
entry_type: "file" | "directory" | "other";
size: number;
modified_at: string | null;
}

export interface FileListResponse {
entries: FilesystemEntry[];
path: string;
}

export interface FileReadResponse {
content: string;
size: number;
truncated: boolean;
}

export interface FileWriteResponse {
success: boolean;
}

export interface FileDeleteResponse {
success: boolean;
}

export interface FileRenameResponse {
success: boolean;
}

export interface FileUploadResponse {
uploaded: string[];
}

// -- Skills Types --

export interface SkillInfo {
Expand Down Expand Up @@ -1632,6 +1668,61 @@ export const api = {
return response.json() as Promise<IngestDeleteResponse>;
},

// Filesystem API
filesystemList: (agentId: string, path = "") => {
const params = new URLSearchParams({ agent_id: agentId, path });
return fetchJson<FileListResponse>(`/agents/files/list?${params}`);
},

filesystemRead: (agentId: string, path: string) => {
const params = new URLSearchParams({ agent_id: agentId, path });
return fetchJson<FileReadResponse>(`/agents/files/read?${params}`);
},

filesystemDownloadUrl: (agentId: string, path: string) => {
const params = new URLSearchParams({ agent_id: agentId, path });
return `${API_BASE}/agents/files/download?${params}`;
},

filesystemWrite: async (agentId: string, path: string, content?: string, isDirectory = false) => {
const response = await fetch(`${API_BASE}/agents/files/write`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ agent_id: agentId, path, content, is_directory: isDirectory }),
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json() as Promise<FileWriteResponse>;
},

filesystemDelete: async (agentId: string, path: string) => {
const params = new URLSearchParams({ agent_id: agentId, path });
const response = await fetch(`${API_BASE}/agents/files/delete?${params}`, { method: "DELETE" });
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json() as Promise<FileDeleteResponse>;
},

filesystemRename: async (agentId: string, oldPath: string, newPath: string) => {
const response = await fetch(`${API_BASE}/agents/files/rename`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ agent_id: agentId, old_path: oldPath, new_path: newPath }),
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json() as Promise<FileRenameResponse>;
},

filesystemUpload: async (agentId: string, path: string, files: File[]) => {
const formData = new FormData();
for (const file of files) formData.append("files", file);
const params = new URLSearchParams({ agent_id: agentId, path });
const response = await fetch(`${API_BASE}/agents/files/upload?${params}`, {
method: "POST",
body: formData,
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json() as Promise<FileUploadResponse>;
},

// Messaging / Bindings API
messagingStatus: () => fetchJson<MessagingStatusResponse>("/messaging/status"),

Expand Down
2 changes: 1 addition & 1 deletion interface/src/components/AgentTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const tabs = [
{ label: "Chat", to: "/agents/$agentId/chat" as const, exact: false },
{ label: "Channels", to: "/agents/$agentId/channels" as const, exact: false },
{ label: "Memories", to: "/agents/$agentId/memories" as const, exact: false },
{ label: "Ingest", to: "/agents/$agentId/ingest" as const, exact: false },
{ label: "Files", to: "/agents/$agentId/files" as const, exact: false },
{ label: "Workers", to: "/agents/$agentId/workers" as const, exact: false },
{ label: "Tasks", to: "/agents/$agentId/tasks" as const, exact: false },
{ label: "Cortex", to: "/agents/$agentId/cortex" as const, exact: false },
Expand Down
17 changes: 10 additions & 7 deletions interface/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {ChannelDetail} from "@/routes/ChannelDetail";
import {AgentMemories} from "@/routes/AgentMemories";
import {AgentConfig} from "@/routes/AgentConfig";
import {AgentCron} from "@/routes/AgentCron";
import {AgentIngest} from "@/routes/AgentIngest";
import {AgentFiles} from "@/routes/AgentFiles";
import {AgentSkills} from "@/routes/AgentSkills";
import {AgentWorkers} from "@/routes/AgentWorkers";
import {AgentTasks} from "@/routes/AgentTasks";
Expand Down Expand Up @@ -168,16 +168,19 @@ const agentMemoriesRoute = createRoute({
},
});

const agentIngestRoute = createRoute({
const agentFilesRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/agents/$agentId/ingest",
component: function AgentIngestPage() {
const {agentId} = agentIngestRoute.useParams();
path: "/agents/$agentId/files",
validateSearch: (search: Record<string, unknown>): {path?: string} => ({
path: typeof search.path === "string" ? search.path : undefined,
}),
component: function AgentFilesPage() {
const {agentId} = agentFilesRoute.useParams();
return (
<div className="flex h-full flex-col">
<AgentHeader agentId={agentId} />
<div className="flex-1 overflow-hidden">
<AgentIngest agentId={agentId} />
<AgentFiles agentId={agentId} />
</div>
</div>
);
Expand Down Expand Up @@ -320,7 +323,7 @@ const routeTree = rootRoute.addChildren([
agentChatRoute,
agentChannelsRoute,
agentMemoriesRoute,
agentIngestRoute,
agentFilesRoute,
agentWorkersRoute,
agentTasksRoute,
agentCortexRoute,
Expand Down
Loading
Loading