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
71 changes: 67 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@ import {
type SandboxThreadSummary,
type SandboxToolLaunch,
} from "./adk/sandbox";
import { getSandboxCapability } from "./adk/newChatCapabilities";
import {
getSandboxAgentCapability,
getSandboxCapability,
} from "./adk/newChatCapabilities";
import { getSkillWorkbenchCapability } from "./ui/skill-workbench/api";
import {
createVideoTask,
Expand Down Expand Up @@ -250,14 +253,21 @@ interface NewChatCapabilitiesState {
harnessEnabled?: boolean;
builtinTools?: string[];
temporaryEnabled?: boolean;
deepseekHarnessEnabled?: boolean;
skillCustomizationEnabled?: boolean;
}

async function probeNewChatCapabilities(
agentId: string,
): Promise<NewChatCapabilitiesState> {
const [sandboxResult, skillResult, harnessResult] = await Promise.allSettled([
const [
sandboxResult,
deepseekHarnessResult,
skillResult,
harnessResult,
] = await Promise.allSettled([
getSandboxCapability(),
getSandboxAgentCapability("deepseek-harness"),
getSkillWorkbenchCapability(),
agentId ? listSessionBuiltinTools(agentId) : Promise.resolve<string[]>([]),
]);
Expand All @@ -268,6 +278,9 @@ async function probeNewChatCapabilities(
builtinTools: harnessResult.status === "fulfilled" ? harnessResult.value : [],
temporaryEnabled:
sandboxResult.status === "fulfilled" && sandboxResult.value.enabled,
deepseekHarnessEnabled:
deepseekHarnessResult.status === "fulfilled" &&
deepseekHarnessResult.value.enabled,
skillCustomizationEnabled:
skillResult.status === "fulfilled" && skillResult.value.enabled,
};
Expand Down Expand Up @@ -2849,7 +2862,7 @@ export default function App() {
setSandboxLaunchError("");
if (
!sandboxSession &&
newChatMode === "temporary" &&
newChatMode !== "agent" &&
!sandboxLaunchFromAgents
) {
setNewChatMode("agent");
Expand Down Expand Up @@ -2890,7 +2903,40 @@ export default function App() {
setMyAgents(true);
return;
}
if (sandboxLaunchKind !== "codex") return;
if (sandboxLaunchKind !== "codex") {
const workspace = await sandboxClient.openAgentSession(
sandboxLaunchKind,
createdSession.id,
{ signal: controller.signal },
);
if (sandboxLaunchAbortRef.current !== controller) return;
viewSidRef.current = "";
setSessionId("");
setPendingTurns([]);
setInput("");
setInvocation(emptyInvocation());
setNewChatMode(
sandboxLaunchKind === "deepseek-harness" ? "deepseek-harness" : "agent",
);
discardDraftAttachments(attachments);
setAttachments([]);
releaseAllSandboxPreviews();
setSandboxTurns([]);
setSandboxSession(null);
setCreateView(null);
setSkillCenter(false);
setAddAgent(false);
setAddMenu(false);
setSearchView(false);
setManageAgents(false);
setAgentDetailTarget(null);
setMyAgents(false);
setSandboxAgentDetailTarget(null);
setSandboxAgentWorkspace(workspace);
setSandboxLaunchOpen(false);
setSandboxLaunchState("confirm");
return;
}
const nextSession = await sandboxClient.connectSession(createdSession.id, {
signal: controller.signal,
});
Expand Down Expand Up @@ -4998,6 +5044,8 @@ export default function App() {
agentName={
sandboxSession.toolName === "codex"
? "Codex"
: sandboxSession.toolName === "deepseek-harness"
? "DeepSeek Harness"
: sandboxSession.toolName === "openclaw"
? "OpenClaw"
: "Hermes"
Expand Down Expand Up @@ -5120,6 +5168,7 @@ export default function App() {
? false
: !userId ||
newChatMode === "temporary" ||
newChatMode === "deepseek-harness" ||
(newChatWorkspaceMode === "agent" &&
newChatMode === "agent" &&
!appName) ||
Expand Down Expand Up @@ -5200,6 +5249,10 @@ export default function App() {
onSkillActionChange={setNewChatSkillAction}
onSkillTargetChange={setNewChatSkillTarget}
temporaryEnabled={newChatCapabilitiesReady && newChatCapabilities.temporaryEnabled}
deepseekHarnessEnabled={
newChatCapabilitiesReady &&
newChatCapabilities.deepseekHarnessEnabled
}
harnessEnabled={newChatCapabilitiesReady && newChatCapabilities.harnessEnabled}
builtinTools={
newChatCapabilitiesReady ? newChatCapabilities.builtinTools : []
Expand All @@ -5212,6 +5265,16 @@ export default function App() {
openSandboxLaunch();
return;
}
if (
mode === "deepseek-harness" &&
!newChatCapabilities.deepseekHarnessEnabled
) return;
if (mode === "deepseek-harness") {
setNewChatTask(null);
setNewChatMode(mode);
openSandboxLaunch("deepseek-harness");
return;
}
setNewChatMode(mode);
if (mode !== "agent") setNewChatTask(null);
setError("");
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/adk/newChatCapabilities.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { withAuth } from "./auth";
import { withLocalUser } from "./identity";
import type { SandboxAgentKind } from "./sandbox";
import { requestSignal } from "./timeout";

const CAPABILITY_TIMEOUT_MS = 10_000;
Expand Down Expand Up @@ -30,3 +31,9 @@ async function getCapability(path: string): Promise<NewChatModeCapability> {
export async function getSandboxCapability(): Promise<NewChatModeCapability> {
return getCapability("/web/sandbox/capabilities");
}

export async function getSandboxAgentCapability(
kind: SandboxAgentKind,
): Promise<NewChatModeCapability> {
return getCapability(`/web/${kind}/capabilities`);
}
2 changes: 1 addition & 1 deletion frontend/src/adk/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const SETTINGS_TIMEOUT_MS = 60_000;
const UPLOAD_TIMEOUT_MS = 330_000;

export const SANDBOX_DISPLAY_NAME_MAX_LENGTH = 40;
export type SandboxAgentKind = "openclaw" | "hermes";
export type SandboxAgentKind = "deepseek-harness" | "openclaw" | "hermes";

export function sandboxStatusLabel(status: string): string {
switch (status.trim().toLowerCase()) {
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/telemetry/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export interface AgentDeployFailedProps {
errorCode?: string;
}

export type SandboxKind = "codex" | "openclaw" | "hermes";
export type SandboxKind = "codex" | "deepseek-harness" | "openclaw" | "hermes";

export interface SandboxCreateStartedProps {
sandboxKind: SandboxKind;
Expand Down Expand Up @@ -138,6 +138,7 @@ export type AgentConnectKind =
| "runtime"
| "local"
| "codex"
| "deepseek-harness"
| "openclaw"
| "hermes";
export type AgentConnectSource =
Expand Down Expand Up @@ -179,7 +180,7 @@ export interface AgentConnectFailedProps {

export interface AgentMessageStartedProps {
agentId: string;
agentKind: "runtime" | "codex" | "openclaw" | "hermes";
agentKind: "runtime" | "codex" | "deepseek-harness" | "openclaw" | "hermes";
messageSource: "composer" | "a2ui_action";
sessionState: "new" | "existing";
sessionId?: string;
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/ui/Composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export interface ComposerProps {
onModeChange?: (value: NewChatMode) => void;
onTaskChange?: (value: NewChatTask | null) => void;
temporaryEnabled?: boolean;
deepseekHarnessEnabled?: boolean;
harnessEnabled?: boolean;
builtinTools?: readonly string[];
showAgentPicker?: boolean;
Expand Down Expand Up @@ -212,6 +213,7 @@ export function Composer({
onModeChange,
onTaskChange,
temporaryEnabled,
deepseekHarnessEnabled,
harnessEnabled = false,
builtinTools = [],
showAgentPicker = false,
Expand Down Expand Up @@ -753,6 +755,7 @@ export function Composer({
onChange={onModeChange}
disabled={busy}
temporaryEnabled={temporaryEnabled}
deepseekHarnessEnabled={deepseekHarnessEnabled}
/>
) : null}

Expand Down
8 changes: 7 additions & 1 deletion frontend/src/ui/MyAgents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ export interface MyAgentCardData {
draft?: WorkspaceAgentDraft;
}

export type AgentType = "general" | "codex" | "openclaw" | "hermes";
export type AgentType =
| "general"
| "codex"
| "deepseek-harness"
| "openclaw"
| "hermes";

const AGENT_TYPES: Array<{ id: AgentType; label: string }> = [
{ id: "general", label: "通用智能体" },
{ id: "codex", label: "Codex 智能体" },
{ id: "deepseek-harness", label: "DeepSeek Harness" },
{ id: "openclaw", label: "OpenClaw 智能体" },
{ id: "hermes", label: "Hermes 智能体" },
];
Expand Down
1 change: 1 addition & 0 deletions frontend/src/ui/SandboxAgentDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "./SandboxAgentDetails.css";

const AGENT_LABELS = {
codex: "Codex",
"deepseek-harness": "DeepSeek Harness",
openclaw: "OpenClaw",
hermes: "Hermes",
} as const;
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/ui/SandboxAgentWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export function SandboxAgentWorkspace({
const [terminalUrl, setTerminalUrl] = useState("");
const [terminalLoading, setTerminalLoading] = useState(false);
const [terminalError, setTerminalError] = useState("");
const label = workspace.kind === "openclaw" ? "OpenClaw" : "Hermes";
const label = workspace.kind === "deepseek-harness"
? "DeepSeek Harness"
: workspace.kind === "openclaw" ? "OpenClaw" : "Hermes";

useEffect(() => {
setSurface("main");
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/ui/SandboxLaunchDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export function SandboxLaunchDialog({
}: SandboxLaunchDialogProps) {
const agentLabel = agentKind === "codex"
? "Codex"
: agentKind === "openclaw" ? "OpenClaw" : "Hermes";
: agentKind === "deepseek-harness"
? "DeepSeek Harness"
: agentKind === "openclaw" ? "OpenClaw" : "Hermes";
const defaultDisplayName = agentKind === "codex"
? DEFAULT_SANDBOX_DISPLAY_NAME
: `我的 ${agentLabel}`;
Expand Down
27 changes: 26 additions & 1 deletion frontend/src/ui/icons/SandboxAgentIcons.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { SVGProps } from "react";

export type SandboxAgentIconKind = "codex" | "openclaw" | "hermes";
export type SandboxAgentIconKind =
| "codex"
| "deepseek-harness"
| "openclaw"
| "hermes";

export function CodexAgentIcon(props: SVGProps<SVGSVGElement>) {
return (
Expand Down Expand Up @@ -60,11 +64,32 @@ export function HermesAgentIcon(props: SVGProps<SVGSVGElement>) {
);
}

export function DeepSeekHarnessAgentIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.75"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
{...props}
>
<path d="M5.2 17.2V8.1a3 3 0 0 1 3-3h7.6a3 3 0 0 1 3 3v9.1" />
<path d="M7.4 17.2h9.2M9 19.9h6" />
<path d="M9.1 9.25h5.8M9.1 12h3.1" />
<path d="m14.1 12.4 2 2.1M16.2 12.4l-2.1 2.1" />
</svg>
);
}

export function SandboxAgentIcon({
kind,
...props
}: SVGProps<SVGSVGElement> & { kind: SandboxAgentIconKind }) {
if (kind === "codex") return <CodexAgentIcon {...props} />;
if (kind === "deepseek-harness") return <DeepSeekHarnessAgentIcon {...props} />;
if (kind === "openclaw") return <OpenClawAgentIcon {...props} />;
return <HermesAgentIcon {...props} />;
}
8 changes: 7 additions & 1 deletion frontend/src/ui/new-chat-modes/NewChatAgentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import { AgentFaceIcon } from "../AgentFaceIcon";
import { SandboxAgentIcon } from "../icons/SandboxAgentIcons";
import "./new-chat-agent-picker.css";

type AgentType = "general" | "codex" | "openclaw" | "hermes";
type AgentType =
| "general"
| "codex"
| "deepseek-harness"
| "openclaw"
| "hermes";

interface AgentTypeOption {
id: AgentType;
Expand All @@ -26,6 +31,7 @@ interface AgentTypeOption {
const AGENT_TYPES: AgentTypeOption[] = [
{ id: "general", label: "通用智能体" },
{ id: "codex", label: "Codex 智能体" },
{ id: "deepseek-harness", label: "DeepSeek Harness" },
{ id: "openclaw", label: "OpenClaw 智能体" },
{ id: "hermes", label: "Hermes 智能体" },
];
Expand Down
Loading
Loading