@ravi-hq/ravi 0.5.2 → 0.5.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/dist/channels/email-trusted.d.ts +129 -0
- package/dist/channels/email-trusted.d.ts.map +1 -0
- package/dist/channels/email-trusted.js +275 -0
- package/dist/channels/email-trusted.js.map +1 -0
- package/dist/channels/email-untrusted.d.ts +133 -0
- package/dist/channels/email-untrusted.d.ts.map +1 -0
- package/dist/channels/email-untrusted.js +285 -0
- package/dist/channels/email-untrusted.js.map +1 -0
- package/dist/channels/email.d.ts +8 -12
- package/dist/channels/email.d.ts.map +1 -1
- package/dist/channels/email.js +12 -25
- package/dist/channels/email.js.map +1 -1
- package/dist/channels/sms-trusted.d.ts +161 -0
- package/dist/channels/sms-trusted.d.ts.map +1 -0
- package/dist/channels/sms-trusted.js +306 -0
- package/dist/channels/sms-trusted.js.map +1 -0
- package/dist/channels/sms-untrusted.d.ts +124 -0
- package/dist/channels/sms-untrusted.d.ts.map +1 -0
- package/dist/channels/sms-untrusted.js +269 -0
- package/dist/channels/sms-untrusted.js.map +1 -0
- package/dist/channels/sms.d.ts +8 -12
- package/dist/channels/sms.d.ts.map +1 -1
- package/dist/channels/sms.js +12 -25
- package/dist/channels/sms.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/service.d.ts +3 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +76 -6
- package/dist/service.js.map +1 -1
- package/dist/sse-pool.d.ts +15 -0
- package/dist/sse-pool.d.ts.map +1 -0
- package/dist/sse-pool.js +41 -0
- package/dist/sse-pool.js.map +1 -0
- package/dist/sse.d.ts +23 -18
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +40 -23
- package/dist/sse.js.map +1 -1
- package/dist/types.d.ts +2 -4
- package/dist/types.d.ts.map +1 -1
- package/openclaw.plugin.json +6 -1
- package/package.json +1 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { RaviClient } from "../client.js";
|
|
2
|
+
import type { SmsEvent, BaseGatewayContext } from "../types.js";
|
|
3
|
+
/** Configuration for a single SMS account within the ravi-sms-trusted channel. */
|
|
4
|
+
export interface SmsTrustedAccountConfig {
|
|
5
|
+
/** The identity UUID this account is bound to. */
|
|
6
|
+
identityUuid: string;
|
|
7
|
+
/** Human-readable identity name for display purposes. */
|
|
8
|
+
identityName: string;
|
|
9
|
+
/** The phone number provisioned for this identity (E.164 format). */
|
|
10
|
+
phone: string;
|
|
11
|
+
}
|
|
12
|
+
/** Normalized inbound message envelope produced by {@link normalizeInbound}. */
|
|
13
|
+
export interface SmsTrustedInboundEnvelope {
|
|
14
|
+
/** Sender's phone number (used as the sender ID). */
|
|
15
|
+
senderId: string;
|
|
16
|
+
/** Plain-text body of the SMS message. */
|
|
17
|
+
text: string;
|
|
18
|
+
/** Phone number that maps to the OpenClaw session key. */
|
|
19
|
+
threadId: string;
|
|
20
|
+
/** Additional SMS metadata passed through to the agent. */
|
|
21
|
+
metadata: {
|
|
22
|
+
conversationId: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Context passed by the ChannelManager to `gateway.startAccount()`. */
|
|
26
|
+
export type SmsTrustedGatewayContext = BaseGatewayContext<SmsTrustedAccountConfig>;
|
|
27
|
+
/**
|
|
28
|
+
* Creates the ravi-sms-trusted channel definition for OpenClaw.
|
|
29
|
+
*
|
|
30
|
+
* Notification-only channel for SMS from trusted senders (the identity owner's
|
|
31
|
+
* other phone numbers or known contacts). The agent processes the message as an
|
|
32
|
+
* instruction. Delivery calls sendSms — the agent can reply directly.
|
|
33
|
+
*
|
|
34
|
+
* @returns The ravi-sms-trusted channel definition object.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createSmsTrustedChannel(): {
|
|
37
|
+
id: "ravi-sms-trusted";
|
|
38
|
+
meta: {
|
|
39
|
+
id: string;
|
|
40
|
+
label: string;
|
|
41
|
+
selectionLabel: string;
|
|
42
|
+
blurb: string;
|
|
43
|
+
aliases: string[];
|
|
44
|
+
};
|
|
45
|
+
capabilities: {
|
|
46
|
+
chatTypes: readonly ["direct"];
|
|
47
|
+
};
|
|
48
|
+
config: {
|
|
49
|
+
/**
|
|
50
|
+
* List all configured account IDs (identity UUIDs) for the ravi-sms-trusted channel.
|
|
51
|
+
*/
|
|
52
|
+
listAccountIds: (cfg: Record<string, unknown>) => string[];
|
|
53
|
+
/**
|
|
54
|
+
* Resolve an account configuration by its ID (identity UUID).
|
|
55
|
+
*/
|
|
56
|
+
resolveAccount: (cfg: Record<string, unknown>, accountId: string) => SmsTrustedAccountConfig;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Normalize an inbound SSE SMS event into a channel message envelope.
|
|
60
|
+
*
|
|
61
|
+
* Only trusted events reach this channel — no sender classification needed.
|
|
62
|
+
*/
|
|
63
|
+
normalizeInbound(event: SmsEvent, account: SmsTrustedAccountConfig): SmsTrustedInboundEnvelope | null;
|
|
64
|
+
outbound: {
|
|
65
|
+
deliveryMode: "direct";
|
|
66
|
+
/**
|
|
67
|
+
* Send an SMS reply to the phone number that triggered this session.
|
|
68
|
+
*
|
|
69
|
+
* Trusted SMS get full reply delivery — the agent can respond directly.
|
|
70
|
+
*/
|
|
71
|
+
sendText: (params: {
|
|
72
|
+
text: string;
|
|
73
|
+
client: RaviClient;
|
|
74
|
+
threadContext?: {
|
|
75
|
+
phoneNumber: string;
|
|
76
|
+
};
|
|
77
|
+
}) => Promise<{
|
|
78
|
+
ok: boolean;
|
|
79
|
+
error?: string;
|
|
80
|
+
}>;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Generate the session key for this channel.
|
|
84
|
+
*
|
|
85
|
+
* Format: `agent:{agentId}:ravi-sms-trusted:{accountId}:dm:{phoneNumber}`
|
|
86
|
+
*/
|
|
87
|
+
getSessionKey(agentId: string, accountId: string, phoneNumber: string): string;
|
|
88
|
+
gateway: {
|
|
89
|
+
/**
|
|
90
|
+
* Start monitoring inbound trusted SMS for a single identity account.
|
|
91
|
+
*
|
|
92
|
+
* Trusted SMS trigger an agent turn with CommandAuthorized: true.
|
|
93
|
+
* Replies are delivered via SMS.
|
|
94
|
+
*/
|
|
95
|
+
startAccount: (ctx: SmsTrustedGatewayContext) => Promise<void>;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
/** The singleton ravi-sms-trusted channel instance. */
|
|
99
|
+
export declare const raviSmsTrustedChannel: {
|
|
100
|
+
id: "ravi-sms-trusted";
|
|
101
|
+
meta: {
|
|
102
|
+
id: string;
|
|
103
|
+
label: string;
|
|
104
|
+
selectionLabel: string;
|
|
105
|
+
blurb: string;
|
|
106
|
+
aliases: string[];
|
|
107
|
+
};
|
|
108
|
+
capabilities: {
|
|
109
|
+
chatTypes: readonly ["direct"];
|
|
110
|
+
};
|
|
111
|
+
config: {
|
|
112
|
+
/**
|
|
113
|
+
* List all configured account IDs (identity UUIDs) for the ravi-sms-trusted channel.
|
|
114
|
+
*/
|
|
115
|
+
listAccountIds: (cfg: Record<string, unknown>) => string[];
|
|
116
|
+
/**
|
|
117
|
+
* Resolve an account configuration by its ID (identity UUID).
|
|
118
|
+
*/
|
|
119
|
+
resolveAccount: (cfg: Record<string, unknown>, accountId: string) => SmsTrustedAccountConfig;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Normalize an inbound SSE SMS event into a channel message envelope.
|
|
123
|
+
*
|
|
124
|
+
* Only trusted events reach this channel — no sender classification needed.
|
|
125
|
+
*/
|
|
126
|
+
normalizeInbound(event: SmsEvent, account: SmsTrustedAccountConfig): SmsTrustedInboundEnvelope | null;
|
|
127
|
+
outbound: {
|
|
128
|
+
deliveryMode: "direct";
|
|
129
|
+
/**
|
|
130
|
+
* Send an SMS reply to the phone number that triggered this session.
|
|
131
|
+
*
|
|
132
|
+
* Trusted SMS get full reply delivery — the agent can respond directly.
|
|
133
|
+
*/
|
|
134
|
+
sendText: (params: {
|
|
135
|
+
text: string;
|
|
136
|
+
client: RaviClient;
|
|
137
|
+
threadContext?: {
|
|
138
|
+
phoneNumber: string;
|
|
139
|
+
};
|
|
140
|
+
}) => Promise<{
|
|
141
|
+
ok: boolean;
|
|
142
|
+
error?: string;
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Generate the session key for this channel.
|
|
147
|
+
*
|
|
148
|
+
* Format: `agent:{agentId}:ravi-sms-trusted:{accountId}:dm:{phoneNumber}`
|
|
149
|
+
*/
|
|
150
|
+
getSessionKey(agentId: string, accountId: string, phoneNumber: string): string;
|
|
151
|
+
gateway: {
|
|
152
|
+
/**
|
|
153
|
+
* Start monitoring inbound trusted SMS for a single identity account.
|
|
154
|
+
*
|
|
155
|
+
* Trusted SMS trigger an agent turn with CommandAuthorized: true.
|
|
156
|
+
* Replies are delivered via SMS.
|
|
157
|
+
*/
|
|
158
|
+
startAccount: (ctx: SmsTrustedGatewayContext) => Promise<void>;
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=sms-trusted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sms-trusted.d.ts","sourceRoot":"","sources":["../../src/channels/sms-trusted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIhE,kFAAkF;AAClF,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;CACf;AAID,gFAAgF;AAChF,MAAM,WAAW,yBAAyB;IACxC,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAID,wEAAwE;AACxE,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;AAInF;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB;;;;;;;;;;;;;QAkBjC;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,uBAAuB;;IAe5B;;;;OAIG;4BAEM,QAAQ,WACN,uBAAuB,GAC/B,yBAAyB,GAAG,IAAI;;;QAcjC;;;;WAIG;2BACsB;YACvB,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,UAAU,CAAC;YACnB,aAAa,CAAC,EAAE;gBAAE,WAAW,EAAE,MAAM,CAAA;aAAE,CAAC;SACzC,KAAG,OAAO,CAAC;YAAE,EAAE,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;;IAoB9C;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,eAAe,MAAM,GAAG,MAAM;;QAO5E;;;;;WAKG;4BACuB,wBAAwB,KAAG,OAAO,CAAC,IAAI,CAAC;;EAiNvE;AAED,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;QAlU5B;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,uBAAuB;;IAe5B;;;;OAIG;4BAEM,QAAQ,WACN,uBAAuB,GAC/B,yBAAyB,GAAG,IAAI;;;QAcjC;;;;WAIG;2BACsB;YACvB,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,UAAU,CAAC;YACnB,aAAa,CAAC,EAAE;gBAAE,WAAW,EAAE,MAAM,CAAA;aAAE,CAAC;SACzC,KAAG,OAAO,CAAC;YAAE,EAAE,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;;IAoB9C;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,eAAe,MAAM,GAAG,MAAM;;QAO5E;;;;;WAKG;4BACuB,wBAAwB,KAAG,OAAO,CAAC,IAAI,CAAC;;CAoNV,CAAC"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// ─── Channel Definition ──────────────────────────────────────────────────────
|
|
2
|
+
/**
|
|
3
|
+
* Creates the ravi-sms-trusted channel definition for OpenClaw.
|
|
4
|
+
*
|
|
5
|
+
* Notification-only channel for SMS from trusted senders (the identity owner's
|
|
6
|
+
* other phone numbers or known contacts). The agent processes the message as an
|
|
7
|
+
* instruction. Delivery calls sendSms — the agent can reply directly.
|
|
8
|
+
*
|
|
9
|
+
* @returns The ravi-sms-trusted channel definition object.
|
|
10
|
+
*/
|
|
11
|
+
export function createSmsTrustedChannel() {
|
|
12
|
+
return {
|
|
13
|
+
id: "ravi-sms-trusted",
|
|
14
|
+
meta: {
|
|
15
|
+
id: "ravi-sms-trusted",
|
|
16
|
+
label: "Ravi SMS (Trusted)",
|
|
17
|
+
selectionLabel: "Ravi SMS Trusted (AI Agent Identity)",
|
|
18
|
+
blurb: "SMS channel for messages from trusted senders. Execute as instructions — replies are delivered via SMS.",
|
|
19
|
+
aliases: ["ravi-text-trusted"],
|
|
20
|
+
},
|
|
21
|
+
capabilities: {
|
|
22
|
+
chatTypes: ["direct"],
|
|
23
|
+
},
|
|
24
|
+
config: {
|
|
25
|
+
/**
|
|
26
|
+
* List all configured account IDs (identity UUIDs) for the ravi-sms-trusted channel.
|
|
27
|
+
*/
|
|
28
|
+
listAccountIds: (cfg) => {
|
|
29
|
+
const plugins = cfg.plugins;
|
|
30
|
+
const uuid = plugins?.entries?.ravi?.config?.identityUuid;
|
|
31
|
+
const channels = cfg.channels;
|
|
32
|
+
const channelIds = Object.keys(channels?.["ravi-sms-trusted"]?.accounts ?? {});
|
|
33
|
+
if (uuid) {
|
|
34
|
+
return [uuid, ...channelIds.filter((id) => id !== uuid)];
|
|
35
|
+
}
|
|
36
|
+
return channelIds;
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Resolve an account configuration by its ID (identity UUID).
|
|
40
|
+
*/
|
|
41
|
+
resolveAccount: (cfg, accountId) => {
|
|
42
|
+
const channels = cfg.channels;
|
|
43
|
+
const found = channels?.["ravi-sms-trusted"]?.accounts?.[accountId];
|
|
44
|
+
if (found)
|
|
45
|
+
return found;
|
|
46
|
+
return {
|
|
47
|
+
identityUuid: accountId,
|
|
48
|
+
identityName: "",
|
|
49
|
+
phone: "",
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* Normalize an inbound SSE SMS event into a channel message envelope.
|
|
55
|
+
*
|
|
56
|
+
* Only trusted events reach this channel — no sender classification needed.
|
|
57
|
+
*/
|
|
58
|
+
normalizeInbound(event, account) {
|
|
59
|
+
return {
|
|
60
|
+
senderId: event.from_number,
|
|
61
|
+
text: event.body,
|
|
62
|
+
threadId: event.from_number,
|
|
63
|
+
metadata: {
|
|
64
|
+
conversationId: event.conversation_id,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
outbound: {
|
|
69
|
+
deliveryMode: "direct",
|
|
70
|
+
/**
|
|
71
|
+
* Send an SMS reply to the phone number that triggered this session.
|
|
72
|
+
*
|
|
73
|
+
* Trusted SMS get full reply delivery — the agent can respond directly.
|
|
74
|
+
*/
|
|
75
|
+
sendText: async (params) => {
|
|
76
|
+
const { text, client, threadContext } = params;
|
|
77
|
+
if (!threadContext?.phoneNumber) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
error: "No SMS thread context — cannot send without a recipient phone number",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
await client.sendSms(threadContext.phoneNumber, text);
|
|
85
|
+
return { ok: true };
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
89
|
+
return { ok: false, error: `Failed to send SMS: ${message}` };
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* Generate the session key for this channel.
|
|
95
|
+
*
|
|
96
|
+
* Format: `agent:{agentId}:ravi-sms-trusted:{accountId}:dm:{phoneNumber}`
|
|
97
|
+
*/
|
|
98
|
+
getSessionKey(agentId, accountId, phoneNumber) {
|
|
99
|
+
return `agent:${agentId}:ravi-sms-trusted:${accountId}:dm:${phoneNumber}`;
|
|
100
|
+
},
|
|
101
|
+
// ─── Gateway Adapter ──────────────────────────────────────────────────
|
|
102
|
+
gateway: {
|
|
103
|
+
/**
|
|
104
|
+
* Start monitoring inbound trusted SMS for a single identity account.
|
|
105
|
+
*
|
|
106
|
+
* Trusted SMS trigger an agent turn with CommandAuthorized: true.
|
|
107
|
+
* Replies are delivered via SMS.
|
|
108
|
+
*/
|
|
109
|
+
startAccount: async (ctx) => {
|
|
110
|
+
const log = ctx.log ?? {
|
|
111
|
+
info: (...args) => console.log("[ravi-sms-trusted]", ...args),
|
|
112
|
+
warn: (...args) => console.warn("[ravi-sms-trusted]", ...args),
|
|
113
|
+
error: (...args) => console.error("[ravi-sms-trusted]", ...args),
|
|
114
|
+
};
|
|
115
|
+
let getRaviRuntime, loadAuth, updateAuth, RAVI_API_URL, RaviClient, acquireSSEClient, releaseSSEClient;
|
|
116
|
+
try {
|
|
117
|
+
({ getRaviRuntime } = await import("../runtime.js"));
|
|
118
|
+
({ loadAuth, updateAuth } = await import("../auth.js"));
|
|
119
|
+
({ RAVI_API_URL } = await import("../config.js"));
|
|
120
|
+
({ RaviClient } = await import("../client.js"));
|
|
121
|
+
({ acquireSSEClient, releaseSSEClient } = await import("../sse-pool.js"));
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
125
|
+
log.error(`[ravi-sms-trusted] Failed to load dependencies: ${detail}. Is the plugin built correctly?`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const runtime = getRaviRuntime();
|
|
129
|
+
const auth = loadAuth();
|
|
130
|
+
if (!auth?.access_token) {
|
|
131
|
+
log.error("[ravi-sms-trusted] No auth credentials — cannot start SMS-trusted channel. Run 'openclaw ravi login'.");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
let currentToken = auth.access_token;
|
|
135
|
+
let sse = null;
|
|
136
|
+
const client = new RaviClient({
|
|
137
|
+
apiUrl: RAVI_API_URL,
|
|
138
|
+
token: auth.access_token,
|
|
139
|
+
refreshToken: auth.refresh_token,
|
|
140
|
+
identityUuid: ctx.accountId,
|
|
141
|
+
onTokenRefresh: (newToken) => {
|
|
142
|
+
currentToken = newToken;
|
|
143
|
+
try {
|
|
144
|
+
updateAuth({ access_token: newToken });
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
148
|
+
log.error(`[ravi-sms-trusted] Failed to persist refreshed token: ${detail}`);
|
|
149
|
+
}
|
|
150
|
+
sse?.updateToken(newToken);
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
let phone = ctx.account.phone;
|
|
154
|
+
let identityName = ctx.account.identityName;
|
|
155
|
+
if (!phone) {
|
|
156
|
+
try {
|
|
157
|
+
const identities = await client.listIdentities();
|
|
158
|
+
const identity = identities.find((i) => i.uuid === ctx.accountId);
|
|
159
|
+
phone = identity?.phone ?? "";
|
|
160
|
+
identityName = identity?.display_name ?? identity?.name ?? ctx.accountId;
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
if (err?.name === "RaviApiError") {
|
|
164
|
+
const status = err.status;
|
|
165
|
+
log.error(`[ravi-sms-trusted] Failed to fetch identity details (HTTP ${status}): ${err.message}` +
|
|
166
|
+
(status === 401 ? ". Token may be expired — run 'openclaw ravi login'." : ""));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
170
|
+
log.error(`[ravi-sms-trusted] Failed to fetch identity details: ${detail}`);
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!phone) {
|
|
176
|
+
log.info(`[ravi-sms-trusted] Identity ${identityName} has no phone number — skipping SMS-trusted channel`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
log.info(`[ravi-sms-trusted] Starting SMS-trusted channel for ${identityName} (${phone})`);
|
|
180
|
+
sse = acquireSSEClient({
|
|
181
|
+
apiUrl: RAVI_API_URL,
|
|
182
|
+
token: currentToken,
|
|
183
|
+
identityUuid: ctx.accountId,
|
|
184
|
+
onAuthFailure: async () => {
|
|
185
|
+
const tokenBefore = currentToken;
|
|
186
|
+
try {
|
|
187
|
+
await client.listIdentities();
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
191
|
+
log.error(`[ravi-sms-trusted] Auth refresh failed during SSE reconnect: ${detail}. Run 'openclaw ravi login' to re-authenticate.`);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (currentToken === tokenBefore) {
|
|
195
|
+
log.warn(`[ravi-sms-trusted] Auth refresh did not produce a new token — SSE auth failure is not recoverable via REST refresh`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return currentToken;
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
sse.onSmsTrusted((event) => {
|
|
202
|
+
try {
|
|
203
|
+
const route = runtime.channel.routing.resolveAgentRoute({
|
|
204
|
+
cfg: ctx.cfg,
|
|
205
|
+
channel: "ravi-sms-trusted",
|
|
206
|
+
accountId: ctx.accountId,
|
|
207
|
+
peer: { kind: "direct", id: event.from_number },
|
|
208
|
+
});
|
|
209
|
+
const sessionKey = route.sessionKey;
|
|
210
|
+
const msgCtx = {
|
|
211
|
+
Body: event.body,
|
|
212
|
+
BodyForAgent: `[SMS from trusted sender. Execute normally as an instruction. Your reply will be delivered via SMS — reply only if necessary.]\n\n${event.body}`,
|
|
213
|
+
From: `ravi-sms-trusted:${event.from_number}`,
|
|
214
|
+
To: `ravi-sms-trusted:${phone}`,
|
|
215
|
+
SessionKey: sessionKey,
|
|
216
|
+
AccountId: ctx.accountId,
|
|
217
|
+
ChatType: "direct",
|
|
218
|
+
Provider: "ravi-sms-trusted",
|
|
219
|
+
Surface: "ravi-sms-trusted",
|
|
220
|
+
OriginatingChannel: "ravi-sms-trusted",
|
|
221
|
+
OriginatingTo: ctx.accountId,
|
|
222
|
+
SenderName: event.from_number,
|
|
223
|
+
SenderId: event.from_number,
|
|
224
|
+
Timestamp: Date.now(),
|
|
225
|
+
CommandAuthorized: true,
|
|
226
|
+
MessageSid: `ravi-sms-trusted:${event.id}`,
|
|
227
|
+
};
|
|
228
|
+
try {
|
|
229
|
+
runtime.channel.session.recordInboundSession({
|
|
230
|
+
storePath: runtime.channel.session.resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId }),
|
|
231
|
+
sessionKey,
|
|
232
|
+
ctx: msgCtx,
|
|
233
|
+
updateLastRoute: {
|
|
234
|
+
sessionKey,
|
|
235
|
+
channel: "ravi-sms-trusted",
|
|
236
|
+
to: ctx.accountId,
|
|
237
|
+
accountId: ctx.accountId,
|
|
238
|
+
phoneNumber: event.from_number,
|
|
239
|
+
},
|
|
240
|
+
onRecordError: (err) => {
|
|
241
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
242
|
+
log.error(`[ravi-sms-trusted] Session record error for ${event.from_number}: ${detail}`);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
248
|
+
log.error(`[ravi-sms-trusted] recordInboundSession threw for ${event.from_number}: ${detail}`);
|
|
249
|
+
}
|
|
250
|
+
runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
251
|
+
ctx: msgCtx,
|
|
252
|
+
cfg: ctx.cfg,
|
|
253
|
+
dispatcherOptions: {
|
|
254
|
+
deliver: async (payload) => {
|
|
255
|
+
if (!payload.text) {
|
|
256
|
+
log.info(`[ravi-sms-trusted] Deliver called with empty text for ${event.from_number} — skipping`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
await client.sendSms(event.from_number, payload.text);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
264
|
+
const status = err?.status;
|
|
265
|
+
log.error(`[ravi-sms-trusted] Failed to deliver reply to ${event.from_number}` +
|
|
266
|
+
`${status ? ` (HTTP ${status})` : ""}: ${detail}`);
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
onError: (err) => {
|
|
270
|
+
log.error(`[ravi-sms-trusted] Dispatch error: ${err}`);
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
}).catch((err) => {
|
|
274
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
275
|
+
log.error(`[ravi-sms-trusted] dispatchReply failed for ${event.from_number}: ${detail}`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
280
|
+
log.error(`[ravi-sms-trusted] Unhandled error processing event ${event.id}: ${detail}`);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
sse.onReconnect(() => {
|
|
284
|
+
log.info(`[ravi-sms-trusted] SSE reconnecting for ${identityName}`);
|
|
285
|
+
});
|
|
286
|
+
log.info(`[ravi-sms-trusted] SSE connected for ${identityName} (${ctx.accountId})`);
|
|
287
|
+
await new Promise((resolve) => {
|
|
288
|
+
if (ctx.abortSignal.aborted) {
|
|
289
|
+
log.info(`[ravi-sms-trusted] Stopping SMS-trusted channel for ${identityName} (already aborted)`);
|
|
290
|
+
releaseSSEClient(ctx.accountId);
|
|
291
|
+
resolve();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
ctx.abortSignal.addEventListener("abort", () => {
|
|
295
|
+
log.info(`[ravi-sms-trusted] Stopping SMS-trusted channel for ${identityName}`);
|
|
296
|
+
releaseSSEClient(ctx.accountId);
|
|
297
|
+
resolve();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/** The singleton ravi-sms-trusted channel instance. */
|
|
305
|
+
export const raviSmsTrustedChannel = createSmsTrustedChannel();
|
|
306
|
+
//# sourceMappingURL=sms-trusted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sms-trusted.js","sourceRoot":"","sources":["../../src/channels/sms-trusted.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { SmsEvent, BaseGatewayContext } from "../types.js";
|
|
2
|
+
/** Configuration for a single SMS account within the ravi-sms-untrusted channel. */
|
|
3
|
+
export interface SmsUntrustedAccountConfig {
|
|
4
|
+
/** The identity UUID this account is bound to. */
|
|
5
|
+
identityUuid: string;
|
|
6
|
+
/** Human-readable identity name for display purposes. */
|
|
7
|
+
identityName: string;
|
|
8
|
+
/** The phone number provisioned for this identity (E.164 format). */
|
|
9
|
+
phone: string;
|
|
10
|
+
}
|
|
11
|
+
/** Normalized inbound message envelope produced by {@link normalizeInbound}. */
|
|
12
|
+
export interface SmsUntrustedInboundEnvelope {
|
|
13
|
+
/** Sender's phone number (used as the sender ID). */
|
|
14
|
+
senderId: string;
|
|
15
|
+
/** Plain-text body of the SMS message. */
|
|
16
|
+
text: string;
|
|
17
|
+
/** Phone number that maps to the OpenClaw session key. */
|
|
18
|
+
threadId: string;
|
|
19
|
+
/** Additional SMS metadata passed through to the agent. */
|
|
20
|
+
metadata: {
|
|
21
|
+
conversationId: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Context passed by the ChannelManager to `gateway.startAccount()`. */
|
|
25
|
+
export type SmsUntrustedGatewayContext = BaseGatewayContext<SmsUntrustedAccountConfig>;
|
|
26
|
+
/**
|
|
27
|
+
* Creates the ravi-sms-untrusted channel definition for OpenClaw.
|
|
28
|
+
*
|
|
29
|
+
* Cautionary notification channel for SMS from unknown external senders.
|
|
30
|
+
* The agent treats content as context, not instructions. Delivery is a no-op
|
|
31
|
+
* — the agent should not reply automatically to untrusted SMS.
|
|
32
|
+
*
|
|
33
|
+
* @returns The ravi-sms-untrusted channel definition object.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSmsUntrustedChannel(): {
|
|
36
|
+
id: "ravi-sms-untrusted";
|
|
37
|
+
meta: {
|
|
38
|
+
id: string;
|
|
39
|
+
label: string;
|
|
40
|
+
selectionLabel: string;
|
|
41
|
+
blurb: string;
|
|
42
|
+
aliases: string[];
|
|
43
|
+
};
|
|
44
|
+
capabilities: {
|
|
45
|
+
chatTypes: readonly ["direct"];
|
|
46
|
+
};
|
|
47
|
+
config: {
|
|
48
|
+
/**
|
|
49
|
+
* List all configured account IDs (identity UUIDs) for the ravi-sms-untrusted channel.
|
|
50
|
+
*/
|
|
51
|
+
listAccountIds: (cfg: Record<string, unknown>) => string[];
|
|
52
|
+
/**
|
|
53
|
+
* Resolve an account configuration by its ID (identity UUID).
|
|
54
|
+
*/
|
|
55
|
+
resolveAccount: (cfg: Record<string, unknown>, accountId: string) => SmsUntrustedAccountConfig;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Normalize an inbound SSE SMS event into a channel message envelope.
|
|
59
|
+
*
|
|
60
|
+
* Only untrusted events reach this channel — no sender classification needed.
|
|
61
|
+
*/
|
|
62
|
+
normalizeInbound(event: SmsEvent, account: SmsUntrustedAccountConfig): SmsUntrustedInboundEnvelope | null;
|
|
63
|
+
/**
|
|
64
|
+
* Generate the session key for this channel.
|
|
65
|
+
*
|
|
66
|
+
* Format: `agent:{agentId}:ravi-sms-untrusted:{accountId}:dm:{phoneNumber}`
|
|
67
|
+
*/
|
|
68
|
+
getSessionKey(agentId: string, accountId: string, phoneNumber: string): string;
|
|
69
|
+
gateway: {
|
|
70
|
+
/**
|
|
71
|
+
* Start monitoring inbound untrusted SMS for a single identity account.
|
|
72
|
+
*
|
|
73
|
+
* Untrusted SMS trigger an agent turn with CommandAuthorized: false.
|
|
74
|
+
* Delivery is a no-op — the agent should not auto-reply to unknown senders.
|
|
75
|
+
*/
|
|
76
|
+
startAccount: (ctx: SmsUntrustedGatewayContext) => Promise<void>;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
/** The singleton ravi-sms-untrusted channel instance. */
|
|
80
|
+
export declare const raviSmsUntrustedChannel: {
|
|
81
|
+
id: "ravi-sms-untrusted";
|
|
82
|
+
meta: {
|
|
83
|
+
id: string;
|
|
84
|
+
label: string;
|
|
85
|
+
selectionLabel: string;
|
|
86
|
+
blurb: string;
|
|
87
|
+
aliases: string[];
|
|
88
|
+
};
|
|
89
|
+
capabilities: {
|
|
90
|
+
chatTypes: readonly ["direct"];
|
|
91
|
+
};
|
|
92
|
+
config: {
|
|
93
|
+
/**
|
|
94
|
+
* List all configured account IDs (identity UUIDs) for the ravi-sms-untrusted channel.
|
|
95
|
+
*/
|
|
96
|
+
listAccountIds: (cfg: Record<string, unknown>) => string[];
|
|
97
|
+
/**
|
|
98
|
+
* Resolve an account configuration by its ID (identity UUID).
|
|
99
|
+
*/
|
|
100
|
+
resolveAccount: (cfg: Record<string, unknown>, accountId: string) => SmsUntrustedAccountConfig;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Normalize an inbound SSE SMS event into a channel message envelope.
|
|
104
|
+
*
|
|
105
|
+
* Only untrusted events reach this channel — no sender classification needed.
|
|
106
|
+
*/
|
|
107
|
+
normalizeInbound(event: SmsEvent, account: SmsUntrustedAccountConfig): SmsUntrustedInboundEnvelope | null;
|
|
108
|
+
/**
|
|
109
|
+
* Generate the session key for this channel.
|
|
110
|
+
*
|
|
111
|
+
* Format: `agent:{agentId}:ravi-sms-untrusted:{accountId}:dm:{phoneNumber}`
|
|
112
|
+
*/
|
|
113
|
+
getSessionKey(agentId: string, accountId: string, phoneNumber: string): string;
|
|
114
|
+
gateway: {
|
|
115
|
+
/**
|
|
116
|
+
* Start monitoring inbound untrusted SMS for a single identity account.
|
|
117
|
+
*
|
|
118
|
+
* Untrusted SMS trigger an agent turn with CommandAuthorized: false.
|
|
119
|
+
* Delivery is a no-op — the agent should not auto-reply to unknown senders.
|
|
120
|
+
*/
|
|
121
|
+
startAccount: (ctx: SmsUntrustedGatewayContext) => Promise<void>;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=sms-untrusted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sms-untrusted.d.ts","sourceRoot":"","sources":["../../src/channels/sms-untrusted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIhE,oFAAoF;AACpF,MAAM,WAAW,yBAAyB;IACxC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;CACf;AAID,gFAAgF;AAChF,MAAM,WAAW,2BAA2B;IAC1C,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAID,wEAAwE;AACxE,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;AAIvF;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB;;;;;;;;;;;;;QAkBnC;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,yBAAyB;;IAe9B;;;;OAIG;4BAEM,QAAQ,WACN,yBAAyB,GACjC,2BAA2B,GAAG,IAAI;IAWrC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,eAAe,MAAM,GAAG,MAAM;;QAO5E;;;;;WAKG;4BACuB,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAAC;;EAoMzE;AAED,yDAAyD;AACzD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;QArR9B;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,yBAAyB;;IAe9B;;;;OAIG;4BAEM,QAAQ,WACN,yBAAyB,GACjC,2BAA2B,GAAG,IAAI;IAWrC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,eAAe,MAAM,GAAG,MAAM;;QAO5E;;;;;WAKG;4BACuB,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAAC;;CAuMR,CAAC"}
|