Compare commits

..

2 Commits

Author SHA1 Message Date
42d8b8e8e1 bug fixes 2026-03-13 13:57:00 +08:00
da6cc1e18b deepagent backend configurable 2026-03-13 13:56:24 +08:00
6 changed files with 173 additions and 38 deletions

View File

@@ -172,7 +172,7 @@ uvicorn fastapi_server.server_dashscope:app --reload --host 0.0.0.0 --port 8588
uvicorn fastapi_server.combined:app --reload --host 0.0.0.0 --port 8500 uvicorn fastapi_server.combined:app --reload --host 0.0.0.0 --port 8500
``` ```
You can change the URL by setting `VITE_FRONT_API_BASE_URL` in `frontend/.env` (defaults to `http://127.0.0.1:8500`). You can change the URL by setting `VITE_FRONT_API_BASE_URL` in `frontend/.env` (defaults to `/`, i.e. same-origin).
### Start the development server ### Start the development server

View File

@@ -4,10 +4,16 @@ WORKDIR /app
RUN npm config set registry https://registry.npmmirror.com RUN npm config set registry https://registry.npmmirror.com
# Build-time API base for Vite (must be set before npm run build).
ARG VITE_FRONT_API_BASE_URL=/
ENV VITE_FRONT_API_BASE_URL=${VITE_FRONT_API_BASE_URL}
COPY package*.json ./ COPY package*.json ./
RUN npm install RUN npm install
COPY . . COPY . .
RUN npm run build RUN npm run build && \
mkdir -p /opt/frontend_dist && \
cp -r dist/. /opt/frontend_dist/
CMD ["ls", "dist"] CMD ["sh", "-c", "rm -rf /app/dist/* && cp -r /opt/frontend_dist/. /app/dist && ls /app/dist"]

View File

@@ -25,7 +25,7 @@ services:
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 5 retries: 5
restart: unless-stopped restart: no #unless-stopped
# Backend API server # Backend API server
backend: backend:
@@ -52,7 +52,7 @@ services:
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
restart: unless-stopped restart: no #unless-stopped
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8500/health"] test: ["CMD", "curl", "-f", "http://localhost:8500/health"]
interval: 30s interval: 30s
@@ -65,6 +65,8 @@ services:
build: build:
context: ../frontend context: ../frontend
dockerfile: ../docker/Dockerfile.frontend dockerfile: ../docker/Dockerfile.frontend
args:
VITE_FRONT_API_BASE_URL: ${VITE_FRONT_API_BASE_URL:-/}
volumes: volumes:
- frontend_dist:/app/dist - frontend_dist:/app/dist
networks: networks:
@@ -86,7 +88,7 @@ services:
condition: service_completed_successfully condition: service_completed_successfully
backend: backend:
condition: service_started condition: service_started
restart: unless-stopped restart: no #unless-stopped
volumes: volumes:
postgres_data: postgres_data:

View File

