Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ server that `veadk frontend` launches — no separate backend.
its generated internal proxy mounts AgentKit A2A center agents dynamically
from the center ID, recall count, region, and OpenAPI endpoint. Remote names,
descriptions, and capabilities come from the returned Agent Cards.
- **Code-package deployment**: upload a ZIP project from the add-Agent menu,
inspect or edit its files in the existing code browser, then choose the
region and public/VPC network before deploying it to AgentKit. The package
must contain a root `app.py`; Studio removes a single wrapping directory,
rejects unsafe paths, and shows upload, image build, Runtime creation, and
service publishing as separate deployment stages.
- **Built-in code execution**: selecting `代码执行` adds VeADK's `run_code`
tool to generated Python and reveals the required `AGENTKIT_TOOL_ID` sandbox
field and optional `AGENTKIT_TOOL_REGION` field below the built-in tool list.
Expand Down
29 changes: 27 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ import { IntelligentCreate } from "./create/IntelligentCreate";
import { CustomCreate } from "./create/CustomCreate";
import { TemplateCreate } from "./create/TemplateCreate";
import { WorkflowCreate } from "./create/WorkflowCreate";
import { CodePackageCreate } from "./create/CodePackageCreate";
import { FileArchive } from "lucide-react";
import type { AgentDraft } from "./create/types";
import type { DeploymentTaskUpdate } from "./ui/ProjectPreview";
import { DeploymentErrorMessage } from "./ui/DeploymentErrorMessage";
Expand Down Expand Up @@ -118,14 +120,17 @@ import {

// Breadcrumb root label for the create flow and the per-mode leaf labels.
const CREATE_ROOT = "创建 Agent";
const MODE_LABEL: Record<QuickCreateKind, string> = {
type CreateMode = QuickCreateKind | "package";

const MODE_LABEL: Record<CreateMode, string> = {
intelligent: "智能模式",
custom: "自定义",
template: "从模板新建",
workflow: "工作流",
package: "代码包部署",
};

type CreateView = "menu" | QuickCreateKind | null;
type CreateView = "menu" | CreateMode | null;

// Persist the last view so a page refresh restores where the user was.
const LS = { app: "veadk.appName", view: "veadk.view", session: "veadk.sessionId" } as const;
Expand Down Expand Up @@ -2398,6 +2403,17 @@ export default function App() {
setCreateView("menu");
},
},
{
key: "package",
icon: FileArchive,
title: "从代码包添加和部署",
desc: "上传 Agent 项目压缩包,查看代码并直接部署到 AgentKit Runtime。",
onClick: () => {
setAddMenu(false);
setImportedDraft(null);
setCreateView("package");
},
},
]}
/>
) : searchView ? (
Expand Down Expand Up @@ -2476,6 +2492,15 @@ export default function App() {
<TemplateCreate onBack={() => setCreateView("menu")} onCreate={onCreate} />
) : visibleCreateView === "workflow" ? (
<WorkflowCreate onBack={() => setCreateView("menu")} onCreate={onCreate} />
) : visibleCreateView === "package" ? (
<CodePackageCreate
onBack={() => {
setCreateView(null);
setAddMenu(true);
}}
onAgentAdded={onAgentAdded}
onDeploymentTaskChange={updateDeploymentTask}
/>
) : turns.length === 0 && skillJob ? (
<SkillCreateWorkspace initialJob={skillJob} />
) : turns.length === 0 ? (
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/adk/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,12 @@ export async function deployAgentkitProject(

let res: Response;
try {
opts?.onStage?.({
level: "info",
phase: "upload",
message: "正在上传代码包",
pct: 0,
});
res = await apiFetch(
"/web/deploy-agentkit",
{
Expand All @@ -1127,6 +1133,12 @@ export async function deployAgentkitProject(
{},
0,
);
opts?.onStage?.({
level: "success",
phase: "upload",
message: "代码包上传完成",
pct: 100,
});
} catch (error) {
clearController();
throw error;
Expand Down
149 changes: 149 additions & 0 deletions frontend/src/create/CodePackageCreate.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
.package-create {
flex: 1;
min-width: 0;
min-height: 0;
display: flex;
color: hsl(var(--foreground));
}

.package-create-preview {
height: 100%;
}

.package-create-preview > * {
flex: 1;
min-width: 0;
min-height: 0;
}

.package-source-pane {
padding: 16px 18px 18px;
}

.package-source-label {
margin-bottom: 10px;
color: hsl(var(--foreground));
font-size: 15px;
font-weight: 650;
}

.package-dropzone {
min-height: 152px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 7px;
padding: 20px;
border: 1px dashed hsl(var(--border));
border-radius: 12px;
background: hsl(var(--secondary) / 0.16);
text-align: center;
cursor: pointer;
transition:
border-color 160ms ease,
background-color 160ms ease;
}

.package-dropzone:focus-visible {
outline: 2px solid hsl(var(--ring) / 0.55);
outline-offset: 3px;
}

.package-dropzone.is-dragging {
border-color: hsl(var(--primary) / 0.62);
background: hsl(var(--primary) / 0.045);
}

.package-dropzone.is-ready {
background: hsl(var(--background));
}

.package-dropzone > strong {
max-width: 100%;
overflow: hidden;
font-size: 15px;
font-weight: 650;
text-overflow: ellipsis;
white-space: nowrap;
}

.package-dropzone > span {
max-width: 420px;
color: hsl(var(--muted-foreground));
font-size: 13px;
line-height: 1.6;
}

.package-upload-actions {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin-top: 5px;
}

.package-upload-actions button {
min-height: 36px;
padding: 0 16px;
border-radius: 7px;
font: inherit;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition:
background-color 140ms ease,
border-color 140ms ease,
color 140ms ease;
}

.package-upload-secondary {
border: 1px solid hsl(var(--border));
background: hsl(var(--background));
color: hsl(var(--foreground));
}

.package-upload-secondary:hover:not(:disabled) {
border-color: hsl(var(--foreground) / 0.24);
background: hsl(var(--secondary));
}

.package-upload-actions button:disabled {
cursor: default;
opacity: 0.45;
}

.package-upload-actions button:focus-visible {
outline: 2px solid hsl(var(--ring) / 0.55);
outline-offset: 2px;
}

.package-dropzone input {
display: none;
}

.package-create-error {
flex: 0 0 auto;
margin-top: 12px;
padding: 10px 12px;
border: 1px solid hsl(var(--destructive) / 0.2);
border-radius: 8px;
background: hsl(var(--destructive) / 0.07);
color: hsl(var(--destructive));
font-size: 13px;
line-height: 1.5;
}

@media (max-width: 860px) {
.package-dropzone {
min-height: 140px;
}
}

@media (prefers-reduced-motion: reduce) {
.package-dropzone,
.package-upload-actions button {
transition: none;
}

}
Loading
Loading