Migrate agent control reads and writes to REST
This commit is contained in:
@@ -14,7 +14,11 @@ from fastapi import APIRouter, HTTPException, Depends, Body, UploadFile, File, F
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
||||||
|
from backend.agents.agent_workspace import load_agent_workspace_config
|
||||||
from backend.agents.skills_manager import SkillsManager
|
from backend.agents.skills_manager import SkillsManager
|
||||||
|
from backend.agents.toolkit_factory import load_agent_profiles
|
||||||
|
from backend.config.bootstrap_config import get_bootstrap_config_for_run
|
||||||
|
from backend.llm.models import get_agent_model_info
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -47,6 +51,14 @@ class InstallExternalSkillRequest(BaseModel):
|
|||||||
activate: bool = Field(True, description="Whether to enable skill immediately")
|
activate: bool = Field(True, description="Whether to enable skill immediately")
|
||||||
|
|
||||||
|
|
||||||
|
class LocalSkillRequest(BaseModel):
|
||||||
|
skill_name: str = Field(..., description="Local skill name")
|
||||||
|
|
||||||
|
|
||||||
|
class LocalSkillContentRequest(BaseModel):
|
||||||
|
content: str = Field(..., description="Updated SKILL.md content")
|
||||||
|
|
||||||
|
|
||||||
class AgentResponse(BaseModel):
|
class AgentResponse(BaseModel):
|
||||||
"""Agent information response."""
|
"""Agent information response."""
|
||||||
agent_id: str
|
agent_id: str
|
||||||
@@ -63,6 +75,24 @@ class AgentFileResponse(BaseModel):
|
|||||||
content: str
|
content: str
|
||||||
|
|
||||||
|
|
||||||
|
class AgentProfileResponse(BaseModel):
|
||||||
|
agent_id: str
|
||||||
|
workspace_id: str
|
||||||
|
profile: Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class AgentSkillsResponse(BaseModel):
|
||||||
|
agent_id: str
|
||||||
|
workspace_id: str
|
||||||
|
skills: List[Dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class SkillDetailResponse(BaseModel):
|
||||||
|
agent_id: str
|
||||||
|
workspace_id: str
|
||||||
|
skill: Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
def get_agent_factory():
|
def get_agent_factory():
|
||||||
"""Get AgentFactory instance."""
|
"""Get AgentFactory instance."""
|
||||||
@@ -199,6 +229,108 @@ async def get_agent(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{agent_id}/profile", response_model=AgentProfileResponse)
|
||||||
|
async def get_agent_profile(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
skills_manager: SkillsManager = Depends(get_skills_manager),
|
||||||
|
):
|
||||||
|
asset_dir = skills_manager.get_agent_asset_dir(workspace_id, agent_id)
|
||||||
|
agent_config = load_agent_workspace_config(asset_dir / "agent.yaml")
|
||||||
|
profiles = load_agent_profiles()
|
||||||
|
profile = profiles.get(agent_id, {})
|
||||||
|
bootstrap = get_bootstrap_config_for_run(skills_manager.project_root, workspace_id)
|
||||||
|
override = bootstrap.agent_override(agent_id)
|
||||||
|
active_tool_groups = override.get("active_tool_groups", agent_config.active_tool_groups or profile.get("active_tool_groups", []))
|
||||||
|
if not isinstance(active_tool_groups, list):
|
||||||
|
active_tool_groups = []
|
||||||
|
disabled_tool_groups = agent_config.disabled_tool_groups
|
||||||
|
if disabled_tool_groups:
|
||||||
|
disabled_set = set(disabled_tool_groups)
|
||||||
|
active_tool_groups = [group_name for group_name in active_tool_groups if group_name not in disabled_set]
|
||||||
|
|
||||||
|
default_skills = profile.get("skills", [])
|
||||||
|
if not isinstance(default_skills, list):
|
||||||
|
default_skills = []
|
||||||
|
resolved_skills = skills_manager.resolve_agent_skill_names(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
default_skills=default_skills,
|
||||||
|
)
|
||||||
|
prompt_files = agent_config.prompt_files or ["SOUL.md", "PROFILE.md", "AGENTS.md", "POLICY.md", "MEMORY.md"]
|
||||||
|
model_name, model_provider = get_agent_model_info(agent_id)
|
||||||
|
|
||||||
|
return AgentProfileResponse(
|
||||||
|
agent_id=agent_id,
|
||||||
|
workspace_id=workspace_id,
|
||||||
|
profile={
|
||||||
|
"model_name": model_name,
|
||||||
|
"model_provider": model_provider,
|
||||||
|
"prompt_files": prompt_files,
|
||||||
|
"default_skills": default_skills,
|
||||||
|
"resolved_skills": resolved_skills,
|
||||||
|
"active_tool_groups": active_tool_groups,
|
||||||
|
"disabled_tool_groups": disabled_tool_groups,
|
||||||
|
"enabled_skills": agent_config.enabled_skills,
|
||||||
|
"disabled_skills": agent_config.disabled_skills,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{agent_id}/skills", response_model=AgentSkillsResponse)
|
||||||
|
async def get_agent_skills(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
skills_manager: SkillsManager = Depends(get_skills_manager),
|
||||||
|
):
|
||||||
|
agent_asset_dir = skills_manager.get_agent_asset_dir(workspace_id, agent_id)
|
||||||
|
agent_config = load_agent_workspace_config(agent_asset_dir / "agent.yaml")
|
||||||
|
resolved_skills = set(skills_manager.resolve_agent_skill_names(config_name=workspace_id, agent_id=agent_id, default_skills=[]))
|
||||||
|
enabled = set(agent_config.enabled_skills)
|
||||||
|
disabled = set(agent_config.disabled_skills)
|
||||||
|
|
||||||
|
payload = []
|
||||||
|
for item in skills_manager.list_agent_skill_catalog(workspace_id, agent_id):
|
||||||
|
if item.skill_name in disabled:
|
||||||
|
status = "disabled"
|
||||||
|
elif item.skill_name in enabled:
|
||||||
|
status = "enabled"
|
||||||
|
elif item.skill_name in resolved_skills:
|
||||||
|
status = "active"
|
||||||
|
else:
|
||||||
|
status = "available"
|
||||||
|
payload.append({
|
||||||
|
"skill_name": item.skill_name,
|
||||||
|
"name": item.name,
|
||||||
|
"description": item.description,
|
||||||
|
"version": item.version,
|
||||||
|
"source": item.source,
|
||||||
|
"tools": item.tools,
|
||||||
|
"status": status,
|
||||||
|
})
|
||||||
|
|
||||||
|
return AgentSkillsResponse(agent_id=agent_id, workspace_id=workspace_id, skills=payload)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{agent_id}/skills/{skill_name}", response_model=SkillDetailResponse)
|
||||||
|
async def get_agent_skill_detail(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
skill_name: str,
|
||||||
|
skills_manager: SkillsManager = Depends(get_skills_manager),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
detail = skills_manager.load_agent_skill_document(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
skill_name=skill_name,
|
||||||
|
)
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Unknown skill: {skill_name}")
|
||||||
|
|
||||||
|
return SkillDetailResponse(agent_id=agent_id, workspace_id=workspace_id, skill=detail)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{agent_id}")
|
@router.delete("/{agent_id}")
|
||||||
async def delete_agent(
|
async def delete_agent(
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
@@ -386,6 +518,85 @@ async def install_external_skill(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/{agent_id}/skills/local")
|
||||||
|
async def create_local_skill(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
request: LocalSkillRequest,
|
||||||
|
registry=Depends(get_registry),
|
||||||
|
):
|
||||||
|
agent_info = registry.get(agent_id)
|
||||||
|
if not agent_info or agent_info.workspace_id != workspace_id:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Agent '{agent_id}' not found")
|
||||||
|
|
||||||
|
skills_manager = SkillsManager()
|
||||||
|
try:
|
||||||
|
skills_manager.create_agent_local_skill(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
skill_name=request.skill_name,
|
||||||
|
)
|
||||||
|
except (ValueError, FileExistsError) as exc:
|
||||||
|
raise HTTPException(status_code=400, detail=str(exc))
|
||||||
|
|
||||||
|
return {"message": f"Created local skill '{request.skill_name}' for '{agent_id}'"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/{agent_id}/skills/local/{skill_name}")
|
||||||
|
async def update_local_skill(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
skill_name: str,
|
||||||
|
request: LocalSkillContentRequest,
|
||||||
|
registry=Depends(get_registry),
|
||||||
|
):
|
||||||
|
agent_info = registry.get(agent_id)
|
||||||
|
if not agent_info or agent_info.workspace_id != workspace_id:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Agent '{agent_id}' not found")
|
||||||
|
|
||||||
|
skills_manager = SkillsManager()
|
||||||
|
try:
|
||||||
|
skills_manager.update_agent_local_skill(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
skill_name=skill_name,
|
||||||
|
content=request.content,
|
||||||
|
)
|
||||||
|
except (ValueError, FileNotFoundError) as exc:
|
||||||
|
raise HTTPException(status_code=400, detail=str(exc))
|
||||||
|
|
||||||
|
return {"message": f"Updated local skill '{skill_name}' for '{agent_id}'"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/{agent_id}/skills/local/{skill_name}")
|
||||||
|
async def delete_local_skill(
|
||||||
|
workspace_id: str,
|
||||||
|
agent_id: str,
|
||||||
|
skill_name: str,
|
||||||
|
registry=Depends(get_registry),
|
||||||
|
):
|
||||||
|
agent_info = registry.get(agent_id)
|
||||||
|
if not agent_info or agent_info.workspace_id != workspace_id:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Agent '{agent_id}' not found")
|
||||||
|
|
||||||
|
skills_manager = SkillsManager()
|
||||||
|
try:
|
||||||
|
skills_manager.delete_agent_local_skill(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
skill_name=skill_name,
|
||||||
|
)
|
||||||
|
skills_manager.forget_agent_skill_overrides(
|
||||||
|
config_name=workspace_id,
|
||||||
|
agent_id=agent_id,
|
||||||
|
skill_names=[skill_name],
|
||||||
|
)
|
||||||
|
except (ValueError, FileNotFoundError) as exc:
|
||||||
|
raise HTTPException(status_code=400, detail=str(exc))
|
||||||
|
|
||||||
|
return {"message": f"Deleted local skill '{skill_name}' for '{agent_id}'"}
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{agent_id}/skills/upload")
|
@router.post("/{agent_id}/skills/upload")
|
||||||
async def upload_external_skill(
|
async def upload_external_skill(
|
||||||
workspace_id: str,
|
workspace_id: str,
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Runtime/workspace/skills handlers extracted from the main Gateway module."""
|
"""Runtime/workspace/skills handlers extracted from the main Gateway module.
|
||||||
|
|
||||||
|
Deprecated note:
|
||||||
|
Agent/workspace/skill read-write operations are being migrated to
|
||||||
|
agent_service REST endpoints. These websocket handlers remain as a
|
||||||
|
compatibility fallback and should not be considered the primary control
|
||||||
|
plane path for frontend reads/writes.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
from backend.apps.agent_service import create_app
|
from backend.apps.agent_service import create_app
|
||||||
|
from backend.api import agents as agents_module
|
||||||
|
|
||||||
|
|
||||||
def test_agent_service_routes_include_control_plane_endpoints(tmp_path):
|
def test_agent_service_routes_include_control_plane_endpoints(tmp_path):
|
||||||
@@ -25,3 +26,79 @@ def test_agent_service_excludes_runtime_routes(tmp_path):
|
|||||||
|
|
||||||
assert "/api/runtime/start" not in paths
|
assert "/api/runtime/start" not in paths
|
||||||
assert "/api/runtime/gateway/port" not in paths
|
assert "/api/runtime/gateway/port" not in paths
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_service_read_routes(monkeypatch, tmp_path):
|
||||||
|
class _FakeSkillsManager:
|
||||||
|
project_root = tmp_path
|
||||||
|
|
||||||
|
def get_agent_asset_dir(self, config_name, agent_id):
|
||||||
|
return tmp_path / "runs" / config_name / "agents" / agent_id
|
||||||
|
|
||||||
|
def resolve_agent_skill_names(self, config_name, agent_id, default_skills=None):
|
||||||
|
return ["demo_skill"]
|
||||||
|
|
||||||
|
def list_agent_skill_catalog(self, config_name, agent_id):
|
||||||
|
return [
|
||||||
|
type(
|
||||||
|
"Skill",
|
||||||
|
(),
|
||||||
|
{
|
||||||
|
"skill_name": "demo_skill",
|
||||||
|
"name": "Demo Skill",
|
||||||
|
"description": "demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": "builtin",
|
||||||
|
"tools": [],
|
||||||
|
},
|
||||||
|
)()
|
||||||
|
]
|
||||||
|
|
||||||
|
def load_agent_skill_document(self, config_name, agent_id, skill_name):
|
||||||
|
return {"skill_name": skill_name, "content": "# demo"}
|
||||||
|
|
||||||
|
class _FakeWorkspaceManager:
|
||||||
|
def load_agent_file(self, config_name, agent_id, filename):
|
||||||
|
return f"{config_name}:{agent_id}:{filename}"
|
||||||
|
|
||||||
|
monkeypatch.setattr(agents_module, "load_agent_profiles", lambda: {"portfolio_manager": {"skills": ["demo_skill"]}})
|
||||||
|
monkeypatch.setattr(agents_module, "get_agent_model_info", lambda agent_id: ("deepseek-v3.2", "DASHSCOPE"))
|
||||||
|
monkeypatch.setattr(
|
||||||
|
agents_module,
|
||||||
|
"load_agent_workspace_config",
|
||||||
|
lambda path: type(
|
||||||
|
"Cfg",
|
||||||
|
(),
|
||||||
|
{
|
||||||
|
"active_tool_groups": ["portfolio_ops"],
|
||||||
|
"disabled_tool_groups": [],
|
||||||
|
"enabled_skills": [],
|
||||||
|
"disabled_skills": [],
|
||||||
|
"prompt_files": ["SOUL.md", "MEMORY.md"],
|
||||||
|
},
|
||||||
|
)(),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
agents_module,
|
||||||
|
"get_bootstrap_config_for_run",
|
||||||
|
lambda project_root, config_name: type("Bootstrap", (), {"agent_override": lambda self, agent_id: {}})(),
|
||||||
|
)
|
||||||
|
|
||||||
|
app = create_app(project_root=tmp_path)
|
||||||
|
app.dependency_overrides[agents_module.get_skills_manager] = lambda: _FakeSkillsManager()
|
||||||
|
app.dependency_overrides[agents_module.get_workspace_manager] = lambda: _FakeWorkspaceManager()
|
||||||
|
|
||||||
|
with TestClient(app) as client:
|
||||||
|
profile = client.get("/api/workspaces/demo/agents/portfolio_manager/profile")
|
||||||
|
skills = client.get("/api/workspaces/demo/agents/portfolio_manager/skills")
|
||||||
|
detail = client.get("/api/workspaces/demo/agents/portfolio_manager/skills/demo_skill")
|
||||||
|
workspace_file = client.get("/api/workspaces/demo/agents/portfolio_manager/files/MEMORY.md")
|
||||||
|
|
||||||
|
assert profile.status_code == 200
|
||||||
|
assert profile.json()["profile"]["model_name"] == "deepseek-v3.2"
|
||||||
|
assert skills.status_code == 200
|
||||||
|
assert skills.json()["skills"][0]["skill_name"] == "demo_skill"
|
||||||
|
assert detail.status_code == 200
|
||||||
|
assert detail.json()["skill"]["content"] == "# demo"
|
||||||
|
assert workspace_file.status_code == 200
|
||||||
|
assert workspace_file.json()["content"] == "demo:portfolio_manager:MEMORY.md"
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { uploadAgentSkillZip } from '../services/runtimeApi';
|
import {
|
||||||
|
createAgentLocalSkill,
|
||||||
|
deleteAgentLocalSkill,
|
||||||
|
disableAgentSkill,
|
||||||
|
enableAgentSkill,
|
||||||
|
fetchAgentProfile,
|
||||||
|
fetchAgentSkillDetail,
|
||||||
|
fetchAgentSkills,
|
||||||
|
fetchAgentWorkspaceFile,
|
||||||
|
fetchCurrentRuntime,
|
||||||
|
updateAgentLocalSkill,
|
||||||
|
updateAgentWorkspaceFile,
|
||||||
|
uploadAgentSkillZip
|
||||||
|
} from '../services/runtimeApi';
|
||||||
import { useAgentStore } from '../store/agentStore';
|
import { useAgentStore } from '../store/agentStore';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,12 +23,16 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
const {
|
const {
|
||||||
selectedSkillAgentId,
|
selectedSkillAgentId,
|
||||||
setSelectedSkillAgentId,
|
setSelectedSkillAgentId,
|
||||||
|
setAgentProfilesByAgent,
|
||||||
setIsAgentSkillsLoading,
|
setIsAgentSkillsLoading,
|
||||||
setAgentSkillsFeedback,
|
setAgentSkillsFeedback,
|
||||||
setAgentSkillsSavingKey,
|
setAgentSkillsSavingKey,
|
||||||
setSkillDetailLoadingKey,
|
setSkillDetailLoadingKey,
|
||||||
|
setAgentSkillsByAgent,
|
||||||
|
setSkillDetailsByName,
|
||||||
localSkillDraftsByKey,
|
localSkillDraftsByKey,
|
||||||
selectedWorkspaceFile,
|
selectedWorkspaceFile,
|
||||||
|
setWorkspaceFilesByAgent,
|
||||||
setWorkspaceDraftContent,
|
setWorkspaceDraftContent,
|
||||||
workspaceDraftContent,
|
workspaceDraftContent,
|
||||||
setWorkspaceFileFeedback,
|
setWorkspaceFileFeedback,
|
||||||
@@ -23,27 +40,88 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
setIsWorkspaceFileLoading
|
setIsWorkspaceFileLoading
|
||||||
} = useAgentStore();
|
} = useAgentStore();
|
||||||
|
|
||||||
|
const resolveWorkspaceId = useCallback(async () => {
|
||||||
|
const runtime = await fetchCurrentRuntime();
|
||||||
|
const workspaceId = runtime?.run_id;
|
||||||
|
if (!workspaceId) {
|
||||||
|
throw new Error('未检测到正在运行的任务');
|
||||||
|
}
|
||||||
|
return workspaceId;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const requestAgentSkills = useCallback((agentId) => {
|
const requestAgentSkills = useCallback((agentId) => {
|
||||||
const normalized = typeof agentId === 'string' ? agentId.trim() : '';
|
const normalized = typeof agentId === 'string' ? agentId.trim() : '';
|
||||||
if (!normalized || !clientRef.current) return false;
|
if (!normalized) return false;
|
||||||
setIsAgentSkillsLoading(true);
|
setIsAgentSkillsLoading(true);
|
||||||
setAgentSkillsFeedback(null);
|
setAgentSkillsFeedback(null);
|
||||||
return clientRef.current.send({ type: 'get_agent_skills', agent_id: normalized });
|
void resolveWorkspaceId()
|
||||||
}, [clientRef, setIsAgentSkillsLoading, setAgentSkillsFeedback]);
|
.then((workspaceId) => fetchAgentSkills(workspaceId, normalized))
|
||||||
|
.then((payload) => {
|
||||||
|
setAgentSkillsByAgent((prev) => ({ ...prev, [normalized]: Array.isArray(payload?.skills) ? payload.skills : [] }));
|
||||||
|
setIsAgentSkillsLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setIsAgentSkillsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST agent skills request failed, falling back to websocket compatibility path');
|
||||||
|
const success = clientRef.current.send({ type: 'get_agent_skills', agent_id: normalized });
|
||||||
|
if (!success) {
|
||||||
|
setIsAgentSkillsLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}, [clientRef, resolveWorkspaceId, setAgentSkillsByAgent, setIsAgentSkillsLoading, setAgentSkillsFeedback]);
|
||||||
|
|
||||||
const requestAgentProfile = useCallback((agentId) => {
|
const requestAgentProfile = useCallback((agentId) => {
|
||||||
const normalized = typeof agentId === 'string' ? agentId.trim() : '';
|
const normalized = typeof agentId === 'string' ? agentId.trim() : '';
|
||||||
if (!normalized || !clientRef.current) return false;
|
if (!normalized) return false;
|
||||||
return clientRef.current.send({ type: 'get_agent_profile', agent_id: normalized });
|
void resolveWorkspaceId()
|
||||||
}, [clientRef]);
|
.then((workspaceId) => fetchAgentProfile(workspaceId, normalized))
|
||||||
|
.then((payload) => {
|
||||||
|
setAgentProfilesByAgent((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[normalized]: payload?.profile && typeof payload.profile === 'object' ? payload.profile : {}
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (clientRef.current) {
|
||||||
|
console.debug('REST agent profile request failed, falling back to websocket compatibility path');
|
||||||
|
clientRef.current.send({ type: 'get_agent_profile', agent_id: normalized });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}, [clientRef, resolveWorkspaceId, setAgentProfilesByAgent]);
|
||||||
|
|
||||||
const requestSkillDetail = useCallback((skillName) => {
|
const requestSkillDetail = useCallback((skillName) => {
|
||||||
const normalized = typeof skillName === 'string' ? skillName.trim() : '';
|
const normalized = typeof skillName === 'string' ? skillName.trim() : '';
|
||||||
if (!normalized || !clientRef.current) return false;
|
if (!normalized) return false;
|
||||||
const detailKey = `${selectedSkillAgentId}:${normalized}`;
|
const detailKey = `${selectedSkillAgentId}:${normalized}`;
|
||||||
setSkillDetailLoadingKey(detailKey);
|
setSkillDetailLoadingKey(detailKey);
|
||||||
return clientRef.current.send({ type: 'get_skill_detail', agent_id: selectedSkillAgentId, skill_name: normalized });
|
void resolveWorkspaceId()
|
||||||
}, [clientRef, selectedSkillAgentId, setSkillDetailLoadingKey]);
|
.then((workspaceId) => fetchAgentSkillDetail(workspaceId, selectedSkillAgentId, normalized))
|
||||||
|
.then((payload) => {
|
||||||
|
setSkillDetailsByName((prev) => ({ ...prev, [detailKey]: payload?.skill || null }));
|
||||||
|
useAgentStore.getState().setLocalSkillDraftsByKey((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[detailKey]: typeof payload?.skill?.content === 'string' ? payload.skill.content : ''
|
||||||
|
}));
|
||||||
|
setSkillDetailLoadingKey(null);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setSkillDetailLoadingKey(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST skill detail request failed, falling back to websocket compatibility path');
|
||||||
|
const success = clientRef.current.send({ type: 'get_skill_detail', agent_id: selectedSkillAgentId, skill_name: normalized });
|
||||||
|
if (!success) {
|
||||||
|
setSkillDetailLoadingKey(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}, [clientRef, resolveWorkspaceId, selectedSkillAgentId, setSkillDetailLoadingKey, setSkillDetailsByName]);
|
||||||
|
|
||||||
const handleCreateLocalSkill = useCallback((skillName) => {
|
const handleCreateLocalSkill = useCallback((skillName) => {
|
||||||
const normalized = typeof skillName === 'string' ? skillName.trim() : '';
|
const normalized = typeof skillName === 'string' ? skillName.trim() : '';
|
||||||
@@ -51,18 +129,30 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
setAgentSkillsFeedback({ type: 'error', text: '技能名称不能为空' });
|
setAgentSkillsFeedback({ type: 'error', text: '技能名称不能为空' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${normalized}:create`);
|
||||||
|
setAgentSkillsFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => createAgentLocalSkill(workspaceId, selectedSkillAgentId, normalized))
|
||||||
|
.then(() => {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'success', text: `已创建本地技能 ${normalized}` });
|
||||||
|
requestAgentSkills(selectedSkillAgentId);
|
||||||
|
requestSkillDetail(normalized);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
if (!clientRef.current) {
|
if (!clientRef.current) {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${normalized}:create`);
|
console.debug('REST local skill create failed, falling back to websocket compatibility path');
|
||||||
setAgentSkillsFeedback(null);
|
|
||||||
const success = clientRef.current.send({ type: 'create_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: normalized });
|
const success = clientRef.current.send({ type: 'create_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: normalized });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setAgentSkillsSavingKey(null);
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
});
|
||||||
|
}, [clientRef, requestAgentSkills, requestSkillDetail, resolveWorkspaceId, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
||||||
|
|
||||||
const handleLocalSkillDraftChange = useCallback((skillName, content) => {
|
const handleLocalSkillDraftChange = useCallback((skillName, content) => {
|
||||||
const detailKey = `${selectedSkillAgentId}:${skillName}`;
|
const detailKey = `${selectedSkillAgentId}:${skillName}`;
|
||||||
@@ -70,64 +160,110 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
}, [selectedSkillAgentId]);
|
}, [selectedSkillAgentId]);
|
||||||
|
|
||||||
const handleLocalSkillSave = useCallback((skillName) => {
|
const handleLocalSkillSave = useCallback((skillName) => {
|
||||||
if (!clientRef.current) {
|
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const detailKey = `${selectedSkillAgentId}:${skillName}`;
|
const detailKey = `${selectedSkillAgentId}:${skillName}`;
|
||||||
const content = localSkillDraftsByKey[detailKey];
|
const content = localSkillDraftsByKey[detailKey];
|
||||||
if (typeof content !== 'string') return;
|
if (typeof content !== 'string') return;
|
||||||
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:content`);
|
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:content`);
|
||||||
setAgentSkillsFeedback(null);
|
setAgentSkillsFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => updateAgentLocalSkill(workspaceId, selectedSkillAgentId, skillName, content))
|
||||||
|
.then(() => {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'success', text: `${selectedSkillAgentId} 的本地技能 ${skillName} 已保存` });
|
||||||
|
requestSkillDetail(skillName);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST local skill save failed, falling back to websocket compatibility path');
|
||||||
const success = clientRef.current.send({ type: 'update_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: skillName, content });
|
const success = clientRef.current.send({ type: 'update_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: skillName, content });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setAgentSkillsSavingKey(null);
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, localSkillDraftsByKey, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
});
|
||||||
|
}, [clientRef, localSkillDraftsByKey, requestSkillDetail, resolveWorkspaceId, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
||||||
|
|
||||||
const handleLocalSkillDelete = useCallback((skillName) => {
|
const handleLocalSkillDelete = useCallback((skillName) => {
|
||||||
|
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:delete`);
|
||||||
|
setAgentSkillsFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => deleteAgentLocalSkill(workspaceId, selectedSkillAgentId, skillName))
|
||||||
|
.then(() => {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'success', text: `${selectedSkillAgentId} 的本地技能 ${skillName} 已删除` });
|
||||||
|
requestAgentSkills(selectedSkillAgentId);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
if (!clientRef.current) {
|
if (!clientRef.current) {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:delete`);
|
console.debug('REST local skill delete failed, falling back to websocket compatibility path');
|
||||||
setAgentSkillsFeedback(null);
|
|
||||||
const success = clientRef.current.send({ type: 'delete_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: skillName });
|
const success = clientRef.current.send({ type: 'delete_agent_local_skill', agent_id: selectedSkillAgentId, skill_name: skillName });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setAgentSkillsSavingKey(null);
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
});
|
||||||
|
}, [clientRef, requestAgentSkills, resolveWorkspaceId, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
||||||
|
|
||||||
const handleRemoveSharedSkill = useCallback((skillName) => {
|
const handleRemoveSharedSkill = useCallback((skillName) => {
|
||||||
|
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:remove`);
|
||||||
|
setAgentSkillsFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => disableAgentSkill(workspaceId, selectedSkillAgentId, skillName))
|
||||||
|
.then(() => {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'success', text: `${selectedSkillAgentId} 已移除共享技能 ${skillName}` });
|
||||||
|
requestAgentSkills(selectedSkillAgentId);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
if (!clientRef.current) {
|
if (!clientRef.current) {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setAgentSkillsSavingKey(`${selectedSkillAgentId}:${skillName}:remove`);
|
console.debug('REST shared skill remove failed, falling back to websocket compatibility path');
|
||||||
setAgentSkillsFeedback(null);
|
|
||||||
const success = clientRef.current.send({ type: 'remove_agent_skill', agent_id: selectedSkillAgentId, skill_name: skillName });
|
const success = clientRef.current.send({ type: 'remove_agent_skill', agent_id: selectedSkillAgentId, skill_name: skillName });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setAgentSkillsSavingKey(null);
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
});
|
||||||
|
}, [clientRef, requestAgentSkills, resolveWorkspaceId, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
||||||
|
|
||||||
const handleAgentSkillToggle = useCallback((skillName, enabled) => {
|
const handleAgentSkillToggle = useCallback((skillName, enabled) => {
|
||||||
if (!clientRef.current) {
|
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const agentId = selectedSkillAgentId;
|
const agentId = selectedSkillAgentId;
|
||||||
setAgentSkillsSavingKey(`${agentId}:${skillName}`);
|
setAgentSkillsSavingKey(`${agentId}:${skillName}`);
|
||||||
setAgentSkillsFeedback(null);
|
setAgentSkillsFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => enabled
|
||||||
|
? enableAgentSkill(workspaceId, agentId, skillName)
|
||||||
|
: disableAgentSkill(workspaceId, agentId, skillName))
|
||||||
|
.then(() => {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'success', text: `${agentId} ${enabled ? '已启用' : '已禁用'} ${skillName}` });
|
||||||
|
requestAgentSkills(agentId);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setAgentSkillsSavingKey(null);
|
||||||
|
setAgentSkillsFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST skill toggle failed, falling back to websocket compatibility path');
|
||||||
const success = clientRef.current.send({ type: 'update_agent_skill', agent_id: agentId, skill_name: skillName, enabled });
|
const success = clientRef.current.send({ type: 'update_agent_skill', agent_id: agentId, skill_name: skillName, enabled });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setAgentSkillsSavingKey(null);
|
setAgentSkillsSavingKey(null);
|
||||||
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setAgentSkillsFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
});
|
||||||
|
}, [clientRef, requestAgentSkills, resolveWorkspaceId, selectedSkillAgentId, setAgentSkillsFeedback, setAgentSkillsSavingKey]);
|
||||||
|
|
||||||
const handleSkillAgentChange = useCallback((agentId) => {
|
const handleSkillAgentChange = useCallback((agentId) => {
|
||||||
setSelectedSkillAgentId(agentId);
|
setSelectedSkillAgentId(agentId);
|
||||||
@@ -139,11 +275,35 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
const requestWorkspaceFile = useCallback((agentId, filename) => {
|
const requestWorkspaceFile = useCallback((agentId, filename) => {
|
||||||
const normalizedAgentId = typeof agentId === 'string' ? agentId.trim() : '';
|
const normalizedAgentId = typeof agentId === 'string' ? agentId.trim() : '';
|
||||||
const normalizedFilename = typeof filename === 'string' ? filename.trim() : '';
|
const normalizedFilename = typeof filename === 'string' ? filename.trim() : '';
|
||||||
if (!normalizedAgentId || !normalizedFilename || !clientRef.current) return false;
|
if (!normalizedAgentId || !normalizedFilename) return false;
|
||||||
setIsWorkspaceFileLoading(true);
|
setIsWorkspaceFileLoading(true);
|
||||||
setWorkspaceFileFeedback(null);
|
setWorkspaceFileFeedback(null);
|
||||||
return clientRef.current.send({ type: 'get_agent_workspace_file', agent_id: normalizedAgentId, filename: normalizedFilename });
|
void resolveWorkspaceId()
|
||||||
}, [clientRef, setIsWorkspaceFileLoading, setWorkspaceFileFeedback]);
|
.then((workspaceId) => fetchAgentWorkspaceFile(workspaceId, normalizedAgentId, normalizedFilename))
|
||||||
|
.then((payload) => {
|
||||||
|
setWorkspaceFilesByAgent((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[normalizedAgentId]: {
|
||||||
|
...(prev[normalizedAgentId] || {}),
|
||||||
|
[normalizedFilename]: typeof payload?.content === 'string' ? payload.content : ''
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
setWorkspaceDraftContent(typeof payload?.content === 'string' ? payload.content : '');
|
||||||
|
setIsWorkspaceFileLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setIsWorkspaceFileLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST workspace file read failed, falling back to websocket compatibility path');
|
||||||
|
const success = clientRef.current.send({ type: 'get_agent_workspace_file', agent_id: normalizedAgentId, filename: normalizedFilename });
|
||||||
|
if (!success) {
|
||||||
|
setIsWorkspaceFileLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}, [clientRef, resolveWorkspaceId, setIsWorkspaceFileLoading, setWorkspaceDraftContent, setWorkspaceFileFeedback, setWorkspaceFilesByAgent]);
|
||||||
|
|
||||||
const handleWorkspaceFileChange = useCallback((filename) => {
|
const handleWorkspaceFileChange = useCallback((filename) => {
|
||||||
useAgentStore.getState().setSelectedWorkspaceFile(filename);
|
useAgentStore.getState().setSelectedWorkspaceFile(filename);
|
||||||
@@ -151,13 +311,29 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
}, [requestWorkspaceFile, selectedSkillAgentId]);
|
}, [requestWorkspaceFile, selectedSkillAgentId]);
|
||||||
|
|
||||||
const handleWorkspaceFileSave = useCallback(() => {
|
const handleWorkspaceFileSave = useCallback(() => {
|
||||||
if (!clientRef.current) {
|
|
||||||
setWorkspaceFileFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const key = `${selectedSkillAgentId}:${selectedWorkspaceFile}`;
|
const key = `${selectedSkillAgentId}:${selectedWorkspaceFile}`;
|
||||||
setWorkspaceFileSavingKey(key);
|
setWorkspaceFileSavingKey(key);
|
||||||
setWorkspaceFileFeedback(null);
|
setWorkspaceFileFeedback(null);
|
||||||
|
void resolveWorkspaceId()
|
||||||
|
.then((workspaceId) => updateAgentWorkspaceFile(workspaceId, selectedSkillAgentId, selectedWorkspaceFile, workspaceDraftContent))
|
||||||
|
.then((payload) => {
|
||||||
|
setWorkspaceFileSavingKey(null);
|
||||||
|
setWorkspaceFileFeedback({ type: 'success', text: `${selectedSkillAgentId} 的 ${selectedWorkspaceFile} 已保存` });
|
||||||
|
setWorkspaceFilesByAgent((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[selectedSkillAgentId]: {
|
||||||
|
...(prev[selectedSkillAgentId] || {}),
|
||||||
|
[selectedWorkspaceFile]: typeof payload?.content === 'string' ? payload.content : workspaceDraftContent
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!clientRef.current) {
|
||||||
|
setWorkspaceFileSavingKey(null);
|
||||||
|
setWorkspaceFileFeedback({ type: 'error', text: '连接未就绪,稍后重试' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug('REST workspace file save failed, falling back to websocket compatibility path');
|
||||||
const success = clientRef.current.send({
|
const success = clientRef.current.send({
|
||||||
type: 'update_agent_workspace_file',
|
type: 'update_agent_workspace_file',
|
||||||
agent_id: selectedSkillAgentId,
|
agent_id: selectedSkillAgentId,
|
||||||
@@ -168,7 +344,8 @@ export function useAgentDataRequests(clientRef) {
|
|||||||
setWorkspaceFileSavingKey(null);
|
setWorkspaceFileSavingKey(null);
|
||||||
setWorkspaceFileFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
setWorkspaceFileFeedback({ type: 'error', text: '发送失败,请检查连接状态' });
|
||||||
}
|
}
|
||||||
}, [clientRef, selectedSkillAgentId, selectedWorkspaceFile, setWorkspaceFileFeedback, setWorkspaceFileSavingKey, workspaceDraftContent]);
|
});
|
||||||
|
}, [clientRef, resolveWorkspaceId, selectedSkillAgentId, selectedWorkspaceFile, setWorkspaceFileFeedback, setWorkspaceFileSavingKey, setWorkspaceFilesByAgent, workspaceDraftContent]);
|
||||||
|
|
||||||
const handleUploadExternalSkill = useCallback(async (file) => {
|
const handleUploadExternalSkill = useCallback(async (file) => {
|
||||||
if (!(file instanceof File)) {
|
if (!(file instanceof File)) {
|
||||||
|
|||||||
@@ -129,6 +129,69 @@ export function fetchRuntimeLogs() {
|
|||||||
return safeFetch(RUNTIME_API_BASE, '/logs');
|
return safeFetch(RUNTIME_API_BASE, '/logs');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchAgentProfile(workspaceId, agentId) {
|
||||||
|
return safeFetch(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/profile`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAgentSkills(workspaceId, agentId) {
|
||||||
|
return safeFetch(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAgentSkillDetail(workspaceId, agentId, skillName) {
|
||||||
|
return safeFetch(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/${encodeURIComponent(skillName)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAgentWorkspaceFile(workspaceId, agentId, filename) {
|
||||||
|
return safeFetch(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/files/${encodeURIComponent(filename)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAgentLocalSkill(workspaceId, agentId, skillName) {
|
||||||
|
return safeRequest(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/local`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ skill_name: skillName })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateAgentLocalSkill(workspaceId, agentId, skillName, content) {
|
||||||
|
return safeRequest(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/local/${encodeURIComponent(skillName)}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ content })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteAgentLocalSkill(workspaceId, agentId, skillName) {
|
||||||
|
return safeRequest(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/local/${encodeURIComponent(skillName)}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enableAgentSkill(workspaceId, agentId, skillName) {
|
||||||
|
return safeRequest(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/${encodeURIComponent(skillName)}/enable`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableAgentSkill(workspaceId, agentId, skillName) {
|
||||||
|
return safeRequest(CONTROL_API_BASE, `/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/skills/${encodeURIComponent(skillName)}/disable`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateAgentWorkspaceFile(workspaceId, agentId, filename, content) {
|
||||||
|
return fetch(`${CONTROL_API_BASE}/workspaces/${encodeURIComponent(workspaceId)}/agents/${encodeURIComponent(agentId)}/files/${encodeURIComponent(filename)}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain'
|
||||||
|
},
|
||||||
|
body: content
|
||||||
|
}).then(async (response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(await response.text());
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function uploadAgentSkillZip({
|
export async function uploadAgentSkillZip({
|
||||||
agentId,
|
agentId,
|
||||||
file,
|
file,
|
||||||
|
|||||||
Reference in New Issue
Block a user