fix(openclaw): make invite snippet/onboarding gateway-first
This commit is contained in:
@@ -37,17 +37,17 @@ describe("buildInviteOnboardingTextDocument", () => {
|
||||
allowedHostnames: [],
|
||||
});
|
||||
|
||||
expect(text).toContain("Paperclip OpenClaw Onboarding");
|
||||
expect(text).toContain("Paperclip OpenClaw Gateway Onboarding");
|
||||
expect(text).toContain("/api/invites/token-123/accept");
|
||||
expect(text).toContain("/api/join-requests/{requestId}/claim-api-key");
|
||||
expect(text).toContain("/api/invites/token-123/onboarding.txt");
|
||||
expect(text).toContain("/api/invites/token-123/test-resolution");
|
||||
expect(text).toContain("Suggested Paperclip base URLs to try");
|
||||
expect(text).toContain("http://localhost:3100");
|
||||
expect(text).toContain("host.docker.internal");
|
||||
expect(text).toContain("paperclipApiUrl");
|
||||
expect(text).toContain("You MUST include agentDefaultsPayload.headers.x-openclaw-auth");
|
||||
expect(text).toContain("will fail with 401 Unauthorized");
|
||||
expect(text).toContain("adapterType \"openclaw_gateway\"");
|
||||
expect(text).toContain("headers.x-openclaw-token");
|
||||
expect(text).toContain("Do NOT use /v1/responses or /hooks/*");
|
||||
expect(text).toContain("set the first reachable candidate as agentDefaultsPayload.paperclipApiUrl");
|
||||
expect(text).toContain("~/.openclaw/workspace/paperclip-claimed-api-key.json");
|
||||
expect(text).toContain("PAPERCLIP_API_KEY");
|
||||
|
||||
@@ -950,10 +950,6 @@ function buildInviteOnboardingManifest(
|
||||
const onboardingTextUrl = baseUrl
|
||||
? `${baseUrl}${onboardingTextPath}`
|
||||
: onboardingTextPath;
|
||||
const testResolutionPath = `/api/invites/${token}/test-resolution`;
|
||||
const testResolutionUrl = baseUrl
|
||||
? `${baseUrl}${testResolutionPath}`
|
||||
: testResolutionPath;
|
||||
const discoveryDiagnostics = buildOnboardingDiscoveryDiagnostics({
|
||||
apiBaseUrl: baseUrl,
|
||||
deploymentMode: opts.deploymentMode,
|
||||
@@ -971,16 +967,16 @@ function buildInviteOnboardingManifest(
|
||||
invite: toInviteSummaryResponse(req, token, invite),
|
||||
onboarding: {
|
||||
instructions:
|
||||
"Join as an OpenClaw agent, save your one-time claim secret, wait for board approval, then claim your API key. Save the claim response token to ~/.openclaw/workspace/paperclip-claimed-api-key.json and load PAPERCLIP_API_KEY from that file before starting heartbeat loops. You MUST include agentDefaultsPayload.headers.x-openclaw-auth in your join request so Paperclip can authenticate callback requests.",
|
||||
"Join as an OpenClaw Gateway agent, save your one-time claim secret, wait for board approval, then claim your API key. Save the claim response token to ~/.openclaw/workspace/paperclip-claimed-api-key.json and load PAPERCLIP_API_KEY from that file before starting heartbeat loops. You MUST submit adapterType='openclaw_gateway', set agentDefaultsPayload.url to your ws:// or wss:// OpenClaw gateway endpoint, and include agentDefaultsPayload.headers.x-openclaw-token (or legacy x-openclaw-auth).",
|
||||
inviteMessage: extractInviteMessage(invite),
|
||||
recommendedAdapterType: "openclaw",
|
||||
recommendedAdapterType: "openclaw_gateway",
|
||||
requiredFields: {
|
||||
requestType: "agent",
|
||||
agentName: "Display name for this agent",
|
||||
adapterType: "Use 'openclaw' for OpenClaw agents",
|
||||
adapterType: "Use 'openclaw_gateway' for OpenClaw Gateway agents",
|
||||
capabilities: "Optional capability summary",
|
||||
agentDefaultsPayload:
|
||||
"Adapter config for OpenClaw endpoint. MUST include headers.x-openclaw-auth; include streamTransport ('sse' or 'webhook') plus url/method/paperclipApiUrl (and optional webhookAuthHeader/timeoutSec/payloadTemplate)."
|
||||
"Adapter config for OpenClaw gateway. MUST include url (ws:// or wss://) and headers.x-openclaw-token (or legacy x-openclaw-auth). Optional fields: paperclipApiUrl, waitTimeoutMs, sessionKeyStrategy, sessionKey, role, scopes, disableDeviceAuth."
|
||||
},
|
||||
registrationEndpoint: {
|
||||
method: "POST",
|
||||
@@ -1001,21 +997,12 @@ function buildInviteOnboardingManifest(
|
||||
bindHost: opts.bindHost,
|
||||
allowedHostnames: opts.allowedHostnames,
|
||||
connectionCandidates,
|
||||
testResolutionEndpoint: {
|
||||
method: "GET",
|
||||
path: testResolutionPath,
|
||||
url: testResolutionUrl,
|
||||
query: {
|
||||
url: "https://your-openclaw-agent.example/v1/responses",
|
||||
timeoutMs: 5000
|
||||
}
|
||||
},
|
||||
diagnostics: discoveryDiagnostics,
|
||||
guidance:
|
||||
opts.deploymentMode === "authenticated" &&
|
||||
opts.deploymentExposure === "private"
|
||||
? "If OpenClaw runs on another machine, ensure the Paperclip hostname is reachable and allowed via `pnpm paperclipai allowed-hostname <host>`."
|
||||
: "Ensure OpenClaw can reach this Paperclip API base URL for callbacks and claims."
|
||||
: "Ensure OpenClaw can reach this Paperclip API base URL for invite, claim, and skill bootstrap calls."
|
||||
},
|
||||
textInstructions: {
|
||||
path: onboardingTextPath,
|
||||
@@ -1076,7 +1063,7 @@ export function buildInviteOnboardingTextDocument(
|
||||
};
|
||||
|
||||
appendBlock(`
|
||||
# Paperclip OpenClaw Onboarding
|
||||
# Paperclip OpenClaw Gateway Onboarding
|
||||
|
||||
This document is meant to be readable by both humans and agents.
|
||||
|
||||
@@ -1116,15 +1103,17 @@ export function buildInviteOnboardingTextDocument(
|
||||
const body = {
|
||||
requestType: "agent",
|
||||
agentName: "OpenClaw",
|
||||
adapterType: "openclaw",
|
||||
adapterType: "openclaw_gateway",
|
||||
capabilities: "OpenClaw agent adapter",
|
||||
agentDefaultsPayload: {
|
||||
url: "http://127.0.0.1:18789/v1/responses",
|
||||
url: "ws://127.0.0.1:18789",
|
||||
paperclipApiUrl: "http://host.docker.internal:3100",
|
||||
streamTransport: "sse",
|
||||
method: "POST",
|
||||
headers: { "x-openclaw-auth": token },
|
||||
timeoutSec: 0
|
||||
headers: { "x-openclaw-token": token },
|
||||
waitTimeoutMs: 120000,
|
||||
sessionKeyStrategy: "fixed",
|
||||
sessionKey: "paperclip",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin"]
|
||||
}
|
||||
};
|
||||
process.stdout.write(JSON.stringify(body));
|
||||
@@ -1135,23 +1124,26 @@ export function buildInviteOnboardingTextDocument(
|
||||
onboarding.registrationEndpoint.url
|
||||
}
|
||||
|
||||
IMPORTANT: You MUST include agentDefaultsPayload.headers.x-openclaw-auth with your gateway token.
|
||||
Without this token, Paperclip callback requests to your OpenClaw endpoint will fail with 401 Unauthorized.
|
||||
Set "streamTransport" to "sse" for streaming /v1/responses endpoints, or "webhook" for wake-style callbacks.
|
||||
IMPORTANT: You MUST include agentDefaultsPayload.headers.x-openclaw-token with your gateway token.
|
||||
Legacy x-openclaw-auth is also accepted, but x-openclaw-token is preferred.
|
||||
Use adapterType "openclaw_gateway" and a ws:// or wss:// gateway URL.
|
||||
Do NOT use /v1/responses or /hooks/* in this gateway join flow.
|
||||
|
||||
Body (JSON):
|
||||
{
|
||||
"requestType": "agent",
|
||||
"agentName": "My OpenClaw Agent",
|
||||
"adapterType": "openclaw",
|
||||
"adapterType": "openclaw_gateway",
|
||||
"capabilities": "Optional summary",
|
||||
"agentDefaultsPayload": {
|
||||
"url": "https://your-openclaw-agent.example/v1/responses",
|
||||
"url": "wss://your-openclaw-gateway.example",
|
||||
"paperclipApiUrl": "https://paperclip-hostname-your-agent-can-reach:3100",
|
||||
"streamTransport": "sse",
|
||||
"method": "POST",
|
||||
"headers": { "x-openclaw-auth": "replace-me" },
|
||||
"timeoutSec": 0
|
||||
"headers": { "x-openclaw-token": "replace-me" },
|
||||
"waitTimeoutMs": 120000,
|
||||
"sessionKeyStrategy": "fixed",
|
||||
"sessionKey": "paperclip",
|
||||
"role": "operator",
|
||||
"scopes": ["operator.admin"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1160,11 +1152,6 @@ export function buildInviteOnboardingTextDocument(
|
||||
- one-time claimSecret
|
||||
- claimApiKeyPath
|
||||
|
||||
Verify the response diagnostics include:
|
||||
'openclaw_auth_header_configured'
|
||||
and do not include:
|
||||
'openclaw_auth_header_missing'
|
||||
|
||||
## Step 2: Wait for board approval
|
||||
The board approves the join request in Paperclip before key claim is allowed.
|
||||
|
||||
@@ -1218,17 +1205,6 @@ export function buildInviteOnboardingTextDocument(
|
||||
}
|
||||
`);
|
||||
|
||||
if (onboarding.connectivity?.testResolutionEndpoint?.url) {
|
||||
appendBlock(`
|
||||
## Optional: test callback resolution from Paperclip
|
||||
${onboarding.connectivity.testResolutionEndpoint.method ?? "GET"} ${
|
||||
onboarding.connectivity.testResolutionEndpoint.url
|
||||
}?url=https%3A%2F%2Fyour-openclaw-agent.example%2Fv1%2Fresponses
|
||||
|
||||
This endpoint checks whether Paperclip can reach your OpenClaw endpoint and reports reachable, timeout, or unreachable.
|
||||
`);
|
||||
}
|
||||
|
||||
const connectionCandidates = Array.isArray(
|
||||
onboarding.connectivity?.connectionCandidates
|
||||
)
|
||||
@@ -1271,9 +1247,6 @@ export function buildInviteOnboardingTextDocument(
|
||||
${onboarding.skill.path}
|
||||
${manifest.invite.onboardingPath}
|
||||
`);
|
||||
if (onboarding.connectivity?.testResolutionEndpoint?.path) {
|
||||
lines.push(`${onboarding.connectivity.testResolutionEndpoint.path}`);
|
||||
}
|
||||
|
||||
return `${lines.join("\n")}\n`;
|
||||
}
|
||||
|
||||
@@ -461,7 +461,7 @@ Suggested command:
|
||||
Then verify with: curl -fsS <base-url>/api/health`;
|
||||
|
||||
const resolutionLine = resolutionTestUrl
|
||||
? `\nYou MUST test callback reachability, call: ${resolutionTestUrl}?url=<urlencoded-webhook-url> (well using the hostname that worked above). Do not assume your 172.x is necessarily reachable from Paperclip. Test it. `
|
||||
? `\nYou MUST test Paperclip-to-gateway reachability, call: ${resolutionTestUrl}?url=<urlencoded-gateway-url> (using the hostname that worked above). Do not assume your 172.x is necessarily reachable from Paperclip. Test it. `
|
||||
: "";
|
||||
|
||||
return `You're invited to join a Paperclip organization.
|
||||
@@ -476,13 +476,18 @@ Verify the hostname works from your runtime with: GET <base-url>/api/health
|
||||
${connectivityBlock}
|
||||
|
||||
For your "agentName", just use your own agent name (OpenClaw or whatever your name is) and send it directly.
|
||||
You also need to send a webhook URL that Paperclip can access. Check your config and include that URL.${resolutionLine}
|
||||
You also need to send a gateway URL that Paperclip can access. Check your config and include that URL.${resolutionLine}
|
||||
|
||||
---
|
||||
|
||||
In order for Paperclip to work smoothly, you need to enable \`gateway.http.endpoints.responses.enabled=true\` in your OpenClaw config.
|
||||
This onboarding flow is for OpenClaw Gateway.
|
||||
When you submit the join request, use:
|
||||
- \`adapterType: "openclaw_gateway"\`
|
||||
- \`agentDefaultsPayload.url\` as your \`ws://\` or \`wss://\` gateway URL
|
||||
- \`agentDefaultsPayload.headers["x-openclaw-token"]\` with your gateway token
|
||||
- (legacy accepted) \`agentDefaultsPayload.headers["x-openclaw-auth"]\`
|
||||
|
||||
Please enable that setting and notify your user that we did so.
|
||||
Do NOT use \`/v1/responses\` or \`/hooks/*\` in this join flow.
|
||||
|
||||
Before you do anything, please respond to your user that you understand the instructions and you're going to work on them. Then do the step above in another session called "paperclip-onboarding" and then tell your user when you're done. Update your user in intermediate steps along the way so they know what's going on.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user