openclaw-rumi 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Rumi — OpenClaw Plugin
2
2
 
3
- Find real people to chat with based on shared interests. When you want human connection, Rumi matches you with compatible people.
3
+ **Talk to real people, not just AI.** Rumi matches you with humans who share your interests by what you want to talk about, not by photos.
4
+
5
+ Your OpenClaw agent finds the right person in the background and connects you when a match is found. Chat right inside OpenClaw or on the Rumi website.
4
6
 
5
7
  ## Quick Start
6
8
 
@@ -48,20 +50,25 @@ If you prefer to set up manually:
48
50
 
49
51
  | Tool | Description |
50
52
  |------|-------------|
53
+ | `rumi_health_check` | Verify your token, check quota, and see active sessions |
51
54
  | `rumi_find_partner` | Find someone to chat with based on your interests |
52
55
  | `rumi_check_status` | Check if a pending match has been found |
53
56
  | `rumi_send_message` | Send a message to your matched partner |
54
57
  | `rumi_get_messages` | Get recent messages from a conversation |
55
58
 
56
- ## Usage
59
+ ## Usage Examples
57
60
 
58
61
  Just tell your OpenClaw agent:
59
62
 
60
63
  > "I want to find someone to talk about hiking with"
61
64
 
65
+ > "Find me someone who's into TypeScript and has done large-scale migrations"
66
+
67
+ > "I'm bored, connect me with someone interesting"
68
+
62
69
  The agent will use Rumi to find a compatible person. When matched, you can chat directly through OpenClaw or visit the Rumi website.
63
70
 
64
- The agent can also **proactively** find matches when it detects you might enjoy talking to a real person — you'll only be notified when someone is found.
71
+ The agent can also **proactively** find matches when it detects you might enjoy talking to a real person — like when you're deep into a hobby topic, working solo late at night, or hitting the limits of what AI can offer. You'll only be notified when someone is found.
65
72
 
66
73
  ## Development
67
74
 
package/dist/index.d.ts CHANGED
@@ -125,6 +125,39 @@ declare const _default: {
125
125
  messageCount?: undefined;
126
126
  messages?: undefined;
127
127
  }>;
128
+ } | {
129
+ name: string;
130
+ description: string;
131
+ parameters: {};
132
+ execute: () => Promise<{
133
+ status: string;
134
+ weeklyUsage: {
135
+ used: number;
136
+ limit: number;
137
+ remaining: number;
138
+ };
139
+ activeSession: {
140
+ sessionId: string;
141
+ status: string;
142
+ } | null;
143
+ tokenExpiresAt: string | null;
144
+ message: string;
145
+ setupUrl?: undefined;
146
+ } | {
147
+ status: string;
148
+ setupUrl: string;
149
+ message: string;
150
+ weeklyUsage?: undefined;
151
+ activeSession?: undefined;
152
+ tokenExpiresAt?: undefined;
153
+ } | {
154
+ status: string;
155
+ message: string;
156
+ weeklyUsage?: undefined;
157
+ activeSession?: undefined;
158
+ tokenExpiresAt?: undefined;
159
+ setupUrl?: undefined;
160
+ }>;
128
161
  })[];
129
162
  }>;
130
163
  };
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { createFindPartnerTool } from "./src/tools/find-partner";
4
4
  import { createCheckStatusTool } from "./src/tools/check-status";
5
5
  import { createSendMessageTool } from "./src/tools/send-message";
6
6
  import { createGetMessagesTool } from "./src/tools/get-messages";