@@ -41,6 +41,7 @@ type EditableAgent = {
apiKey: string; apiKey: string;
llmName: string; llmName: string;
actBackend: DeepAgentActBackend; actBackend: DeepAgentActBackend;
fileBackendConfig: FileBackendConfig;
}; };
type AgentChatMessage = { type AgentChatMessage = {
@@ -51,6 +52,13 @@ type AgentChatMessage = {
type ActiveTab = "agents" | "discussions" | "mcp"; type ActiveTab = "agents" | "discussions" | "mcp";
type DeepAgentActBackend = "state_bk" | "local_shell" | "daytona_sandbox"; type DeepAgentActBackend = "state_bk" | "local_shell" | "daytona_sandbox";
type FileBackendConfig = {
skills_dir: string;
rt_skills_dir: string;
workspace_dir?: string;
api_key?: string;
};
type McpTransport = "streamable_http" | "sse" | "stdio"; type McpTransport = "streamable_http" | "sse" | "stdio";
type McpEntry = { type McpEntry = {
id: string; id: string;
@@ -74,7 +82,24 @@ const DEEPAGENT_BACKEND_OPTIONS: Array<{
{ value: "local_shell", label: "local_shell" }, { value: "local_shell", label: "local_shell" },
{ value: "daytona_sandbox", label: "daytona_sandbox" }, { value: "daytona_sandbox", label: "daytona_sandbox" },
]; ];
const LOCAL_DASHSCOPE_BASE = "http://127.0.0.1:8500/v1/apps";
const DEFAULT_FILE_BACKEND_CONFIG: Record<DeepAgentActBackend, FileBackendConfig> = {
state_bk: {
skills_dir: "./assets/skills",
rt_skills_dir: "/skills",
},
local_shell: {
skills_dir: "./workspace/skills",
rt_skills_dir: "/skills",
workspace_dir: "./workspace",
},
daytona_sandbox: {
skills_dir: "./workspace/skills",
rt_skills_dir: "",
api_key: "",
},
};
const LOCAL_DASHSCOPE_BASE = "/v1/apps";
const MCP_TRANSPORT_OPTIONS: McpTransport[] = ["streamable_http", "sse", "stdio"]; const MCP_TRANSPORT_OPTIONS: McpTransport[] = ["streamable_http", "sse", "stdio"];
const GRAPH_ARCH_IMAGE_MODULES = import.meta.glob( const GRAPH_ARCH_IMAGE_MODULES = import.meta.glob(
"../assets/images/graph_arch/*.{png,jpg,jpeg,webp,gif}", "../assets/images/graph_arch/*.{png,jpg,jpeg,webp,gif}",
@@ -442,7 +467,10 @@ function normalizeDeepAgentActBackend(value: unknown): DeepAgentActBackend {
function buildGraphParams(editor: EditableAgent): Record<string, unknown> { function buildGraphParams(editor: EditableAgent): Record<string, unknown> {
if (editor.graphId === "deepagent") { if (editor.graphId === "deepagent") {
return { act_bkend: editor.actBackend }; return {
act_bkend: editor.actBackend,
file_backend_config: editor.fileBackendConfig,
};
} }
return {}; return {};
} }
@@ -465,6 +493,7 @@ function toEditable(
apiKey: config.api_key || DEFAULT_API_KEY, apiKey: config.api_key || DEFAULT_API_KEY,
llmName: DEFAULT_LLM_NAME, llmName: DEFAULT_LLM_NAME,
actBackend: DEFAULT_DEEPAGENT_ACT_BACKEND, actBackend: DEFAULT_DEEPAGENT_ACT_BACKEND,
fileBackendConfig: DEFAULT_FILE_BACKEND_CONFIG[DEFAULT_DEEPAGENT_ACT_BACKEND],
}; };
} }
@@ -757,6 +786,10 @@ export default function App() {
graphId === "deepagent" graphId === "deepagent"
? prev.actBackend || DEFAULT_DEEPAGENT_ACT_BACKEND ? prev.actBackend || DEFAULT_DEEPAGENT_ACT_BACKEND
: DEFAULT_DEEPAGENT_ACT_BACKEND, : DEFAULT_DEEPAGENT_ACT_BACKEND,
fileBackendConfig:
graphId === "deepagent"
? prev.fileBackendConfig || DEFAULT_FILE_BACKEND_CONFIG[DEFAULT_DEEPAGENT_ACT_BACKEND]
: DEFAULT_FILE_BACKEND_CONFIG[DEFAULT_DEEPAGENT_ACT_BACKEND],
}; };
if (next.isDraft) { if (next.isDraft) {
setDraftAgents((drafts) => drafts.map((draft) => (draft.id === next.id ? next : draft))); setDraftAgents((drafts) => drafts.map((draft) => (draft.id === next.id ? next : draft)));
@@ -790,6 +823,24 @@ export default function App() {
setEditorAndSyncDraft((prev) => ({ ...prev, [key]: value })); setEditorAndSyncDraft((prev) => ({ ...prev, [key]: value }));
} }
function updateActBackend(newBackend: DeepAgentActBackend): void {
setEditorAndSyncDraft((prev) => ({
...prev,
actBackend: newBackend,
fileBackendConfig: DEFAULT_FILE_BACKEND_CONFIG[newBackend],
}));
}
function updateFileBackendConfig(key: keyof FileBackendConfig, value: string): void {
setEditorAndSyncDraft((prev) => ({
...prev,
fileBackendConfig: {
...prev.fileBackendConfig,
[key]: value,
},
}));
}
function updatePrompt(key: string, value: string): void { function updatePrompt(key: string, value: string): void {
setEditorAndSyncDraft((prev) => ({ setEditorAndSyncDraft((prev) => ({
...prev, ...prev,
@@ -1404,15 +1455,13 @@ export default function App() {
</label> </label>
{editor.graphId === "deepagent" ? ( {editor.graphId === "deepagent" ? (
<>
<label> <label>
act_bkend act_bkend
<select <select
value={editor.actBackend} value={editor.actBackend}
onChange={(e) => onChange={(e) =>
updateEditor( updateActBackend(normalizeDeepAgentActBackend(e.target.value))
"actBackend",
normalizeDeepAgentActBackend(e.target.value)
)
} }
disabled={busy} disabled={busy}
> >
@@ -1423,6 +1472,52 @@ export default function App() {
))} ))}
</select> </select>
</label> </label>
<div className="file-backend-config">
<h3>File Backend Config</h3>
{editor.actBackend === "daytona_sandbox" ? (
<label>
api_key
<input
type="password"
value={editor.fileBackendConfig.api_key || ""}
onChange={(e) => updateFileBackendConfig("api_key", e.target.value)}
placeholder="Daytona API key"
disabled={busy}
/>
</label>
) : null}
{editor.actBackend === "local_shell" ? (
<label>
workspace_dir
<input
value={editor.fileBackendConfig.workspace_dir || ""}
onChange={(e) => updateFileBackendConfig("workspace_dir", e.target.value)}
placeholder="./workspace"
disabled={busy}
/>
</label>
) : null}
<label>
skills_dir
<input
value={editor.fileBackendConfig.skills_dir || ""}
onChange={(e) => updateFileBackendConfig("skills_dir", e.target.value)}
placeholder="./assets/skills"
disabled={busy}
/>
</label>
<label>
rt_skills_dir
<input
value={editor.fileBackendConfig.rt_skills_dir || ""}
onChange={(e) => updateFileBackendConfig("rt_skills_dir", e.target.value)}
placeholder="/skills"
disabled={busy}
/>
</label>
</div>
</>
) : null} ) : null}
<div className="prompt-section"> <div className="prompt-section">

View File

@@ -224,6 +224,7 @@ button:disabled {
} }
.prompt-section, .prompt-section,
.file-backend-config,
.run-info { .run-info {
border: 1px solid #dbe2ea; border: 1px solid #dbe2ea;
border-radius: 10px; border-radius: 10px;
@@ -232,6 +233,7 @@ button:disabled {
} }
.prompt-section h3, .prompt-section h3,
.file-backend-config h3,
.run-info h3 { .run-info h3 {
margin-top: 0; margin-top: 0;
} }

View File

@@ -1,4 +1,4 @@
from typing import Any, Dict, List, Literal from typing import Any, Dict, List, Literal, Optional
import os import os
import os.path as osp import os.path as osp
import subprocess import subprocess
@@ -158,6 +158,7 @@ def build_deep_agent(
"daytona_sandbox", "daytona_sandbox",
"daytonasandbox", "daytonasandbox",
] = "state_bk", ] = "state_bk",
file_backend_config: Optional[Dict[str, Any]] = None,
**_: Any, **_: Any,
): ):
backend_subcommand = _DEEP_AGENT_BACKEND_ALIASES.get(act_bkend) backend_subcommand = _DEEP_AGENT_BACKEND_ALIASES.get(act_bkend)
@@ -185,11 +186,40 @@ def build_deep_agent(
cmd_opt.extend( cmd_opt.extend(
["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys] ["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys]
) )
# Same greedy-list behavior as `build_route`; terminate before backend subcommand.
cmd_opt.extend(["--pipeline-id", pipeline_id]) cmd_opt.extend(["--pipeline-id", pipeline_id])
cmd_opt.append(backend_subcommand) cmd_opt.append(backend_subcommand)
if file_backend_config:
if "skills_dir" in file_backend_config and file_backend_config["skills_dir"]:
cmd_opt.extend(
["--file-backend-config.skills-dir", file_backend_config["skills_dir"]]
)
if (
"rt_skills_dir" in file_backend_config
and file_backend_config["rt_skills_dir"]
):
cmd_opt.extend(
[
"--file-backend-config.rt-skills-dir",
file_backend_config["rt_skills_dir"],
]
)
if (
"workspace_dir" in file_backend_config
and file_backend_config["workspace_dir"]
):
cmd_opt.extend(
[
"--file-backend-config.workspace-dir",
file_backend_config["workspace_dir"],
]
)
if "api_key" in file_backend_config and file_backend_config["api_key"]:
cmd_opt.extend(
["--file-backend-config.api-key", file_backend_config["api_key"]]
)
return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt) return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt)