openclaw-app 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.ts CHANGED
@@ -881,9 +881,66 @@ async function handleRelayMessage(ctx: any, accountId: string, state: RelayState
881
881
  await handleInbound(ctx, accountId, msg);
882
882
  }
883
883
 
884
+ async function handleRpc(ctx: any, accountId: string, msg: any): Promise<boolean> {
885
+ if (msg.type !== "rpc") return false;
886
+ const reqId = msg.id as string | undefined;
887
+ const method = msg.method as string | undefined;
888
+ const params = msg.params ?? {};
889
+ const replySessionKey = msg.sessionKey as string | undefined;
890
+
891
+ ctx.log?.info?.(`[${CHANNEL_ID}] [${accountId}] handleRpc: method=${method} id=${reqId}`);
892
+
893
+ const runtime = pluginRuntime;
894
+ if (!runtime) {
895
+ ctx.log?.error?.(`[${CHANNEL_ID}] [${accountId}] RPC: no runtime`);
896
+ return true;
897
+ }
898
+
899
+ const relayState = getRelayState(accountId);
900
+
901
+ const sendRpcReply = async (data: unknown, error?: string) => {
902
+ if (!relayState.ws || relayState.ws.readyState !== WebSocket.OPEN) return;
903
+ if (!replySessionKey) return;
904
+ const sessionE2E = relayState.e2eSessions.get(replySessionKey);
905
+ if (!sessionE2E?.ready) return;
906
+ const inner = JSON.stringify({ type: "rpc-response", id: reqId, data, error: error ?? null, sessionKey: replySessionKey });
907
+ const encrypted = JSON.parse(await e2eEncrypt(sessionE2E, inner));
908
+ encrypted.sessionKey = replySessionKey;
909
+ relayState.ws.send(JSON.stringify(encrypted));
910
+ };
911
+
912
+ try {
913
+ if (method === "agents.list") {
914
+ const agents = runtime.agents?.list?.() ?? runtime.config?.loadConfig()?.agents?.agents ?? [];
915
+ // Normalize to [{id, name, emoji, workspace, createdAt}]
916
+ const list = Array.isArray(agents) ? agents.map((a: any) => ({
917
+ id: a.id ?? a.agentId ?? '',
918
+ name: a.name ?? a.id ?? '',
919
+ emoji: a.emoji ?? null,
920
+ workspace: a.workspace ?? null,
921
+ createdAt: a.createdAt ?? null,
922
+ })).filter((a: any) => a.id) : [];
923
+ await sendRpcReply({ agents: list });
924
+ } else if (method === "sessions.list") {
925
+ const cfg = runtime.config.loadConfig();
926
+ const sessions = runtime.session?.listSessions?.({ cfg, accountId }) ?? [];
927
+ await sendRpcReply({ sessions });
928
+ } else {
929
+ await sendRpcReply(null, `Unknown RPC method: ${method}`);
930
+ }
931
+ } catch (e: any) {
932
+ ctx.log?.error?.(`[${CHANNEL_ID}] [${accountId}] RPC error: ${e}`);
933
+ await sendRpcReply(null, String(e));
934
+ }
935
+ return true;
936
+ }
937
+
884
938
  async function handleInbound(ctx: any, accountId: string, msg: any) {
885
939
  ctx.log?.info?.(`[${CHANNEL_ID}] [${accountId}] handleInbound: type=${msg.type} content=${String(msg.content ?? "").slice(0, 100)}`);
886
940
 
941
+ // Handle RPC requests (agents.list, sessions.list, etc.) without AI involvement
942
+ if (await handleRpc(ctx, accountId, msg)) return;
943
+
887
944
  if (msg.type !== "message" || !msg.content) {
888
945
  ctx.log?.warn?.(`[${CHANNEL_ID}] [${accountId}] Skipping non-message: type=${msg.type}`);
889
946
  return;
@@ -913,18 +970,16 @@ async function handleInbound(ctx: any, accountId: string, msg: any) {
913
970
  peer: { kind: "direct", id: senderId },
914
971
  });
915
972
 
916
- // If the app specified a sessionKey (UUID-based), derive an isolated
917
- // Gateway session so each mobile conversation has its own context.
918
- // Format: "agent:main:mobile-<uuid>"
919
- // No appSessionKey use the route's mainSessionKey (default conversation).
973
+ // Derive an isolated Gateway session for each mobile conversation.
974
+ // If the app provides an agentId, route to that agent's session:
975
+ // agent:<agentId>:mobile-<appSessionKey>
976
+ // Otherwise fall back to the default main agent route.
920
977
  let sessionKey: string;
921
978
  const appSessionKey = msg.sessionKey ? String(msg.sessionKey) : null;
979
+ const msgAgentId = msg.agentId ? String(msg.agentId) : null;
922
980
  if (appSessionKey) {
923
- // Extract agent prefix from mainSessionKey e.g. "agent:main:" from "agent:main:main"
924
- const mainKey = route.mainSessionKey as string;
925
- const colonIdx = mainKey.lastIndexOf(':');
926
- const agentPrefix = colonIdx > 0 ? mainKey.substring(0, colonIdx + 1) : '';
927
- sessionKey = `${agentPrefix}mobile-${appSessionKey}`;
981
+ const agentId = msgAgentId || 'main';
982
+ sessionKey = `agent:${agentId}:mobile-${appSessionKey}`;
928
983
  } else {
929
984
  sessionKey = route.mainSessionKey;
930
985
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-app",
3
3
  "name": "OpenClaw App",
4
- "version": "1.1.1",
4
+ "version": "1.1.3",
5
5
  "description": "Mobile app channel for OpenClaw — chat via the OpenClaw App app through a Cloudflare Worker relay.",
6
6
  "channels": [
7
7
  "openclaw-app"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-app",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "OpenClaw App channel plugin — relay bridge for the OpenClaw App app",
5
5
  "main": "index.ts",
6
6
  "type": "module",