mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-22 09:34:53 +02:00
[Haik]: refactor: overhaul agents API contract and frontend backend layer — rename all backend agent routes from RESTful path-param style (e.g. /sessions/{id}/message) to flat action-named endpoints (e.g. /send_message), replace Pydantic BaseModel request classes (LaunchBody, MessageBody, etc.) with inline FastAPI Body() parameters, delete the scattered frontend shared/routes/ directory (11 files) and agentsThunks.ts, and replace them with a co-located shared/backend/apps/ structure where each backend app has its routes, fetch functions, and async thunks in a single file
This commit is contained in:
@@ -14,7 +14,7 @@ from datetime import datetime
|
||||
from typing import Optional, List, Dict
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import HTTPException, WebSocket, WebSocketDisconnect
|
||||
from fastapi import HTTPException, WebSocket, WebSocketDisconnect, Body
|
||||
import json
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -113,32 +113,32 @@ async def websocket_dashboard(websocket: WebSocket):
|
||||
# Session CRUD
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@agents.router.get("/SESSIONS")
|
||||
async def list_sessions(dashboard_id: str = "") -> dict:
|
||||
@agents.router.get("/get_all_sessions")
|
||||
async def get_all_sessions(dashboard_id: str = Body(default="")) -> dict:
|
||||
result: List[Agent] = list[Agent](SESSIONS.values())
|
||||
if dashboard_id:
|
||||
result: List[Agent] = [a for a in result if getattr(a, "dashboard_id", None) == dashboard_id]
|
||||
return {"SESSIONS": [a.model_dump(mode="json") for a in result]}
|
||||
|
||||
|
||||
@agents.router.get("/sessions/{session_id}")
|
||||
async def get_session(session_id: str) -> dict:
|
||||
@agents.router.get("/get_session")
|
||||
async def get_session(session_id: str = Body()) -> dict:
|
||||
return get_agent(session_id).model_dump(mode="json")
|
||||
|
||||
|
||||
class LaunchBody(BaseModel):
|
||||
model: str = "claude-sonnet-4-6"
|
||||
mode: str = "agent"
|
||||
system_prompt: str = ""
|
||||
max_turns: int = 200
|
||||
|
||||
@agents.router.post("/launch")
|
||||
async def launch(body: LaunchBody) -> dict:
|
||||
@agents.router.post("/launch_agent")
|
||||
async def launch_agent(
|
||||
model: str = Body(),
|
||||
mode: str = Body(),
|
||||
system_prompt: str = Body(),
|
||||
max_turns: int = Body(),
|
||||
) -> dict:
|
||||
agent: Agent = Agent(
|
||||
model=body.model,
|
||||
mode=body.mode,
|
||||
model=model,
|
||||
mode=mode,
|
||||
status="stopped",
|
||||
config=ClaudeAgentOptions(max_turns=body.max_turns),
|
||||
config=ClaudeAgentOptions(max_turns=max_turns),
|
||||
)
|
||||
agent.on_event = COMMS_MANAGER.make_session_emitter(agent.session_id)
|
||||
SESSIONS[agent.session_id] = agent
|
||||
@@ -152,8 +152,8 @@ async def launch(body: LaunchBody) -> dict:
|
||||
mcp_servers: Dict[str, McpServerConfig] = toolkit.collect_mcp_servers()
|
||||
|
||||
resolved_mode_config: ResolvedModeConfig = await ResolvedModeConfig.create(
|
||||
mode_id=body.mode,
|
||||
session_prompt=body.system_prompt or None,
|
||||
mode_id=mode,
|
||||
session_prompt=system_prompt or None,
|
||||
toolkit=toolkit,
|
||||
)
|
||||
|
||||
@@ -167,9 +167,9 @@ async def launch(body: LaunchBody) -> dict:
|
||||
|
||||
agent.config = ClaudeAgentOptions(
|
||||
env=env,
|
||||
model=body.model,
|
||||
model=model,
|
||||
system_prompt=resolved_mode_config.system_prompt,
|
||||
max_turns=body.max_turns,
|
||||
max_turns=max_turns,
|
||||
cwd=resolved_mode_config.cwd,
|
||||
mcp_servers=mcp_servers if mcp_servers else None,
|
||||
allowed_tools=resolved_mode_config.allowed_tools,
|
||||
@@ -189,14 +189,14 @@ async def launch(body: LaunchBody) -> dict:
|
||||
return {"session_id": agent.session_id, "session": agent.snapshot().model_dump(mode="json")}
|
||||
|
||||
|
||||
class UpdateBody(BaseModel):
|
||||
system_prompt: Optional[str] = None
|
||||
|
||||
@agents.router.patch("/SESSIONS/{session_id}")
|
||||
async def update_session(session_id: str, body: UpdateBody) -> dict:
|
||||
@agents.router.patch("/update_system_prompt")
|
||||
async def update_system_prompt(
|
||||
session_id: str = Body(),
|
||||
system_prompt: Optional[str] = Body(default=None),
|
||||
) -> dict:
|
||||
agent: Agent = get_agent(session_id)
|
||||
if body.system_prompt is not None:
|
||||
agent.config.system_prompt = body.system_prompt
|
||||
if system_prompt is not None:
|
||||
agent.config.system_prompt = system_prompt
|
||||
await agent.emit(AgentStatusEvent(
|
||||
session_id=session_id, status=agent.status,
|
||||
session=agent.snapshot(),
|
||||
@@ -204,8 +204,8 @@ async def update_session(session_id: str, body: UpdateBody) -> dict:
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@agents.router.delete("/sessions/{session_id}")
|
||||
async def delete_session(session_id: str) -> dict:
|
||||
@agents.router.delete("/delete_session")
|
||||
async def delete_session(session_id: str = Body()) -> dict:
|
||||
agent: Optional[Agent] = SESSIONS.pop(session_id, None)
|
||||
if agent is not None:
|
||||
await agent.stop_agent()
|
||||
@@ -228,16 +228,28 @@ class MessageBody(BaseModel):
|
||||
attached_skills: Optional[List[dict]] = None
|
||||
hidden: bool = False
|
||||
|
||||
@agents.router.post("/SESSIONS/{session_id}/message")
|
||||
async def send_message(session_id: str, body: MessageBody) -> dict:
|
||||
@agents.router.post("/send_message")
|
||||
async def send_message(
|
||||
session_id: str = Body(),
|
||||
prompt: str = Body(),
|
||||
mode: Optional[str] = Body(default=None),
|
||||
model: Optional[str] = Body(default=None),
|
||||
images: Optional[List[str]] = Body(default=None),
|
||||
image_media_types: Optional[List[str]] = Body(default=None),
|
||||
context_paths: Optional[List[dict]] = Body(default=None),
|
||||
forced_tools: Optional[List[str]] = Body(default=None),
|
||||
attached_skills: Optional[List[dict]] = Body(default=None),
|
||||
hidden: bool = Body(default=False),
|
||||
|
||||
) -> dict:
|
||||
agent: Agent = get_agent(session_id)
|
||||
mode_changed: bool = bool(body.mode and body.mode != agent.mode)
|
||||
model_changed: bool = bool(body.model and body.model != agent.model)
|
||||
mode_changed: bool = bool(mode and mode != agent.mode)
|
||||
model_changed: bool = bool(model and model != agent.model)
|
||||
|
||||
if mode_changed:
|
||||
agent.mode = body.mode # type: ignore[assignment]
|
||||
agent.mode = mode # type: ignore[assignment]
|
||||
if model_changed:
|
||||
agent.model = body.model # type: ignore[assignment]
|
||||
agent.model = model # type: ignore[assignment]
|
||||
|
||||
if mode_changed or model_changed:
|
||||
resolved_mode_config: ResolvedModeConfig = await ResolvedModeConfig.create(
|
||||
@@ -253,39 +265,38 @@ async def send_message(session_id: str, body: MessageBody) -> dict:
|
||||
agent.config.cwd = resolved_mode_config.cwd
|
||||
|
||||
msg: UserMessage = UserMessage(
|
||||
content=body.prompt,
|
||||
content=prompt,
|
||||
branch_id=agent.branch_id,
|
||||
images=body.images or [],
|
||||
image_media_types=body.image_media_types or [],
|
||||
context_paths=body.context_paths or [],
|
||||
attached_skills=body.attached_skills or [],
|
||||
forced_tools=body.forced_tools or [],
|
||||
hidden=body.hidden,
|
||||
images=images or [],
|
||||
image_media_types=image_media_types or [],
|
||||
context_paths=context_paths or [],
|
||||
attached_skills=attached_skills or [],
|
||||
forced_tools=forced_tools or [],
|
||||
hidden=hidden,
|
||||
)
|
||||
await agent.send_message(msg)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@agents.router.post("/sessions/{session_id}/stop")
|
||||
async def stop_agent(session_id: str) -> dict:
|
||||
@agents.router.post("/stop_agent")
|
||||
async def stop_agent(session_id: str = Body()) -> dict:
|
||||
agent: Agent = get_agent(session_id)
|
||||
await agent.stop_agent()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
class ApprovalBody(BaseModel):
|
||||
request_id: str
|
||||
behavior: str
|
||||
message: str = ""
|
||||
updated_input: Optional[dict] = None
|
||||
|
||||
@agents.router.post("/approval")
|
||||
async def handle_approval(body: ApprovalBody) -> dict:
|
||||
@agents.router.post("/handle_approval")
|
||||
async def handle_approval(
|
||||
request_id: str = Body(),
|
||||
behavior: str = Body(),
|
||||
message: str = Body(default=""),
|
||||
updated_input: Optional[dict] = Body(default=None),
|
||||
) -> dict:
|
||||
await COMMS_MANAGER.resolve_approval(
|
||||
request_id=body.request_id,
|
||||
behavior=body.behavior,
|
||||
message=body.message,
|
||||
updated_input=body.updated_input,
|
||||
request_id=request_id,
|
||||
behavior=behavior,
|
||||
message=message,
|
||||
updated_input=updated_input,
|
||||
)
|
||||
return {"ok": True}
|
||||
|
||||
@@ -294,31 +305,32 @@ async def handle_approval(body: ApprovalBody) -> dict:
|
||||
# Branching
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class EditMessageBody(BaseModel):
|
||||
message_id: str
|
||||
content: str
|
||||
|
||||
@agents.router.post("/sessions/{session_id}/edit_message")
|
||||
async def edit_message(session_id: str, body: EditMessageBody) -> dict:
|
||||
@agents.router.post("/edit_message")
|
||||
async def edit_message(
|
||||
session_id: str = Body(),
|
||||
message_id: str = Body(),
|
||||
content: str = Body(),
|
||||
) -> dict:
|
||||
agent: Agent = get_agent(session_id)
|
||||
await agent.stop_agent()
|
||||
fork: Agent = agent.branch(body.message_id)
|
||||
fork: Agent = agent.branch(message_id)
|
||||
SESSIONS[fork.session_id] = fork
|
||||
|
||||
edited_msg: UserMessage = UserMessage(content=body.content, branch_id=fork.branch_id)
|
||||
edited_msg: UserMessage = UserMessage(content=content, branch_id=fork.branch_id)
|
||||
await fork.send_message(edited_msg)
|
||||
return {"ok": True, "branch_id": fork.branch_id, "session_id": fork.session_id}
|
||||
|
||||
|
||||
class SwitchBranchBody(BaseModel):
|
||||
branch_id: str
|
||||
|
||||
@agents.router.post("/SESSIONS/{session_id}/switch_branch")
|
||||
async def switch_branch(session_id: str, body: SwitchBranchBody) -> dict:
|
||||
@agents.router.post("/switch_branch")
|
||||
async def switch_branch(
|
||||
session_id: str = Body(),
|
||||
branch_id: str = Body(),
|
||||
) -> dict:
|
||||
agent: Agent = get_agent(session_id)
|
||||
agent.branch_id = body.branch_id
|
||||
agent.branch_id = branch_id
|
||||
await agent.emit(BranchSwitchedEvent(
|
||||
session_id=session_id, active_branch_id=body.branch_id,
|
||||
session_id=session_id, active_branch_id=branch_id,
|
||||
))
|
||||
return {"ok": True}
|
||||
|
||||
@@ -327,8 +339,8 @@ async def switch_branch(session_id: str, body: SwitchBranchBody) -> dict:
|
||||
# Persistence
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@agents.router.post("/sessions/{session_id}/close")
|
||||
async def close_session(session_id: str) -> dict:
|
||||
@agents.router.post("/close_session")
|
||||
async def close_session(session_id: str = Body()) -> dict:
|
||||
agent: Optional[Agent] = SESSIONS.pop(session_id, None)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Session not found")
|
||||
@@ -343,8 +355,8 @@ async def close_session(session_id: str) -> dict:
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@agents.router.post("/SESSIONS/{session_id}/resume")
|
||||
async def resume_session(session_id: str) -> dict:
|
||||
@agents.router.post("/resume_session")
|
||||
async def resume_session(session_id: str = Body()) -> dict:
|
||||
if session_id in SESSIONS:
|
||||
return {"session": SESSIONS[session_id].model_dump(mode="json")}
|
||||
agent: Optional[Agent] = AGENT_STORE.load_or_none(session_id)
|
||||
@@ -366,8 +378,8 @@ async def resume_session(session_id: str) -> dict:
|
||||
return {"session": agent.snapshot().model_dump(mode="json")}
|
||||
|
||||
|
||||
@agents.router.post("/SESSIONS/{session_id}/duplicate")
|
||||
async def duplicate_session(session_id: str, body: dict = {}) -> dict:
|
||||
@agents.router.post("/duplicate_session")
|
||||
async def duplicate_session(session_id: str = Body()) -> dict:
|
||||
source: Optional[Agent] = SESSIONS.get(session_id)
|
||||
if source is None:
|
||||
source = AGENT_STORE.load_or_none(session_id)
|
||||
@@ -395,8 +407,12 @@ async def duplicate_session(session_id: str, body: dict = {}) -> dict:
|
||||
return {"session": clone.snapshot().model_dump(mode="json")}
|
||||
|
||||
|
||||
@agents.router.get("/history")
|
||||
async def get_history(q: str = "", limit: int = 20, offset: int = 0, dashboard_id: str = "") -> dict:
|
||||
@agents.router.get("/get_history")
|
||||
async def get_history(
|
||||
q: str = Body(default=""),
|
||||
limit: int = Body(default=20),
|
||||
offset: int = Body(default=0),
|
||||
) -> dict:
|
||||
all_agents: List[Agent] = AGENT_STORE.load_all()
|
||||
all_agents.sort(
|
||||
key=lambda a: a.messages.messages[-1].timestamp if a.messages.messages else datetime.min,
|
||||
|
||||
@@ -9,7 +9,7 @@ from backend.config.Apps import SubApp
|
||||
from backend.core.db.PydanticStore import PydanticStore
|
||||
from backend.core.shared_structs.dashboard.Dashboard import Dashboard
|
||||
from backend.core.shared_structs.dashboard.DashboardLayout import DashboardLayout
|
||||
from backend.apps.agents.agents import list_sessions, delete_session
|
||||
from backend.apps.agents.agents import get_all_sessions, delete_session
|
||||
from backend.apps.settings.settings import load_settings
|
||||
from backend.apps.dashboards.generate_dashboard_name import generate_dashboard_name
|
||||
from backend.ports import NINE_ROUTER_PORT
|
||||
@@ -61,7 +61,7 @@ async def create_dashboard(body: DashboardCreate):
|
||||
return dashboard.model_dump(mode="json")
|
||||
|
||||
|
||||
# TODO: Maybe parse the output of list_sessions into actual Agent objects?
|
||||
# TODO: Maybe parse the output of get_all_sessions into actual Agent objects?
|
||||
@dashboards.router.post("/{dashboard_id}/generate-name")
|
||||
async def generate_name(dashboard_id: str):
|
||||
dashboard = DASHBOARD_STORE.load(dashboard_id)
|
||||
@@ -69,7 +69,7 @@ async def generate_name(dashboard_id: str):
|
||||
if not dashboard.auto_named and dashboard.name != "Untitled Dashboard":
|
||||
return {"name": dashboard.name, "auto_named": dashboard.auto_named}
|
||||
|
||||
sessions_resp = await list_sessions(dashboard_id=dashboard_id)
|
||||
sessions_resp = await get_all_sessions(dashboard_id=dashboard_id)
|
||||
sessions = sessions_resp.get("SESSIONS", [])
|
||||
|
||||
prompts = []
|
||||
@@ -134,7 +134,7 @@ async def update_dashboard(dashboard_id: str, body: DashboardUpdate):
|
||||
async def delete_dashboard(dashboard_id: str):
|
||||
DASHBOARD_STORE.load(dashboard_id) # confirm it exists (raises 404 if not)
|
||||
|
||||
sessions_resp = await list_sessions(dashboard_id=dashboard_id)
|
||||
sessions_resp = await get_all_sessions(dashboard_id=dashboard_id)
|
||||
for session in sessions_resp.get("SESSIONS", []):
|
||||
try:
|
||||
await delete_session(session["session_id"])
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { API_BASE } from '@/shared/backend/base_routes';
|
||||
import type {
|
||||
AgentSession, AgentConfig, HistorySession,
|
||||
} from '@/shared/state/agentsTypes';
|
||||
|
||||
const AGENTS_API: string = `${API_BASE}/agents`;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Session CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
const get_all_sessions_endpoint: string = `${AGENTS_API}/get_all_sessions`;
|
||||
async function get_all_sessions_function(dashboardId?: string): Promise<AgentSession[]> {
|
||||
const params = new URLSearchParams();
|
||||
if (dashboardId) params.set('dashboard_id', dashboardId);
|
||||
const res = await fetch(get_all_sessions_endpoint, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ params }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.sessions as AgentSession[];
|
||||
}
|
||||
export const GET_ALL_SESSIONS = createAsyncThunk(
|
||||
get_all_sessions_endpoint,
|
||||
get_all_sessions_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const get_session_endpoint: string = `${AGENTS_API}/get_session`;
|
||||
async function get_session_function(sessionId: string): Promise<AgentSession> {
|
||||
const res = await fetch(get_session_endpoint, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const GET_SESSION = createAsyncThunk(
|
||||
get_session_endpoint,
|
||||
get_session_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const launch_agent_endpoint: string = `${AGENTS_API}/launch_agent`;
|
||||
async function launch_agent_function(config: AgentConfig): Promise<AgentSession> {
|
||||
const res = await fetch(launch_agent_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const LAUNCH_AGENT = createAsyncThunk(
|
||||
launch_agent_endpoint,
|
||||
launch_agent_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const update_system_prompt_endpoint: string = `${AGENTS_API}/update_system_prompt`;
|
||||
async function update_system_prompt_function(sessionId: string, systemPrompt: string): Promise<string> {
|
||||
const res = await fetch(update_system_prompt_endpoint, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId, system_prompt: systemPrompt }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.ok as string;
|
||||
}
|
||||
export const UPDATE_SYSTEM_PROMPT = createAsyncThunk(
|
||||
update_system_prompt_endpoint,
|
||||
update_system_prompt_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const delete_session_endpoint: string = `${AGENTS_API}/delete_session`;
|
||||
async function delete_session_function(sessionId: string): Promise<string> {
|
||||
const res = await fetch(delete_session_endpoint, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.sessionId as string;
|
||||
}
|
||||
export const DELETE_SESSION = createAsyncThunk(
|
||||
delete_session_endpoint,
|
||||
delete_session_function
|
||||
);
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Agent lifecycle
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
const send_message_endpoint: string = `${AGENTS_API}/send_message`;
|
||||
async function send_message_function(
|
||||
sessionId: string,
|
||||
prompt: string,
|
||||
mode: string,
|
||||
model: string,
|
||||
provider: string,
|
||||
images: string[],
|
||||
contextPaths: string[],
|
||||
forcedTools: string[],
|
||||
attachedSkills: string[],
|
||||
hidden: boolean,
|
||||
selectedBrowserIds: string[]
|
||||
): Promise<AgentSession> {
|
||||
const res = await fetch(send_message_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
session_id: sessionId,
|
||||
prompt: prompt,
|
||||
mode: mode,
|
||||
model: model,
|
||||
provider: provider,
|
||||
images: images,
|
||||
context_paths: contextPaths,
|
||||
forced_tools: forcedTools,
|
||||
attached_skills: attachedSkills,
|
||||
hidden: hidden,
|
||||
selected_browser_ids: selectedBrowserIds,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const SEND_MESSAGE = createAsyncThunk(
|
||||
send_message_endpoint,
|
||||
send_message_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const stop_agent_endpoint: string = `${AGENTS_API}/stop_agent`;
|
||||
async function stop_agent_function(sessionId: string): Promise<string> {
|
||||
const res = await fetch(stop_agent_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.sessionId as string;
|
||||
}
|
||||
export const STOP_AGENT = createAsyncThunk(
|
||||
stop_agent_endpoint,
|
||||
stop_agent_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
const handle_approval_endpoint: string = `${AGENTS_API}/handle_approval`;
|
||||
async function handle_approval_function(
|
||||
requestId: string,
|
||||
behavior: 'allow' | 'deny',
|
||||
message?: string,
|
||||
updatedInput?: Record<string, unknown>
|
||||
): Promise<{ requestId: string; behavior: 'allow' | 'deny' }> {
|
||||
const res = await fetch(handle_approval_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
request_id: requestId,
|
||||
behavior: behavior,
|
||||
message: message,
|
||||
updated_input: updatedInput,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error(`Approval request failed (${res.status})`);
|
||||
return { requestId, behavior };
|
||||
}
|
||||
export const HANDLE_APPROVAL = createAsyncThunk(
|
||||
handle_approval_endpoint,
|
||||
handle_approval_function
|
||||
);
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Branching
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
const edit_message_endpoint: string = `${AGENTS_API}/edit_message`;
|
||||
async function edit_message_function(sessionId: string, messageId: string, content: string): Promise<AgentSession> {
|
||||
const res = await fetch(edit_message_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
session_id: sessionId,
|
||||
message_id: messageId,
|
||||
content: content,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const EDIT_MESSAGE = createAsyncThunk(
|
||||
edit_message_endpoint,
|
||||
edit_message_function,
|
||||
);
|
||||
|
||||
|
||||
const switch_branch_endpoint: string = `${AGENTS_API}/switch_branch`;
|
||||
async function switch_branch_function(sessionId: string, branchId: string): Promise<AgentSession> {
|
||||
const res = await fetch(switch_branch_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId, branch_id: branchId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const SWITCH_BRANCH = createAsyncThunk(
|
||||
switch_branch_endpoint,
|
||||
switch_branch_function,
|
||||
);
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Persistence
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
const close_session_endpoint: string = `${AGENTS_API}/close_session`;
|
||||
async function close_session_function(sessionId: string): Promise<string> {
|
||||
const res = await fetch(close_session_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.sessionId as string;
|
||||
}
|
||||
export const CLOSE_SESSION = createAsyncThunk(
|
||||
close_session_endpoint,
|
||||
close_session_function
|
||||
);
|
||||
|
||||
|
||||
|
||||
const resume_session_endpoint: string = `${AGENTS_API}/resume_session`;
|
||||
async function resume_session_function(sessionId: string): Promise<AgentSession> {
|
||||
const res = await fetch(resume_session_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sessionId }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const RESUME_SESSION = createAsyncThunk(
|
||||
resume_session_endpoint,
|
||||
resume_session_function
|
||||
);
|
||||
|
||||
|
||||
|
||||
const duplicate_session_endpoint: string = `${AGENTS_API}/duplicate_session`;
|
||||
async function duplicate_session_function(sessionId: string, dashboardId: string, upToMessageId: string): Promise<AgentSession> {
|
||||
const res = await fetch(duplicate_session_endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
session_id: sessionId,
|
||||
dashboard_id: dashboardId,
|
||||
up_to_message_id: upToMessageId,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
export const DUPLICATE_SESSION = createAsyncThunk(
|
||||
duplicate_session_endpoint,
|
||||
duplicate_session_function
|
||||
);
|
||||
|
||||
|
||||
|
||||
const get_history_endpoint: string = `${AGENTS_API}/get_history`;
|
||||
async function get_history_function(q: string, limit: number, offset: number): Promise<HistorySession[]> {
|
||||
const res = await fetch(get_history_endpoint, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ q, limit, offset }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.sessions as HistorySession[];
|
||||
}
|
||||
export const GET_HISTORY = createAsyncThunk(
|
||||
get_history_endpoint,
|
||||
get_history_function,
|
||||
);
|
||||
@@ -1,19 +0,0 @@
|
||||
import { API_BASE, WS_BASE } from '@/shared/routes/base';
|
||||
|
||||
const AGENTS_API: string = `${API_BASE}/agents`;
|
||||
|
||||
export const AGENTS_WS: string = `${WS_BASE}/api/agents/ws/dashboard`;
|
||||
|
||||
export const AGENTS_SESSIONS_API: string = `${AGENTS_API}/SESSIONS`;
|
||||
export const AGENTS_SESSION_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/sessions/${sessionId}`;
|
||||
export const AGENTS_LAUNCH_API: string = `${AGENTS_API}/launch`;
|
||||
export const AGENTS_UPDATE_SESSION_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/SESSIONS/${sessionId}`;
|
||||
export const AGENTS_MESSAGE_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/SESSIONS/${sessionId}/message`;
|
||||
export const AGENTS_STOP_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/sessions/${sessionId}/stop`;
|
||||
export const AGENTS_APPROVAL_API: string = `${AGENTS_API}/approval`;
|
||||
export const AGENTS_EDIT_MESSAGE_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/sessions/${sessionId}/edit_message`;
|
||||
export const AGENTS_SWITCH_BRANCH_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/SESSIONS/${sessionId}/switch_branch`;
|
||||
export const AGENTS_CLOSE_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/sessions/${sessionId}/close`;
|
||||
export const AGENTS_RESUME_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/SESSIONS/${sessionId}/resume`;
|
||||
export const AGENTS_DUPLICATE_API: (sessionId: string) => string = (sessionId: string) => `${AGENTS_API}/SESSIONS/${sessionId}/duplicate`;
|
||||
export const AGENTS_HISTORY_API: string = `${AGENTS_API}/history`;
|
||||
@@ -1,15 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const APP_BUILDER_API: string = `${API_BASE}/app_builder`;
|
||||
|
||||
export const APP_BUILDER_SOURCE_FILE_API: (appId: string, filepath: string) => string = (appId: string, filepath: string) => `${APP_BUILDER_API}/app/${appId}/source_dir/${filepath}`;
|
||||
export const APP_BUILDER_SERVE_API: (appId: string, filepath: string) => string = (appId: string, filepath: string) => `${APP_BUILDER_API}/${appId}/serve/${filepath}`;
|
||||
export const APP_BUILDER_READ_APP_API: (appId: string) => string = (appId: string) => `${APP_BUILDER_API}/app/${appId}`;
|
||||
export const APP_BUILDER_SEED_API: string = `${APP_BUILDER_API}/app/seed`;
|
||||
export const APP_BUILDER_FILE_API: (appId: string, filepath: string) => string = (appId: string, filepath: string) => `${APP_BUILDER_API}/app/${appId}/file/${filepath}`;
|
||||
export const APP_BUILDER_LIST_API: string = `${APP_BUILDER_API}/list`;
|
||||
export const APP_BUILDER_GET_API: (appId: string) => string = (appId: string) => `${APP_BUILDER_API}/${appId}`;
|
||||
export const APP_BUILDER_CREATE_API: string = `${APP_BUILDER_API}/create`;
|
||||
export const APP_BUILDER_UPDATE_API: (appId: string) => string = (appId: string) => `${APP_BUILDER_API}/${appId}`;
|
||||
export const APP_BUILDER_DELETE_API: (appId: string) => string = (appId: string) => `${APP_BUILDER_API}/${appId}`;
|
||||
export const APP_BUILDER_EXECUTE_API: string = `${APP_BUILDER_API}/execute`;
|
||||
@@ -1,11 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const DASHBOARDS_API: string = `${API_BASE}/dashboards`;
|
||||
|
||||
export const DASHBOARDS_LIST_API: string = `${DASHBOARDS_API}/list`;
|
||||
export const DASHBOARDS_CREATE_API: string = `${DASHBOARDS_API}/create`;
|
||||
export const DASHBOARDS_GET_API: (dashboardId: string) => string = (dashboardId: string) => `${DASHBOARDS_API}/${dashboardId}`;
|
||||
export const DASHBOARDS_UPDATE_API: (dashboardId: string) => string = (dashboardId: string) => `${DASHBOARDS_API}/${dashboardId}`;
|
||||
export const DASHBOARDS_DELETE_API: (dashboardId: string) => string = (dashboardId: string) => `${DASHBOARDS_API}/${dashboardId}`;
|
||||
export const DASHBOARDS_DUPLICATE_API: (dashboardId: string) => string = (dashboardId: string) => `${DASHBOARDS_API}/${dashboardId}/duplicate`;
|
||||
export const DASHBOARDS_GENERATE_NAME_API: (dashboardId: string) => string = (dashboardId: string) => `${DASHBOARDS_API}/${dashboardId}/generate-name`;
|
||||
@@ -1,5 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const HEALTH_API: string = `${API_BASE}/health`;
|
||||
|
||||
export const HEALTH_CHECK_API: string = `${HEALTH_API}/check`;
|
||||
@@ -1,11 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const MODES_API: string = `${API_BASE}/modes`;
|
||||
|
||||
export const MODES_LIST_API: string = `${MODES_API}/list`;
|
||||
export const MODES_GET_API: (modeId: string) => string = (modeId: string) => `${MODES_API}/${modeId}`;
|
||||
export const MODES_CREATE_API: string = `${MODES_API}/create`;
|
||||
export const MODES_UPDATE_API: (modeId: string) => string = (modeId: string) => `${MODES_API}/${modeId}`;
|
||||
export const MODES_RESET_API: (modeId: string) => string = (modeId: string) => `${MODES_API}/${modeId}/reset`;
|
||||
export const MODES_DELETE_API: (modeId: string) => string = (modeId: string) => `${MODES_API}/${modeId}`;
|
||||
export const MODES_GET_BY_ID_API: string = `${MODES_API}/get_mode_by_id`;
|
||||
@@ -1,7 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const SETTINGS_API: string = `${API_BASE}/settings`;
|
||||
|
||||
export const SETTINGS_GET_API: string = SETTINGS_API;
|
||||
export const SETTINGS_UPDATE_API: string = SETTINGS_API;
|
||||
export const SETTINGS_RESET_SYSTEM_PROMPT_API: string = `${SETTINGS_API}/reset-system-prompt`;
|
||||
@@ -1,15 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const SKILLS_API: string = `${API_BASE}/skills`;
|
||||
|
||||
export const SKILLS_LIST_API: string = `${SKILLS_API}/list`;
|
||||
export const SKILLS_WORKSPACE_API: (workspaceId: string) => string = (workspaceId: string) => `${SKILLS_API}/workspace/${workspaceId}`;
|
||||
export const SKILLS_WORKSPACE_SEED_API: string = `${SKILLS_API}/workspace/seed`;
|
||||
export const SKILLS_DETAIL_API: (skillId: string) => string = (skillId: string) => `${SKILLS_API}/detail/${skillId}`;
|
||||
export const SKILLS_CREATE_API: string = `${SKILLS_API}/create`;
|
||||
export const SKILLS_UPDATE_API: (skillId: string) => string = (skillId: string) => `${SKILLS_API}/${skillId}`;
|
||||
export const SKILLS_DELETE_API: (skillId: string) => string = (skillId: string) => `${SKILLS_API}/${skillId}`;
|
||||
|
||||
export const SKILLS_REGISTRY_STATS_API: string = `${SKILLS_API}/registry/stats`;
|
||||
export const SKILLS_REGISTRY_SEARCH_API: string = `${SKILLS_API}/registry/search`;
|
||||
export const SKILLS_REGISTRY_DETAIL_API: (skillName: string) => string = (skillName: string) => `${SKILLS_API}/registry/detail/${skillName}`;
|
||||
@@ -1,10 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const SUBSCRIPTIONS_API: string = `${API_BASE}/subscriptions`;
|
||||
|
||||
export const SUBSCRIPTIONS_STATUS_API: string = `${SUBSCRIPTIONS_API}/status`;
|
||||
export const SUBSCRIPTIONS_CONNECT_API: string = `${SUBSCRIPTIONS_API}/connect`;
|
||||
export const SUBSCRIPTIONS_POLL_API: string = `${SUBSCRIPTIONS_API}/poll`;
|
||||
export const SUBSCRIPTIONS_DISCONNECT_API: string = `${SUBSCRIPTIONS_API}/disconnect`;
|
||||
export const SUBSCRIPTIONS_PENDING_API: (state: string) => string = (state: string) => `${SUBSCRIPTIONS_API}/pending/${state}`;
|
||||
export const SUBSCRIPTIONS_CALLBACK_API: string = `${SUBSCRIPTIONS_API}/callback`;
|
||||
@@ -1,16 +0,0 @@
|
||||
import { API_BASE } from '@/shared/routes/base';
|
||||
|
||||
const TOOLS_API: string = `${API_BASE}/tools`;
|
||||
|
||||
export const TOOLS_BUILTIN_API: string = `${TOOLS_API}/builtin`;
|
||||
export const TOOLS_BUILTIN_PERMISSIONS_API: string = `${TOOLS_API}/builtin/permissions`;
|
||||
export const TOOLS_LIST_API: string = `${TOOLS_API}/list`;
|
||||
export const TOOLS_CREATE_API: string = `${TOOLS_API}/create`;
|
||||
export const TOOLS_GET_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}`;
|
||||
export const TOOLS_UPDATE_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}`;
|
||||
export const TOOLS_DELETE_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}`;
|
||||
export const TOOLS_DISCOVER_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}/discover`;
|
||||
export const TOOLS_LOAD_USER_TOOLKIT_API: string = `${TOOLS_API}/load_user_toolkit`;
|
||||
export const TOOLS_OAUTH_CALLBACK_API: string = `${TOOLS_API}/oauth/callback`;
|
||||
export const TOOLS_OAUTH_START_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}/oauth/start`;
|
||||
export const TOOLS_OAUTH_DISCONNECT_API: (toolId: string) => string = (toolId: string) => `${TOOLS_API}/${toolId}/oauth/disconnect`;
|
||||
@@ -42,4 +42,3 @@ export const {
|
||||
export default agentsSlice.reducer;
|
||||
|
||||
export * from './agentsTypes';
|
||||
export * from './agentsThunks';
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { API_BASE } from '@/shared/config';
|
||||
import type {
|
||||
AgentSession, AgentConfig, HistorySession,
|
||||
SendMessagePayload, LaunchAndSendPayload,
|
||||
GenerateGroupMetaPayload, SearchHistoryParams,
|
||||
} from './agentsTypes';
|
||||
|
||||
const AGENTS_API = `${API_BASE}/agents`;
|
||||
|
||||
export const fetchSessions = createAsyncThunk(
|
||||
'agents/fetchSessions',
|
||||
async ({ dashboardId }: { dashboardId?: string } = {}) => {
|
||||
const params = new URLSearchParams();
|
||||
if (dashboardId) params.set('dashboard_id', dashboardId);
|
||||
const qs = params.toString();
|
||||
const res = await fetch(`${AGENTS_API}/sessions${qs ? `?${qs}` : ''}`);
|
||||
const data = await res.json();
|
||||
return data.sessions as AgentSession[];
|
||||
},
|
||||
);
|
||||
|
||||
export const launchAgent = createAsyncThunk('agents/launchAgent', async (config: AgentConfig) => {
|
||||
const res = await fetch(`${AGENTS_API}/launch`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
});
|
||||
|
||||
export const sendMessage = createAsyncThunk(
|
||||
'agents/sendMessage',
|
||||
async ({ sessionId, prompt, mode, model, provider, images, contextPaths, forcedTools, attachedSkills, hidden, selectedBrowserIds }: SendMessagePayload) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}/message`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt, mode, model, provider, images, context_paths: contextPaths, forced_tools: forcedTools, attached_skills: attachedSkills, hidden, selected_browser_ids: selectedBrowserIds }),
|
||||
});
|
||||
return { sessionId, prompt };
|
||||
}
|
||||
);
|
||||
|
||||
export const stopAgent = createAsyncThunk(
|
||||
'agents/stopAgent',
|
||||
async ({ sessionId, removeWorktree = false }: { sessionId: string; removeWorktree?: boolean }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}/stop`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ remove_worktree: removeWorktree }),
|
||||
});
|
||||
return sessionId;
|
||||
}
|
||||
);
|
||||
|
||||
export const editMessage = createAsyncThunk(
|
||||
'agents/editMessage',
|
||||
async ({ sessionId, messageId, content }: { sessionId: string; messageId: string; content: string }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}/edit_message`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ message_id: messageId, content }),
|
||||
});
|
||||
return { sessionId, messageId, content };
|
||||
}
|
||||
);
|
||||
|
||||
export const switchBranch = createAsyncThunk(
|
||||
'agents/switchBranch',
|
||||
async ({ sessionId, branchId }: { sessionId: string; branchId: string }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}/switch_branch`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ branch_id: branchId }),
|
||||
});
|
||||
return { sessionId, branchId };
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchSession = createAsyncThunk(
|
||||
'agents/fetchSession',
|
||||
async (sessionId: string) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${sessionId}`);
|
||||
const session = await res.json();
|
||||
return session as AgentSession;
|
||||
}
|
||||
);
|
||||
|
||||
export const launchAndSendFirstMessage = createAsyncThunk(
|
||||
'agents/launchAndSendFirstMessage',
|
||||
async ({ draftId, config, prompt, mode, model, provider, images, contextPaths, forcedTools, attachedSkills, selectedBrowserIds }: LaunchAndSendPayload) => {
|
||||
const launchRes = await fetch(`${AGENTS_API}/launch`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
const launchData = await launchRes.json();
|
||||
const session = launchData.session as AgentSession;
|
||||
|
||||
await fetch(`${AGENTS_API}/sessions/${session.id}/message`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt, mode, model, provider, images, context_paths: contextPaths, forced_tools: forcedTools, attached_skills: attachedSkills, selected_browser_ids: selectedBrowserIds }),
|
||||
});
|
||||
|
||||
const refreshRes = await fetch(`${AGENTS_API}/sessions/${session.id}`);
|
||||
const updatedSession = await refreshRes.json() as AgentSession;
|
||||
|
||||
return { draftId, session: updatedSession };
|
||||
}
|
||||
);
|
||||
|
||||
export const generateTitle = createAsyncThunk(
|
||||
'agents/generateTitle',
|
||||
async ({ sessionId, prompt }: { sessionId: string; prompt: string }) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${sessionId}/generate-title`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt }),
|
||||
});
|
||||
const data = await res.json();
|
||||
return { sessionId, title: data.title as string };
|
||||
}
|
||||
);
|
||||
|
||||
export const generateGroupMeta = createAsyncThunk(
|
||||
'agents/generateGroupMeta',
|
||||
async ({ sessionId, groupId, toolCalls, resultsSummary, isRefinement }: GenerateGroupMetaPayload) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${sessionId}/generate-group-meta`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
group_id: groupId,
|
||||
tool_calls: toolCalls,
|
||||
results_summary: resultsSummary,
|
||||
is_refinement: isRefinement ?? false,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
return { sessionId, groupId, name: data.name as string, svg: data.svg as string, isRefined: data.is_refined as boolean };
|
||||
}
|
||||
);
|
||||
|
||||
export const updateSystemPrompt = createAsyncThunk(
|
||||
'agents/updateSystemPrompt',
|
||||
async ({ sessionId, systemPrompt }: { sessionId: string; systemPrompt: string }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ system_prompt: systemPrompt }),
|
||||
});
|
||||
return { sessionId, systemPrompt };
|
||||
}
|
||||
);
|
||||
|
||||
export const handleApproval = createAsyncThunk(
|
||||
'agents/handleApproval',
|
||||
async ({ requestId, behavior, message, updatedInput }: {
|
||||
requestId: string; behavior: 'allow' | 'deny'; message?: string; updatedInput?: Record<string, any>;
|
||||
}) => {
|
||||
const res = await fetch(`${AGENTS_API}/approval`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ request_id: requestId, behavior, message, updated_input: updatedInput }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`Approval request failed (${res.status})`);
|
||||
return { requestId, behavior };
|
||||
}
|
||||
);
|
||||
|
||||
export const closeSession = createAsyncThunk('agents/closeSession', async ({ sessionId }: { sessionId: string }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}/close`, { method: 'POST' });
|
||||
return sessionId;
|
||||
});
|
||||
|
||||
export const duplicateSession = createAsyncThunk(
|
||||
'agents/duplicateSession',
|
||||
async ({ sessionId, dashboardId, upToMessageId }: { sessionId: string; dashboardId?: string; upToMessageId?: string }) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${sessionId}/duplicate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ dashboard_id: dashboardId, up_to_message_id: upToMessageId }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to duplicate session');
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteSession = createAsyncThunk('agents/deleteSession', async ({ sessionId }: { sessionId: string }) => {
|
||||
await fetch(`${AGENTS_API}/sessions/${sessionId}`, { method: 'DELETE' });
|
||||
return sessionId;
|
||||
});
|
||||
|
||||
export const fetchHistory = createAsyncThunk(
|
||||
'agents/fetchHistory',
|
||||
async ({ dashboardId }: { dashboardId?: string } = {}) => {
|
||||
const params = new URLSearchParams({ limit: '10000' });
|
||||
if (dashboardId) params.set('dashboard_id', dashboardId);
|
||||
const res = await fetch(`${AGENTS_API}/history?${params}`);
|
||||
const data = await res.json();
|
||||
return data.sessions as HistorySession[];
|
||||
},
|
||||
);
|
||||
|
||||
export const searchHistory = createAsyncThunk(
|
||||
'agents/searchHistory',
|
||||
async ({ q = '', limit = 20, offset = 0, dashboardId }: SearchHistoryParams) => {
|
||||
const params = new URLSearchParams({ q, limit: String(limit), offset: String(offset) });
|
||||
if (dashboardId) params.set('dashboard_id', dashboardId);
|
||||
const res = await fetch(`${AGENTS_API}/history?${params}`);
|
||||
const data = await res.json();
|
||||
return {
|
||||
sessions: data.sessions as HistorySession[],
|
||||
total: data.total as number,
|
||||
hasMore: data.has_more as boolean,
|
||||
query: q,
|
||||
offset,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const resumeSession = createAsyncThunk(
|
||||
'agents/resumeSession',
|
||||
async ({ sessionId }: { sessionId: string }) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${sessionId}/resume`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
return data.session as AgentSession;
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchBrowserAgentChildren = createAsyncThunk(
|
||||
'agents/fetchBrowserAgentChildren',
|
||||
async (parentSessionId: string) => {
|
||||
const res = await fetch(`${AGENTS_API}/sessions/${parentSessionId}/browser-agents`);
|
||||
const data = await res.json();
|
||||
return data.sessions as AgentSession[];
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user