7
+ import { createHealthCheckTool } from "./src/tools/health-check";
7
8
  export default {
8
9
  id: "openclaw-rumi",
9
10
  slot: "tool",
@@ -16,6 +17,7 @@ export default {
16
17
  const client = new RumiClient(config);
17
18
  return {
18
19
  tools: [
20
+ createHealthCheckTool(client),
19
21
  createFindPartnerTool(client),
20
22
  createCheckStatusTool(client),
21
23
  createSendMessageTool(client),
@@ -1,4 +1,4 @@
1
- import type { RumiConfig, FindMatchResponse, SessionStatusResponse, MessagesResponse, SendMessageResponse } from "./types";
1
+ import type { RumiConfig, FindMatchResponse, SessionStatusResponse, MessagesResponse, SendMessageResponse, HealthResponse } from "./types";
2
2
  /**
3
3
  * HTTP client for Rumi Partner API
4
4
  */
@@ -11,5 +11,6 @@ export declare class RumiClient {
11
11
  getSessionStatus(sessionId: string): Promise<SessionStatusResponse>;
12
12
  getMessages(conversationId: string, after?: string, limit?: number): Promise<MessagesResponse>;
13
13
  getConnectUrl(): string;
14
+ healthCheck(): Promise<HealthResponse>;
14
15
  sendMessage(conversationId: string, content: string): Promise<SendMessageResponse>;
15
16
  }
@@ -54,6 +54,9 @@ export class RumiClient {
54
54
  getConnectUrl() {
55
55
  return `${this.baseUrl}/connect?partner=openclaw`;
56
56
  }
57
+ async healthCheck() {
58
+ return this.request("/api/partner/health");
59
+ }
57
60
  async sendMessage(conversationId, content) {
58
61
  return this.request(`/api/conversations/${encodeURIComponent(conversationId)}/messages`, {
59
62
  method: "POST",
@@ -0,0 +1,35 @@
1
+ import type { RumiClient } from "../client";
2
+ export declare function createHealthCheckTool(client: RumiClient): {
3
+ name: string;
4
+ description: string;
5
+ parameters: {};
6
+ execute: () => Promise<{
7
+ status: string;
8
+ weeklyUsage: {
9
+ used: number;
10
+ limit: number;
11
+ remaining: number;
12
+ };
13
+ activeSession: {
14
+ sessionId: string;
15
+ status: string;
16
+ } | null;
17
+ tokenExpiresAt: string | null;
18
+ message: string;
19
+ setupUrl?: undefined;
20
+ } | {
21
+ status: string;
22
+ setupUrl: string;
23
+ message: string;
24
+ weeklyUsage?: undefined;
25
+ activeSession?: undefined;
26
+ tokenExpiresAt?: undefined;
27
+ } | {
28
+ status: string;
29
+ message: string;
30
+ weeklyUsage?: undefined;
31
+ activeSession?: undefined;
32
+ tokenExpiresAt?: undefined;
33
+ setupUrl?: undefined;
34
+ }>;
35
+ };
@@ -0,0 +1,46 @@
1
+ export function createHealthCheckTool(client) {
2
+ return {
3
+ name: "rumi_health_check",
4
+ description: "Check if Rumi is properly configured: token validity, weekly usage quota, and any active matching sessions. Use this before rumi_find_partner to verify the setup is working.",
5
+ parameters: {},
6
+ execute: async () => {
7
+ try {
8
+ const result = await client.healthCheck();
9
+ const parts = [
10
+ `Status: ${result.status}`,
11
+ `Weekly usage: ${result.weeklyUsage.used}/${result.weeklyUsage.limit} (${result.weeklyUsage.remaining} remaining)`,
12
+ ];
13
+ if (result.tokenExpiresAt) {
14
+ const expires = new Date(result.tokenExpiresAt);
15
+ const daysLeft = Math.ceil((expires.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
16
+ parts.push(`Token expires in ${daysLeft} days`);
17
+ }
18
+ if (result.activeSession) {
19
+ parts.push(`Active session: ${result.activeSession.sessionId} (${result.activeSession.status})`);
20
+ }
21
+ return {
22
+ status: result.status,
23
+ weeklyUsage: result.weeklyUsage,
24
+ activeSession: result.activeSession,
25
+ tokenExpiresAt: result.tokenExpiresAt,
26
+ message: parts.join("\n"),
27
+ };
28
+ }
29
+ catch (error) {
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ if (message.includes("401") || message.includes("UNAUTHORIZED")) {
32
+ return {
33
+ status: "setup_required",
34
+ setupUrl: client.getConnectUrl(),
35
+ message: "Rumi is not set up or the token has expired. Open this URL to set up: " +
36
+ client.getConnectUrl(),
37
+ };
38
+ }
39
+ return {
40
+ status: "error",
41
+ message: `Health check failed: ${message}`,
42
+ };
43
+ }
44
+ },
45
+ };
46
+ }
@@ -38,6 +38,20 @@ export interface SendMessageResponse {
38
38
  id: string;
39
39
  created_at: string;
40
40
  }
41
+ export interface HealthResponse {
42
+ status: string;
43
+ userId: string;
44
+ tokenExpiresAt: string | null;
45
+ weeklyUsage: {
46
+ used: number;
47
+ limit: number;
48
+ remaining: number;
49
+ };
50
+ activeSession: {
51
+ sessionId: string;
52
+ status: string;
53
+ } | null;
54
+ }
41
55
  export declare const FindPartnerInput: import("@sinclair/typebox").TObject<{
42
56
  description: import("@sinclair/typebox").TString;
43
57
  locale: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"zh-TW">, import("@sinclair/typebox").TLiteral<"en">, import("@sinclair/typebox").TLiteral<"ja">, import("@sinclair/typebox").TLiteral<"ko">]>>;
package/index.ts CHANGED
@@ -4,6 +4,7 @@ import { createFindPartnerTool } from "./src/tools/find-partner";
4
4
  import { createCheckStatusTool } from "./src/tools/check-status";
5
5
  import { createSendMessageTool } from "./src/tools/send-message";
6
6
  import { createGetMessagesTool } from "./src/tools/get-messages";
7
+ import { createHealthCheckTool } from "./src/tools/health-check";
7
8
 
8
9
  export default {
9
10
  id: "openclaw-rumi",
@@ -19,6 +20,7 @@ export default {
19
20
 
20
21
  return {
21
22
  tools: [
23
+ createHealthCheckTool(client),
22
24
  createFindPartnerTool(client),
23
25
  createCheckStatusTool(client),
24
26
  createSendMessageTool(client),
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "openclaw-rumi",
3
- "version": "0.1.1",
4
- "description": "Rumi integration for OpenClaw — find real people to chat with based on shared interests",
3
+ "version": "0.1.2",
4
+ "description": "OpenClaw plugin to find real people to chat with AI-powered interest matching connects you with compatible humans for genuine conversations",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "homepage": "https://rumi.app",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/maggiehu/Rumi",
11
+ "directory": "openclaw-plugin"
12
+ },
7
13
  "scripts": {
8
14
  "build": "tsc",
9
15
  "dev": "tsc --watch"
@@ -11,7 +17,22 @@
11
17
  "openclaw": {
12
18
  "extensions": "./dist/index.js"
13
19
  },
14
- "keywords": ["openclaw", "rumi", "social", "matching", "chat"],
20
+ "keywords": [
21
+ "openclaw",
22
+ "openclaw-plugin",
23
+ "rumi",
24
+ "social",
25
+ "matching",
26
+ "chat",
27
+ "human-connection",
28
+ "interest-matching",
29
+ "conversation",
30
+ "ai-agent",
31
+ "find-people",
32
+ "real-people",
33
+ "networking",
34
+ "penpal"
35
+ ],
15
36
  "license": "MIT",
16
37
  "dependencies": {
17
38
  "@sinclair/typebox": "^0.32.0"
package/skills/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rumi
3
- description: Find real people to chat with based on shared interests
3
+ description: Match with real humans who share your interests — topic-driven matching, not photo swiping. Chat through OpenClaw or on the web.
4
4
  user-invocable: true
5
5
  metadata: {"openclaw":{"emoji":"🤝"}}
6
6
  ---
@@ -66,10 +66,11 @@ You can and SHOULD proactively search for a match when you detect these patterns
66
66
 
67
67
  ### If set up (apiToken configured):
68
68
 
69
- 1. Gather context about what the user wants to talk about (or infer from conversation)
70
- 2. Call `rumi_find_partner` with a rich description include interests, mood, what kind of person they want
71
- 3. If status is `searching` — check back with `rumi_check_status` every few minutes
72
- 4. When matched notify the user naturally: "Hey, I found someone who shares your interest in X!"
69
+ 1. Call `rumi_health_check` first to verify token and check quota
70
+ 2. Gather context about what the user wants to talk about (or infer from conversation)
71
+ 3. Call `rumi_find_partner` with a rich description include interests, mood, what kind of person they want
72
+ 4. If status is `searching` check back with `rumi_check_status` every few minutes
73
+ 5. When matched — notify the user naturally: "Hey, I found someone who shares your interest in X!"
73
74
 
74
75
  ## Handling Results
75
76
 
package/src/client.ts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  SessionStatusResponse,
5
5
  MessagesResponse,
6
6
  SendMessageResponse,
7
+ HealthResponse,
7
8
  } from "./types";
8
9
 
9
10
  const REQUEST_TIMEOUT_MS = 60000;
@@ -86,6 +87,10 @@ export class RumiClient {
86
87
  return `${this.baseUrl}/connect?partner=openclaw`;
87
88
  }
88
89
 
90
+ async healthCheck(): Promise<HealthResponse> {
91
+ return this.request<HealthResponse>("/api/partner/health");
92
+ }
93
+
89
94
  async sendMessage(
90
95
  conversationId: string,
91
96
  content: string
@@ -0,0 +1,60 @@
1
+ import type { RumiClient } from "../client";
2
+
3
+ export function createHealthCheckTool(client: RumiClient) {
4
+ return {
5
+ name: "rumi_health_check",
6
+ description:
7
+ "Check if Rumi is properly configured: token validity, weekly usage quota, and any active matching sessions. Use this before rumi_find_partner to verify the setup is working.",
8
+ parameters: {},
9
+ execute: async () => {
10
+ try {
11
+ const result = await client.healthCheck();
12
+
13
+ const parts = [
14
+ `Status: ${result.status}`,
15
+ `Weekly usage: ${result.weeklyUsage.used}/${result.weeklyUsage.limit} (${result.weeklyUsage.remaining} remaining)`,
16
+ ];
17
+
18
+ if (result.tokenExpiresAt) {
19
+ const expires = new Date(result.tokenExpiresAt);
20
+ const daysLeft = Math.ceil(
21
+ (expires.getTime() - Date.now()) / (1000 * 60 * 60 * 24)
22
+ );
23
+ parts.push(`Token expires in ${daysLeft} days`);
24
+ }
25
+
26
+ if (result.activeSession) {
27
+ parts.push(
28
+ `Active session: ${result.activeSession.sessionId} (${result.activeSession.status})`
29
+ );
30
+ }
31
+
32
+ return {
33
+ status: result.status,
34
+ weeklyUsage: result.weeklyUsage,
35
+ activeSession: result.activeSession,
36
+ tokenExpiresAt: result.tokenExpiresAt,
37
+ message: parts.join("\n"),
38
+ };
39
+ } catch (error) {
40
+ const message =
41
+ error instanceof Error ? error.message : String(error);
42
+
43
+ if (message.includes("401") || message.includes("UNAUTHORIZED")) {
44
+ return {
45
+ status: "setup_required",
46
+ setupUrl: client.getConnectUrl(),
47
+ message:
48
+ "Rumi is not set up or the token has expired. Open this URL to set up: " +
49
+ client.getConnectUrl(),
50
+ };
51
+ }
52
+
53
+ return {
54
+ status: "error",
55
+ message: `Health check failed: ${message}`,
56
+ };
57
+ }
58
+ },
59
+ };
60
+ }
package/src/types.ts CHANGED
@@ -55,6 +55,21 @@ export interface SendMessageResponse {
55
55
  created_at: string;
56
56
  }
57
57
 
58
+ export interface HealthResponse {
59
+ status: string;
60
+ userId: string;
61
+ tokenExpiresAt: string | null;
62
+ weeklyUsage: {
63
+ used: number;
64
+ limit: number;
65
+ remaining: number;
66
+ };
67
+ activeSession: {
68
+ sessionId: string;
69
+ status: string;
70
+ } | null;
71
+ }
72
+
58
73
  // Tool input schemas
59
74
  export const FindPartnerInput = Type.Object({
60
75
  description: Type.String({