mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
feat: add OpenClaw adapter type
Introduce openclaw adapter package with server execution, CLI stream formatting, and UI config fields. Register the adapter across CLI, server, and UI registries. Add adapter label in all relevant pages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
39d7f5d196
commit
b0f3f04ac6
26 changed files with 502 additions and 7 deletions
|
|
@ -16,6 +16,7 @@
|
|||
"@mdxeditor/editor": "^3.52.4",
|
||||
"@paperclip/adapter-claude-local": "workspace:*",
|
||||
"@paperclip/adapter-codex-local": "workspace:*",
|
||||
"@paperclip/adapter-openclaw": "workspace:*",
|
||||
"@paperclip/adapter-utils": "workspace:*",
|
||||
"@paperclip/shared": "workspace:*",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
|
|
|
|||
53
ui/src/adapters/openclaw/config-fields.tsx
Normal file
53
ui/src/adapters/openclaw/config-fields.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import type { AdapterConfigFieldsProps } from "../types";
|
||||
import {
|
||||
Field,
|
||||
DraftInput,
|
||||
help,
|
||||
} from "../../components/agent-config-primitives";
|
||||
|
||||
const inputClass =
|
||||
"w-full rounded-md border border-border px-2.5 py-1.5 bg-transparent outline-none text-sm font-mono placeholder:text-muted-foreground/40";
|
||||
|
||||
export function OpenClawConfigFields({
|
||||
isCreate,
|
||||
values,
|
||||
set,
|
||||
config,
|
||||
eff,
|
||||
mark,
|
||||
}: AdapterConfigFieldsProps) {
|
||||
return (
|
||||
<>
|
||||
<Field label="Webhook URL" hint={help.webhookUrl}>
|
||||
<DraftInput
|
||||
value={
|
||||
isCreate
|
||||
? values!.url
|
||||
: eff("adapterConfig", "url", String(config.url ?? ""))
|
||||
}
|
||||
onCommit={(v) =>
|
||||
isCreate
|
||||
? set!({ url: v })
|
||||
: mark("adapterConfig", "url", v || undefined)
|
||||
}
|
||||
immediate
|
||||
className={inputClass}
|
||||
placeholder="https://..."
|
||||
/>
|
||||
</Field>
|
||||
{!isCreate && (
|
||||
<Field label="Webhook auth header (optional)">
|
||||
<DraftInput
|
||||
value={
|
||||
eff("adapterConfig", "webhookAuthHeader", String(config.webhookAuthHeader ?? ""))
|
||||
}
|
||||
onCommit={(v) => mark("adapterConfig", "webhookAuthHeader", v || undefined)}
|
||||
immediate
|
||||
className={inputClass}
|
||||
placeholder="Bearer <token>"
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
12
ui/src/adapters/openclaw/index.ts
Normal file
12
ui/src/adapters/openclaw/index.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import type { UIAdapterModule } from "../types";
|
||||
import { parseOpenClawStdoutLine } from "@paperclip/adapter-openclaw/ui";
|
||||
import { buildOpenClawConfig } from "@paperclip/adapter-openclaw/ui";
|
||||
import { OpenClawConfigFields } from "./config-fields";
|
||||
|
||||
export const openClawUIAdapter: UIAdapterModule = {
|
||||
type: "openclaw",
|
||||
label: "OpenClaw",
|
||||
parseStdoutLine: parseOpenClawStdoutLine,
|
||||
ConfigFields: OpenClawConfigFields,
|
||||
buildAdapterConfig: buildOpenClawConfig,
|
||||
};
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
import type { UIAdapterModule } from "./types";
|
||||
import { claudeLocalUIAdapter } from "./claude-local";
|
||||
import { codexLocalUIAdapter } from "./codex-local";
|
||||
import { openClawUIAdapter } from "./openclaw";
|
||||
import { processUIAdapter } from "./process";
|
||||
import { httpUIAdapter } from "./http";
|
||||
|
||||
const adaptersByType = new Map<string, UIAdapterModule>(
|
||||
[claudeLocalUIAdapter, codexLocalUIAdapter, processUIAdapter, httpUIAdapter].map((a) => [a.type, a]),
|
||||
[claudeLocalUIAdapter, codexLocalUIAdapter, openClawUIAdapter, processUIAdapter, httpUIAdapter].map((a) => [a.type, a]),
|
||||
);
|
||||
|
||||
export function getUIAdapter(type: string): UIAdapterModule {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ interface AgentPropertiesProps {
|
|||
const adapterLabels: Record<string, string> = {
|
||||
claude_local: "Claude (local)",
|
||||
codex_local: "Codex (local)",
|
||||
openclaw: "OpenClaw",
|
||||
process: "Process",
|
||||
http: "HTTP",
|
||||
};
|
||||
|
|
@ -72,7 +73,7 @@ export function AgentProperties({ agent, runtimeState }: AgentPropertiesProps) {
|
|||
)}
|
||||
{runtimeState?.lastError && (
|
||||
<PropertyRow label="Last error">
|
||||
<span className="text-xs text-red-400 truncate max-w-[160px]">{runtimeState.lastError}</span>
|
||||
<span className="text-xs text-red-600 dark:text-red-400 truncate max-w-[160px]">{runtimeState.lastError}</span>
|
||||
</PropertyRow>
|
||||
)}
|
||||
{agent.lastHeartbeatAt && (
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ export const help: Record<string, string> = {
|
|||
role: "Organizational role. Determines position and capabilities.",
|
||||
reportsTo: "The agent this one reports to in the org hierarchy.",
|
||||
capabilities: "Describes what this agent can do. Shown in the org chart and used for task routing.",
|
||||
adapterType: "How this agent runs: local CLI (Claude/Codex), spawned process, or HTTP webhook.",
|
||||
adapterType: "How this agent runs: local CLI (Claude/Codex), OpenClaw webhook, spawned process, or generic HTTP webhook.",
|
||||
cwd: "Default working directory fallback for local adapters. Use an absolute path on the machine running Paperclip.",
|
||||
promptTemplate: "The prompt sent to the agent on each heartbeat. Supports {{ agent.id }}, {{ agent.name }}, {{ agent.role }} variables.",
|
||||
model: "Override the default model used by the adapter.",
|
||||
thinkingEffort: "Control model reasoning depth. Supported values vary by adapter/model.",
|
||||
chrome: "Enable Claude's Chrome integration by passing --chrome.",
|
||||
dangerouslySkipPermissions: "Run Claude without permission prompts. Required for unattended operation.",
|
||||
dangerouslyBypassSandbox: "Run Codex without sandbox restrictions. Required for filesystem/network access.",
|
||||
search: "Enable Codex web search capability during runs.",
|
||||
|
|
@ -43,6 +44,7 @@ export const help: Record<string, string> = {
|
|||
export const adapterLabels: Record<string, string> = {
|
||||
claude_local: "Claude (local)",
|
||||
codex_local: "Codex (local)",
|
||||
openclaw: "OpenClaw",
|
||||
process: "Process",
|
||||
http: "HTTP",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import type { Agent } from "@paperclip/shared";
|
|||
const adapterLabels: Record<string, string> = {
|
||||
claude_local: "Claude",
|
||||
codex_local: "Codex",
|
||||
openclaw: "OpenClaw",
|
||||
process: "Process",
|
||||
http: "HTTP",
|
||||
};
|
||||
|
|
@ -398,7 +399,7 @@ function LiveRunIndicator({
|
|||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
|
||||
</span>
|
||||
<span className="text-[11px] font-medium text-blue-400">
|
||||
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">
|
||||
Live{liveCount > 1 ? ` (${liveCount})` : ""}
|
||||
</span>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ function collectEdges(nodes: LayoutNode[]): Array<{ parent: LayoutNode; child: L
|
|||
const adapterLabels: Record<string, string> = {
|
||||
claude_local: "Claude",
|
||||
codex_local: "Codex",
|
||||
openclaw: "OpenClaw",
|
||||
process: "Process",
|
||||
http: "HTTP",
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue