feat(desktop): support Claude Code OpenClaw and Hermes ACP
This commit is contained in:
1 parent
578ca26ed8
commit
5d4cd4386c
11 files changed
+126
-39
No files matched your search
@@ -13,7 +13,10 @@ import { startAcpMcpBridge } from "./acp-mcp-bridge.mjs";
|
||||
|
||||
const ADAPTERS = {
|
||||
codex: { id: "codex", label: "Codex" },
|
||||
claudeCode: { id: "claudeCode", label: "Claude Code" },
|
||||
antigravity: { id: "antigravity", label: "Antigravity" },
|
||||
openClaw: { id: "openClaw", label: "OpenClaw" },
|
||||
hermesAgent: { id: "hermesAgent", label: "Hermes Agent" },
|
||||
grokBuild: { id: "grokBuild", label: "Grok Build" },
|
||||
deepseekHarness: { id: "deepseekHarness", label: "DeepSeek Harness" },
|
||||
piAgent: { id: "piAgent", label: "pi agent" },
|
||||
@@ -125,7 +128,10 @@ export function resolveAcpCommand(input, deps = {}) {
|
||||
const id = input?.id;
|
||||
if (!Object.hasOwn(ADAPTERS, id)) return { ok: false, state: "failed", detail: "unknown_adapter" };
|
||||
if (id === "codex") return resolveCodex(input?.path, resolved);
|
||||
if (id === "claudeCode") return resolveAgentCli("claude-agent-acp", [], resolved);
|
||||
if (id === "antigravity") return resolveAntigravity(input?.path, resolved);
|
||||
if (id === "openClaw") return resolveAgentCli("openclaw", ["acp"], resolved);
|
||||
if (id === "hermesAgent") return resolveAgentCli("hermes", ["acp"], resolved);
|
||||
if (id === "grokBuild") return resolveGrok(input?.path, resolved);
|
||||
if (id === "deepseekHarness") return resolveLocalAcpCli("dsh", ["--profile", "acp"], resolved);
|
||||
if (id === "piAgent") {
|
||||
@@ -159,6 +165,14 @@ function resolveLocalAcpCli(name, args, deps) {
|
||||
: { command: executable, args } };
|
||||
}
|
||||
|
||||
function resolveAgentCli(name, args, deps) {
|
||||
const result = resolveLocalAcpCli(name, args, deps);
|
||||
if (!result.ok || deps.platform === "win32") return result;
|
||||
// Desktop launchers may omit the directories containing node or agent shims.
|
||||
const paths = [path.join(deps.home, ".local", "bin"), ...(deps.platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : []), deps.pathEnv];
|
||||
return { ...result, command: { ...result.command, env: { ...result.command.env, PATH: paths.join(":") } } };
|
||||
}
|
||||
|
||||
function withPiPath(command, deps) {
|
||||
if (deps.platform === "win32" || findOnPath(["pi"], deps)) return command;
|
||||
const candidates = [path.join(deps.home, ".local", "bin", "pi"), ...(deps.platform === "darwin" ? ["/opt/homebrew/bin/pi", "/usr/local/bin/pi"] : [])];
|
||||
@@ -738,7 +752,7 @@ export function createAcpHostRuntime(options = {}) {
|
||||
|
||||
return {
|
||||
listAdapters() {
|
||||
return ["codex", "antigravity", "grokBuild", "deepseekHarness", "piAgent", "workbuddyCn", "workbuddyIntl"].map((id) => {
|
||||
return ["codex", "claudeCode", "antigravity", "openClaw", "hermesAgent", "grokBuild", "deepseekHarness", "piAgent", "workbuddyCn", "workbuddyIntl"].map((id) => {
|
||||
if (installingIds.has(id)) return { ...adapterShell(id), state: "installing" };
|
||||
const resolved = resolveCommand({ id });
|
||||
return resolved.ok
|
||||
@@ -870,7 +884,8 @@ export function createAcpHostRuntime(options = {}) {
|
||||
let connected;
|
||||
let mcpBridge;
|
||||
try {
|
||||
if (options.mcpAccess) {
|
||||
// OpenClaw's ACP Gateway bridge rejects session-scoped MCP servers.
|
||||
if (options.mcpAccess && input.adapterId !== "openClaw") {
|
||||
const access = await options.mcpAccess();
|
||||
mcpBridge = await (options.startMcpBridge ?? startAcpMcpBridge)(access);
|
||||
}
|
||||
|
||||
@@ -266,6 +266,23 @@ describe("ACP command allow-list", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("resolves the three additional ACP entry points from installed commands", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "edgeever-acp-extra-"));
|
||||
try {
|
||||
for (const name of ["claude-agent-acp", "openclaw", "hermes"]) {
|
||||
await writeFile(path.join(directory, name), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
|
||||
}
|
||||
const deps = { platform: "darwin", pathEnv: directory, home: directory };
|
||||
expect(resolveAcpCommand({ id: "claudeCode" }, deps).command).toMatchObject({ command: realpathSync(path.join(directory, "claude-agent-acp")), args: [] });
|
||||
expect(resolveAcpCommand({ id: "openClaw" }, deps).command).toMatchObject({ command: realpathSync(path.join(directory, "openclaw")), args: ["acp"] });
|
||||
expect(resolveAcpCommand({ id: "hermesAgent" }, deps).command).toMatchObject({ command: realpathSync(path.join(directory, "hermes")), args: ["acp"] });
|
||||
expect(resolveAcpCommand({ id: "openClaw" }, deps).command.env.PATH).toContain(path.join(directory, ".local", "bin"));
|
||||
expect(resolveAcpCommand({ id: "openClaw" }, { ...deps, pathEnv: "" }).state).toBe("not_installed");
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("automatically installs only a detected agent missing its ACP connector", async () => {
|
||||
let installed = false;
|
||||
let installs = 0;
|
||||
@@ -623,6 +640,35 @@ describe("ACP stdio session", () => {
|
||||
}
|
||||
}, 15_000);
|
||||
|
||||
sessionTest("keeps OpenClaw ACP sessions free of unsupported session MCP servers", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "edgeever-openclaw-acp-"));
|
||||
const reportPath = path.join(directory, "report.json");
|
||||
try {
|
||||
const scriptPath = await writeFakeAgent(directory, {
|
||||
reportPath,
|
||||
secretPath: path.join(directory, "secret.txt"),
|
||||
allowImage: false,
|
||||
allowEmbedded: false,
|
||||
hold: false,
|
||||
});
|
||||
const executable = path.join(directory, "openclaw");
|
||||
await writeFile(executable, await readFile(scriptPath), { mode: 0o755 });
|
||||
const runtime = createAcpHostRuntime({
|
||||
pathEnv: directory,
|
||||
home: directory,
|
||||
mcpAccess: () => { throw new Error("OpenClaw must use Gateway MCP configuration"); },
|
||||
});
|
||||
const events = collector();
|
||||
await runtime.prompt({ adapterId: "openClaw", prompt: "Hello" }, events.emit);
|
||||
await events.waitFor((event) => event.type === "done");
|
||||
const report = await readReport(reportPath);
|
||||
expect(report.newSession.mcpServers).toEqual([]);
|
||||
expect(report.prompt).toEqual([{ type: "text", text: "Hello" }]);
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
}, 15_000);
|
||||
|
||||
sessionTest("offers advertised agent login and verifies a session after authentication", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "edgeever-acp-auth-"));
|
||||
const reportPath = path.join(directory, "report.json");
|
||||
|
||||
@@ -351,7 +351,7 @@ function AiSidebarThreadMenu({
|
||||
|
||||
const readLocalAdapter = (): { id: DesktopAcpAdapterId; path?: string } | null => {
|
||||
const id = readStorage(AI_SIDEBAR_ADAPTER_KEY);
|
||||
if (id !== "codex" && id !== "antigravity" && id !== "grokBuild" && id !== "deepseekHarness" && id !== "piAgent" && id !== "workbuddyCn" && id !== "workbuddyIntl") return null;
|
||||
if (id !== "codex" && id !== "claudeCode" && id !== "antigravity" && id !== "openClaw" && id !== "hermesAgent" && id !== "grokBuild" && id !== "deepseekHarness" && id !== "piAgent" && id !== "workbuddyCn" && id !== "workbuddyIntl") return null;
|
||||
const path = readStorage(AI_SIDEBAR_ADAPTER_PATH_KEY)?.trim();
|
||||
return id === "antigravity" && path ? { id, path } : { id };
|
||||
};
|
||||
|
||||
@@ -27,18 +27,7 @@ import {
|
||||
SETTINGS_ITEM_TITLE_CLASSNAME,
|
||||
} from "./settings-ui";
|
||||
|
||||
const adapterIds: DesktopAcpAdapterId[] = ["codex", "antigravity", "grokBuild", "deepseekHarness", "piAgent", "workbuddyCn", "workbuddyIntl"];
|
||||
|
||||
const agentCatalog = [
|
||||
{ id: "codex", connectable: true },
|
||||
{ id: "antigravity", connectable: true },
|
||||
{ id: "claudeCode", connectable: false },
|
||||
{ id: "workbuddyCn", connectable: true },
|
||||
{ id: "workbuddyIntl", connectable: true },
|
||||
{ id: "grokBuild", connectable: true },
|
||||
{ id: "deepseekHarness", connectable: true },
|
||||
{ id: "piAgent", connectable: true },
|
||||
] as const;
|
||||
const adapterIds: DesktopAcpAdapterId[] = ["codex", "claudeCode", "antigravity", "openClaw", "hermesAgent", "grokBuild", "deepseekHarness", "piAgent", "workbuddyCn", "workbuddyIntl"];
|
||||
|
||||
const readSource = (): AiSidebarSource => (
|
||||
localStorage.getItem(AI_SIDEBAR_SOURCE_KEY) === "local" ? "local" : "builtin"
|
||||
@@ -55,6 +44,9 @@ const statusKey = (adapter: DesktopAcpAdapter | undefined, probing: boolean) =>
|
||||
if (adapter.detail === "invalid_path") return "aiAssistant.agentSource.invalidPath";
|
||||
if (adapter.detail === "desktop_unavailable") return "aiAssistant.agentSource.localDisabled";
|
||||
if (adapter.id === "grokBuild" && adapter.state === "not_installed") return "aiAssistant.agentSource.grokBuildNotFound";
|
||||
if (adapter.id === "claudeCode" && adapter.state === "not_installed") return "aiAssistant.agentSource.claudeCodeNotFound";
|
||||
if (adapter.id === "openClaw" && adapter.state === "not_installed") return "aiAssistant.agentSource.openClawNotFound";
|
||||
if (adapter.id === "hermesAgent" && adapter.state === "not_installed") return "aiAssistant.agentSource.hermesAgentNotFound";
|
||||
if (adapter.id === "deepseekHarness" && adapter.state === "not_installed") return "aiAssistant.agentSource.deepseekHarnessNotFound";
|
||||
if (adapter.id === "piAgent" && adapter.state === "not_installed") return adapter.detail === "adapter_missing" ? "aiAssistant.agentSource.piAgentAdapterMissing" : "aiAssistant.agentSource.piAgentNotFound";
|
||||
if ((adapter.id === "workbuddyCn" || adapter.id === "workbuddyIntl") && adapter.state === "not_installed") return "aiAssistant.agentSource.workbuddyNotFound";
|
||||
@@ -240,10 +232,10 @@ const DesktopAcpAgentCardBody = ({ bridge }: { bridge: boolean }) => {
|
||||
</label>
|
||||
{disabled ? (
|
||||
<div role="group" className="flex flex-wrap gap-2 px-3.5 pb-3 pl-9" aria-label={t("aiAssistant.agentSource.adapter")}>
|
||||
{agentCatalog.map((agent) => (
|
||||
<span key={agent.id} className="flex h-8 items-center gap-2 rounded-md border border-slate-200 px-2.5 text-xs text-slate-500">
|
||||
{adapterIds.map((id) => (
|
||||
<span key={id} className="flex h-8 items-center gap-2 rounded-md border border-slate-200 px-2.5 text-xs text-slate-500">
|
||||
<span aria-hidden="true" className="h-1.5 w-1.5 rounded-full bg-slate-300" />
|
||||
{t(`aiAssistant.agentSource.${agent.id}`)}
|
||||
{t(`aiAssistant.agentSource.${id}`)}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@@ -279,12 +271,6 @@ const DesktopAcpAgentCardBody = ({ bridge }: { bridge: boolean }) => {
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
{agentCatalog.filter((agent) => !agent.connectable).map((agent) => (
|
||||
<span key={agent.id} className="flex h-8 cursor-not-allowed items-center gap-2 rounded-md border border-slate-200 px-2.5 text-xs text-slate-400">
|
||||
<span aria-hidden="true" className="h-1.5 w-1.5 rounded-full bg-slate-300" />
|
||||
{t(`aiAssistant.agentSource.${agent.id}`)}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{adapterId === "antigravity" ? (
|
||||
@@ -374,7 +360,7 @@ const DesktopAcpAgentCardBody = ({ bridge }: { bridge: boolean }) => {
|
||||
<div className="space-y-2">
|
||||
{shown?.state === "not_installed" ? (
|
||||
<p className="text-xs leading-relaxed text-slate-600">
|
||||
{t(adapterId === "grokBuild" ? "aiAssistant.agentSource.grokBuildMissingHint" : adapterId === "deepseekHarness" ? "aiAssistant.agentSource.deepseekHarnessMissingHint" : adapterId === "piAgent" ? shown.detail === "adapter_missing" ? "aiAssistant.agentSource.piAgentAdapterMissingHint" : "aiAssistant.agentSource.piAgentMissingHint" : adapterId === "workbuddyCn" || adapterId === "workbuddyIntl" ? "aiAssistant.agentSource.workbuddyMissingHint" : "aiAssistant.agentSource.installHint")}
|
||||
{t(adapterId === "claudeCode" ? "aiAssistant.agentSource.claudeCodeMissingHint" : adapterId === "openClaw" ? "aiAssistant.agentSource.openClawMissingHint" : adapterId === "hermesAgent" ? "aiAssistant.agentSource.hermesAgentMissingHint" : adapterId === "grokBuild" ? "aiAssistant.agentSource.grokBuildMissingHint" : adapterId === "deepseekHarness" ? "aiAssistant.agentSource.deepseekHarnessMissingHint" : adapterId === "piAgent" ? shown.detail === "adapter_missing" ? "aiAssistant.agentSource.piAgentAdapterMissingHint" : "aiAssistant.agentSource.piAgentMissingHint" : adapterId === "workbuddyCn" || adapterId === "workbuddyIntl" ? "aiAssistant.agentSource.workbuddyMissingHint" : "aiAssistant.agentSource.installHint")}
|
||||
</p>
|
||||
) : null}
|
||||
{shown?.state === "needs_login" && adapterId === "piAgent" ? (
|
||||
@@ -400,6 +386,12 @@ const DesktopAcpAgentCardBody = ({ bridge }: { bridge: boolean }) => {
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{adapterId === "openClaw" ? (
|
||||
<p className="text-xs leading-relaxed text-amber-700">{t("aiAssistant.agentSource.openClawNoteAccessHint")}</p>
|
||||
) : null}
|
||||
{adapterId === "hermesAgent" && (shown?.state === "failed" || shown?.state === "needs_login") ? (
|
||||
<p className="text-xs leading-relaxed text-amber-700">{t("aiAssistant.agentSource.hermesAgentSetupHint")}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type DesktopAcpAdapterId = "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
export type DesktopAcpAdapterId = "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
export type DesktopAcpAdapterState = "not_installed" | "installing" | "needs_login" | "available" | "failed";
|
||||
|
||||
export type DesktopAcpPromptCapabilities = {
|
||||
|
||||
Vendored
+6
-6
@@ -92,7 +92,7 @@ interface EdgeEverDesktopBridge {
|
||||
finishWeChatImport?(importId: string, success: boolean): Promise<void>;
|
||||
retryWeChatImport?(importId: string): Promise<boolean>;
|
||||
listAcpAdapters?(): Promise<Array<{
|
||||
id: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
id: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
label: string;
|
||||
state: "not_installed" | "installing" | "needs_login" | "available" | "failed";
|
||||
detail?: string;
|
||||
@@ -102,8 +102,8 @@ interface EdgeEverDesktopBridge {
|
||||
updateError?: string;
|
||||
authMethods?: Array<{ id: string; name: string }>;
|
||||
}>>;
|
||||
probeAcpAdapter?(input: { id: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl"; path?: string }): Promise<{
|
||||
id: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
probeAcpAdapter?(input: { id: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl"; path?: string }): Promise<{
|
||||
id: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
label: string;
|
||||
state: "not_installed" | "needs_login" | "available" | "failed";
|
||||
detail?: string;
|
||||
@@ -120,15 +120,15 @@ interface EdgeEverDesktopBridge {
|
||||
promptCapabilities?: { image?: boolean; embeddedContext?: boolean };
|
||||
authMethods?: Array<{ id: string; name: string }>;
|
||||
} }>;
|
||||
authenticateAcpAdapter?(input: { id: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl"; path?: string; methodId: string }): Promise<{
|
||||
id: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
authenticateAcpAdapter?(input: { id: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl"; path?: string; methodId: string }): Promise<{
|
||||
id: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
label: string;
|
||||
state: "not_installed" | "needs_login" | "available" | "failed";
|
||||
detail?: string;
|
||||
authMethods?: Array<{ id: string; name: string }>;
|
||||
}>;
|
||||
promptAcp?(input: {
|
||||
adapterId: "codex" | "antigravity" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
adapterId: "codex" | "claudeCode" | "antigravity" | "openClaw" | "hermesAgent" | "grokBuild" | "deepseekHarness" | "piAgent" | "workbuddyCn" | "workbuddyIntl";
|
||||
path?: string;
|
||||
prompt: string;
|
||||
contextText?: string;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# Note access for local ACP agents
|
||||
|
||||
When a user sends a message to a local agent in the desktop app, EdgeEver automatically supplies MCP tools for the signed-in account. The user does not need to configure the EdgeEver instance in the agent or create an API token. The tools follow the existing server-side note permissions and can read, create, edit, and delete content in the current workspace. The agent's other local tool permissions remain subject to the agent and ACP client.
|
||||
When a user sends a message to a local agent that accepts session-scoped MCP servers, EdgeEver automatically supplies MCP tools for the signed-in account. The user does not need to configure the EdgeEver instance in that agent or create an API token. The tools follow the existing server-side note permissions and can read, create, edit, and delete content in the current workspace. The agent's other local tool permissions remain subject to the agent and ACP client.
|
||||
|
||||
The desktop main process retains the login credential and creates a temporary loopback bridge for each turn. The agent receives a temporary credential for that bridge. The bridge expires when the turn ends or is cancelled, or when the current instance or login session changes. A turn with note tools does not start if the current sign-in state cannot be verified.
|
||||
Claude Code uses the `claude-agent-acp` connector from the ACP project, and Hermes Agent uses `hermes acp`. Both accept session MCP servers. Install and authenticate the connector or agent separately before selecting it in EdgeEver. OpenClaw uses `openclaw acp`, which rejects session-scoped MCP servers. Its ACP conversation can run in EdgeEver, but automatic current-account note access is unavailable. To let OpenClaw access notes, configure EdgeEver MCP in its Gateway and verify the configured instance and account.
|
||||
|
||||
For agents that accept session MCP, the desktop main process retains the login credential and creates a temporary loopback bridge for each turn. The agent receives a temporary credential for that bridge. The bridge expires when the turn ends or is cancelled, or when the current instance or login session changes. A turn with note tools does not start if the current sign-in state cannot be verified.
|
||||
|
||||
The ACP session server is named `edgeever-current-workspace`. An agent that already has EdgeEver MCP configured may see two sets of tools. This causes no protocol conflict, but the configurations may target different instances or accounts and may lead to duplicate writes. EdgeEver instructs the agent to use the session server and warns the user to check existing configurations. ACP cannot guarantee that an agent's persistent MCP configuration is replaced or removed.
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# 本机 ACP Agent 的笔记库访问
|
||||
|
||||
桌面端在用户向本机 Agent 发送消息时,自动提供当前登录账号的 EdgeEver MCP 工具。用户无需在 Agent 中配置 EdgeEver 实例或创建 API Token。工具遵循现有服务端笔记权限,可读取、创建、修改和删除当前工作区中的内容。Agent 的其他本机工具权限仍由其自身和 ACP 客户端控制。
|
||||
桌面端在用户向支持会话级 MCP 服务的本机 Agent 发送消息时,自动提供当前登录账号的 EdgeEver MCP 工具。用户无需在该 Agent 中配置 EdgeEver 实例或创建 API Token。工具遵循现有服务端笔记权限,可读取、创建、修改和删除当前工作区中的内容。Agent 的其他本机工具权限仍由其自身和 ACP 客户端控制。
|
||||
|
||||
桌面主进程保留登录会话凭据,并为每次对话轮次建立仅监听本机的临时转发入口。Agent 获得的是该入口的临时凭据;轮次结束、取消或当前实例及登录会话改变时,入口失效。无法确认当前登录状态时,不启动带笔记工具的 Agent 轮次。
|
||||
Claude Code 使用 ACP 项目提供的 `claude-agent-acp` 连接组件,Hermes Agent 使用 `hermes acp`;两者均支持会话级 MCP 服务。请先分别安装连接组件或 Agent 并完成认证,再在 EdgeEver 中选择。OpenClaw 使用 `openclaw acp`,但它拒绝会话级 MCP 服务,因此可在 EdgeEver 中使用 ACP 对话,却无法自动访问当前账号的笔记。如需让 OpenClaw 访问笔记,需在其 Gateway 中配置 EdgeEver MCP,并核对目标实例和账号。
|
||||
|
||||
对于支持会话级 MCP 的 Agent,桌面主进程保留登录会话凭据,并为每次对话轮次建立仅监听本机的临时转发入口。Agent 获得的是该入口的临时凭据;轮次结束、取消或当前实例及登录会话改变时,入口失效。无法确认当前登录状态时,不启动带笔记工具的 Agent 轮次。
|
||||
|
||||
ACP 会话中的服务名为 `edgeever-current-workspace`。如果 Agent 自己已经配置了 EdgeEver MCP,它可能同时看到两套工具。协议层面不会冲突,但两套配置可能指向不同的实例或账号,也可能导致重复写入。EdgeEver 会在会话中指示 Agent 使用本次提供的服务,并在设置中提示用户核对既有配置;ACP 协议无法保证覆盖或移除 Agent 的持久 MCP 配置。
|
||||
|
||||
|
||||
@@ -1392,11 +1392,13 @@ export const enUS = {
|
||||
builtin: "Built-in Agent",
|
||||
builtinHint: "Uses the model services and tools configured below.",
|
||||
local: "Local Agent (ACP)",
|
||||
localHint: "Connects to a local Agent via ACP and automatically grants read and write access to notes in the current account.",
|
||||
localHint: "Connects to a local Agent via ACP. Agents that accept session MCP can access notes in the current account.",
|
||||
adapter: "Agent",
|
||||
codex: "Codex",
|
||||
antigravity: "Antigravity",
|
||||
claudeCode: "Claude Code",
|
||||
openClaw: "OpenClaw",
|
||||
hermesAgent: "Hermes Agent",
|
||||
workbuddy: "WorkBuddy",
|
||||
workbuddyCn: "WorkBuddy China",
|
||||
workbuddyIntl: "WorkBuddy International",
|
||||
@@ -1408,6 +1410,14 @@ export const enUS = {
|
||||
pathHint: "Enter the absolute path of an existing Antigravity ACP executable, or let EdgeEver install one on demand.",
|
||||
install: "Install connector",
|
||||
installHint: "When a local agent is detected, its connector downloads from the official source. This may exceed 100 MiB; updates are checked automatically.",
|
||||
claudeCodeNotFound: "Claude Code ACP connector not found",
|
||||
claudeCodeMissingHint: "Run npm install -g @agentclientprotocol/claude-agent-acp and make sure claude-agent-acp runs from your shell. This connector is maintained by the ACP project.",
|
||||
openClawNotFound: "OpenClaw CLI not found",
|
||||
openClawMissingHint: "Install the OpenClaw CLI and start its Gateway. EdgeEver connects using openclaw acp.",
|
||||
openClawNoteAccessHint: "OpenClaw ACP does not accept session MCP servers. To access EdgeEver notes, configure EdgeEver MCP in the OpenClaw Gateway and check the instance and account.",
|
||||
hermesAgentNotFound: "Hermes Agent CLI not found",
|
||||
hermesAgentMissingHint: "Install Hermes Agent with its ACP extra and make sure hermes acp --check succeeds.",
|
||||
hermesAgentSetupHint: "Configure a model provider and sign in through Hermes (for example, run hermes model), then check the connection again.",
|
||||
grokBuildMissingHint: "Grok Build includes ACP. Install the Grok CLI first; EdgeEver uses the local grok command without a separate connector download.",
|
||||
grokBuildNotFound: "Grok CLI not found",
|
||||
deepseekHarnessNotFound: "DeepSeek Harness CLI not found",
|
||||
|
||||
@@ -1392,11 +1392,13 @@ export const ja = {
|
||||
builtin: "内蔵 Agent",
|
||||
builtinHint: "下で設定したモデルサービスとツールを使用します。",
|
||||
local: "ローカル Agent (ACP)",
|
||||
localHint: "ACP 経由でローカル Agent に接続し、現在のアカウントのノートに対する読み書き権限を自動で付与します。",
|
||||
localHint: "ACP 経由でローカル Agent に接続します。セッション MCP に対応する Agent は現在のアカウントのノートを利用できます。",
|
||||
adapter: "エージェント",
|
||||
codex: "Codex",
|
||||
antigravity: "Antigravity",
|
||||
claudeCode: "Claude Code",
|
||||
openClaw: "OpenClaw",
|
||||
hermesAgent: "Hermes Agent",
|
||||
workbuddy: "WorkBuddy",
|
||||
workbuddyCn: "WorkBuddy 中国版",
|
||||
workbuddyIntl: "WorkBuddy 国際版",
|
||||
@@ -1408,6 +1410,14 @@ export const ja = {
|
||||
pathHint: "既存の Antigravity ACP 実行ファイルの絶対パスを入力するか、EdgeEver で必要時にインストールします。",
|
||||
install: "接続コンポーネントをインストール",
|
||||
installHint: "ローカルのエージェントを検出すると、公式配布元からダウンロードします。100 MiB を超える場合があり、インストール後は更新を自動確認します。",
|
||||
claudeCodeNotFound: "Claude Code ACP 接続コンポーネントが見つかりません",
|
||||
claudeCodeMissingHint: "npm install -g @agentclientprotocol/claude-agent-acp を実行し、claude-agent-acp をコマンドラインから実行できるようにしてください。この接続コンポーネントは ACP プロジェクトが提供します。",
|
||||
openClawNotFound: "OpenClaw CLI が見つかりません",
|
||||
openClawMissingHint: "OpenClaw CLI をインストールして Gateway を起動してください。EdgeEver は openclaw acp で接続します。",
|
||||
openClawNoteAccessHint: "OpenClaw ACP はセッション MCP サーバーを受け付けません。EdgeEver のノートにアクセスするには、OpenClaw Gateway で EdgeEver MCP を別途設定し、インスタンスとアカウントを確認してください。",
|
||||
hermesAgentNotFound: "Hermes Agent CLI が見つかりません",
|
||||
hermesAgentMissingHint: "Hermes Agent と ACP 拡張機能をインストールし、hermes acp --check が成功することを確認してください。",
|
||||
hermesAgentSetupHint: "Hermes でモデルサービスと認証情報を設定し(例: hermes model)、接続を再確認してください。",
|
||||
grokBuildMissingHint: "Grok Build には ACP が内蔵されています。先に Grok CLI をインストールしてください。EdgeEver はローカルの grok コマンドを使用し、別の接続コンポーネントはダウンロードしません。",
|
||||
grokBuildNotFound: "Grok CLI が見つかりません",
|
||||
deepseekHarnessNotFound: "DeepSeek Harness CLI が見つかりません",
|
||||
|
||||
@@ -1392,11 +1392,13 @@ export const zhCN = {
|
||||
builtin: "内置 Agent",
|
||||
builtinHint: "直接调用下方配置的模型服务与工具。",
|
||||
local: "本机 Agent (ACP)",
|
||||
localHint: "通过 ACP 连接本机 Agent,并自动授予当前账号笔记的读写权限。",
|
||||
localHint: "通过 ACP 连接本机 Agent。支持会话级 MCP 的 Agent 可使用当前账号的笔记。",
|
||||
adapter: "Agent",
|
||||
codex: "Codex",
|
||||
antigravity: "Antigravity",
|
||||
claudeCode: "Claude Code",
|
||||
openClaw: "OpenClaw",
|
||||
hermesAgent: "Hermes Agent",
|
||||
workbuddy: "WorkBuddy",
|
||||
workbuddyCn: "WorkBuddy 国内版",
|
||||
workbuddyIntl: "WorkBuddy 国际版",
|
||||
@@ -1408,6 +1410,14 @@ export const zhCN = {
|
||||
pathHint: "如需使用已有的 Antigravity ACP 程序,可填写其绝对路径;也可以让 EdgeEver 按需安装。",
|
||||
install: "安装连接组件",
|
||||
installHint: "检测到本机 Agent 后会从官方来源下载,可能超过 100 MiB;安装后会自动检查更新。",
|
||||
claudeCodeNotFound: "未找到 Claude Code ACP 连接组件",
|
||||
claudeCodeMissingHint: "请运行 npm install -g @agentclientprotocol/claude-agent-acp,并确保 claude-agent-acp 可从命令行运行。此连接组件由 ACP 项目提供。",
|
||||
openClawNotFound: "未找到 OpenClaw CLI",
|
||||
openClawMissingHint: "请安装 OpenClaw CLI 并启动 Gateway。EdgeEver 使用 openclaw acp 连接。",
|
||||
openClawNoteAccessHint: "OpenClaw ACP 不接受会话级 MCP 服务;如需访问 EdgeEver 笔记,请在 OpenClaw Gateway 中单独配置 EdgeEver MCP,并核对实例和账号。",
|
||||
hermesAgentNotFound: "未找到 Hermes Agent CLI",
|
||||
hermesAgentMissingHint: "请安装 Hermes Agent 及其 ACP 扩展,并确保 hermes acp --check 可运行。",
|
||||
hermesAgentSetupHint: "请先在 Hermes 中配置模型服务与登录信息(例如运行 hermes model),再检查连接。",
|
||||
grokBuildMissingHint: "Grok Build 已内置 ACP。请先安装 Grok CLI;EdgeEver 会使用本机的 grok 命令,无需下载单独适配器。",
|
||||
grokBuildNotFound: "未找到 Grok CLI",
|
||||
deepseekHarnessNotFound: "未找到 DeepSeek Harness CLI",
|
||||
|
||||
Reference in new issue
Block a user