@rine-network/eve 0.3.0 → 0.5.0
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 +12 -6
- package/dist/{channel-WlN3x1wP.js → channel-B81UiHyr.js} +12 -9
- package/dist/channel-core.d.ts +9 -6
- package/dist/channel.d.ts +1 -1
- package/dist/channel.js +1 -1
- package/dist/{client-DsG2xtKs.js → client-CXJATA-m.js} +22 -2
- package/dist/client.d.ts +18 -0
- package/dist/format-groups-list.d.ts +140 -0
- package/dist/format-groups.d.ts +81 -0
- package/dist/format.d.ts +51 -11
- package/dist/index.js +7 -7
- package/dist/onboard.js +2 -2
- package/dist/{registry-Bn4EqPcp.js → registry-DsU13KY3.js} +47 -2
- package/dist/relay.js +2 -2
- package/dist/scaffold-DQ2CA1kD.js +239 -0
- package/dist/scaffold.js +1 -1
- package/dist/schemas-groups-list.d.ts +29 -0
- package/dist/schemas-groups.d.ts +83 -9
- package/dist/schemas.d.ts +26 -6
- package/dist/skill-content.d.ts +8 -2
- package/dist/tool-DeOeMNlK.js +618 -0
- package/dist/tool.d.ts +2 -2
- package/dist/tools/discovery.d.ts +8 -2
- package/dist/tools/groups-admin.d.ts +25 -0
- package/dist/tools/groups-admission.d.ts +56 -0
- package/dist/tools/groups-list.d.ts +21 -0
- package/dist/tools/groups-resolve.d.ts +80 -0
- package/dist/tools/groups.d.ts +18 -14
- package/dist/tools/index.d.ts +5 -3
- package/dist/tools/index.js +3 -3
- package/dist/tools/messaging.d.ts +13 -11
- package/dist/tools-CQDZG-qN.js +1149 -0
- package/dist/types.d.ts +2 -1
- package/dist/webhook.d.ts +8 -1
- package/dist/webhook.js +33 -13
- package/package.json +3 -3
- package/dist/scaffold-3cEUy3jD.js +0 -147
- package/dist/tool-xlLdY8kn.js +0 -276
- package/dist/tools-BhkhV3Mv.js +0 -595
package/dist/tools-BhkhV3Mv.js
DELETED
|
@@ -1,595 +0,0 @@
|
|
|
1
|
-
import { _ as renderThread, a as GROUP_ON_WAIT_MESSAGE, b as verifiedNote, c as groupIsMls, d as renderInbox, f as renderInvites, g as renderSingleMessage, h as renderProfile, i as redactToText, l as renderDiscover, m as renderMessageBody, n as asRecipient, p as renderJoinResult, r as makeExecute, s as isGroupUnsupportedOnWait, t as approvalGate, u as renderGroup } from "./tool-xlLdY8kn.js";
|
|
2
|
-
import { t as RINE_TOOL_META } from "./registry-Bn4EqPcp.js";
|
|
3
|
-
import { FACILITATOR_PRESET, NotFoundError, X402Error, X402FacilitatorError, X402_ERROR, X402_MESSAGE_TYPE, asAgentUuid, asGroupUuid, asMessageUuid } from "@rine-network/sdk";
|
|
4
|
-
import { UUID_RE, normalizeHandle, resolveToUuid } from "@rine-network/core";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { defineTool } from "eve/tools";
|
|
7
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
8
|
-
//#region src/_zod.ts
|
|
9
|
-
/**
|
|
10
|
-
* Convert a zod schema to a plain JSON Schema for `defineTool`'s `inputSchema`.
|
|
11
|
-
* Returns `any` deliberately: it bridges into Eve's internal `JsonObject` type,
|
|
12
|
-
* which is not exported for us to name.
|
|
13
|
-
*/
|
|
14
|
-
function jsonSchema(schema) {
|
|
15
|
-
return zodToJsonSchema(schema, { $refStrategy: "none" });
|
|
16
|
-
}
|
|
17
|
-
/** The shared `outputSchema` for every rine tool: a JSON-Schema string. */
|
|
18
|
-
const STRING_OUTPUT = { type: "string" };
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/schemas-groups.ts
|
|
21
|
-
/**
|
|
22
|
-
* Zod input schemas for the 6 group tools (split out of `schemas.ts` to hold the
|
|
23
|
-
* ~200-LOC budget — one file per domain). Same authoring rules: rich `.describe()`
|
|
24
|
-
* on every field, NO identity/credentials in the schema (env-injected).
|
|
25
|
-
*
|
|
26
|
-
* Groups are MLS-capable by default — `enableMls` (default true) on create.
|
|
27
|
-
*/
|
|
28
|
-
const groupCreateInput = z.object({
|
|
29
|
-
name: z.string().describe("Human-readable group name. A group handle is derived from it."),
|
|
30
|
-
enrollment: z.enum([
|
|
31
|
-
"open",
|
|
32
|
-
"closed",
|
|
33
|
-
"majority",
|
|
34
|
-
"unanimity"
|
|
35
|
-
]).default("closed").describe("Who may join and how: `open` (anyone), `closed` (invite-only, default), `majority` (member vote), `unanimity` (all must approve)."),
|
|
36
|
-
visibility: z.enum(["public", "private"]).default("private").describe("`public` (listed in discovery) or `private` (hidden, default)."),
|
|
37
|
-
description: z.string().optional().describe("Optional group description."),
|
|
38
|
-
enableMls: z.boolean().default(true).describe("Create the group with MLS (RFC 9420) end-to-end encryption (default true). MLS gives forward secrecy and post-compromise security; disable only to force the legacy sender-key scheme.")
|
|
39
|
-
});
|
|
40
|
-
const groupInviteInput = z.object({
|
|
41
|
-
group: z.string().describe("The target group: a handle (`#name@org`) or a UUID. Resolved to a UUID before inviting."),
|
|
42
|
-
agentToInvite: z.string().describe("The agent to invite: a handle (`name@org`) or a UUID. Resolved to a UUID before inviting."),
|
|
43
|
-
message: z.string().optional().describe("Optional message included with the invite.")
|
|
44
|
-
});
|
|
45
|
-
const groupRemoveInput = z.object({
|
|
46
|
-
group: z.string().describe("The target group: a handle (`#name@org`) or a UUID. Resolved to a UUID before removal."),
|
|
47
|
-
agentId: z.string().describe("The member to remove: a handle (`name@org`) or a UUID. Group keys are rotated after removal.")
|
|
48
|
-
});
|
|
49
|
-
const groupInspectInput = z.object({ group: z.string().describe("The group to inspect: a handle (`#name@org`) or a UUID. Reports its E2EE mode and policy.") });
|
|
50
|
-
const groupJoinInput = z.object({
|
|
51
|
-
group: z.string().describe("The group to join: a handle (`#name@org`), bare name, or a UUID. Resolved against your pending invites, or pass the UUID directly for a publicly discovered open-enrollment group."),
|
|
52
|
-
message: z.string().optional().describe("Optional message included with the join request (approval-gated groups only).")
|
|
53
|
-
});
|
|
54
|
-
/** No input: lists the caller's own pending group invites. */
|
|
55
|
-
const groupInvitesInput = z.object({});
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/schemas-payments.ts
|
|
58
|
-
/**
|
|
59
|
-
* Zod input schemas for the 2 x402 payment tools (split out of `schemas.ts` to
|
|
60
|
-
* hold the ~200-LOC budget — one file per domain). Same authoring rules: rich
|
|
61
|
-
* `.describe()` on every field, NO identity/credentials in the schema
|
|
62
|
-
* (env-injected). The facilitator is infra config, resolved from the tool factory / env —
|
|
63
|
-
* never a model-visible input.
|
|
64
|
-
*/
|
|
65
|
-
const payInput = z.object({
|
|
66
|
-
messageId: z.string().describe("The UUID of the received `rine.v1.x402_payment_required` quote to pay. The signed payment is sent back in the same conversation."),
|
|
67
|
-
autoPay: z.boolean().default(false).describe("If true, pay ONLY when the quote is at/below your policy's autoPayThreshold; otherwise return `above-auto-pay-threshold` without paying. Default false — calling this tool is itself the authorization, still bounded by the spend caps."),
|
|
68
|
-
emitMarker: z.boolean().default(true).describe("Attach the cleartext status marker (coarse lifecycle state only — never amounts/assets/addresses). Default true; set false for a fully-sealed payment."),
|
|
69
|
-
allowRepay: z.boolean().default(false).describe("If true, re-pay a quote already paid today (a deliberate second, permanent debit). Default false — a repeat pay of the same messageId returns `already-paid` without spending.")
|
|
70
|
-
});
|
|
71
|
-
const fulfillInput = z.object({
|
|
72
|
-
messageId: z.string().describe("The UUID of the received `rine.v1.x402_payment` (signed authorization) to fulfill. Verifies and settles it via your configured facilitator, then sends the receipt back in-thread."),
|
|
73
|
-
emitMarker: z.boolean().default(true).describe("Attach the cleartext status marker on the receipt (coarse lifecycle state only). Default true.")
|
|
74
|
-
});
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/schemas.ts
|
|
77
|
-
/**
|
|
78
|
-
* Shared Zod input schemas for the 12 rine tools.
|
|
79
|
-
*
|
|
80
|
-
* Rich `.describe()` on EVERY field: the field descriptions are the #1 lever on
|
|
81
|
-
* tool-call accuracy (the AI-DX). Identity/credentials NEVER appear here — the
|
|
82
|
-
* acting agent + config dir come from `process.env`, never the model-visible
|
|
83
|
-
* input schema.
|
|
84
|
-
*/
|
|
85
|
-
const DEFAULT_MESSAGE_TYPE = "rine.v1.task_request";
|
|
86
|
-
const DEFAULT_REPLY_TYPE = "rine.v1.task_response";
|
|
87
|
-
const sendInput = z.object({
|
|
88
|
-
to: z.string().describe("Recipient address: a 1:1 agent handle `name@org`, a UUID, or a group handle prefixed with `#` (e.g. `#ops@acme`). A `#` target sends to the whole group over its E2EE channel (MLS or sender-key, chosen automatically)."),
|
|
89
|
-
body: z.string().describe("The plaintext message text to send. It is end-to-end encrypted before transmission."),
|
|
90
|
-
messageType: z.string().default(DEFAULT_MESSAGE_TYPE).describe("The rine message type, e.g. `rine.v1.task_request` (default) or `rine.v1.text`. Leave as the default unless you know the recipient expects a specific type."),
|
|
91
|
-
idempotencyKey: z.string().optional().describe("Optional idempotency key. Reusing the same key for a retry prevents a duplicate send if the first attempt's response was lost.")
|
|
92
|
-
});
|
|
93
|
-
const sendAndWaitInput = z.object({
|
|
94
|
-
to: z.string().describe("Recipient agent address (1:1 ONLY): a handle `name@org` or a UUID. Group handles (`#…`) are NOT supported here — use rine_send for groups."),
|
|
95
|
-
body: z.string().describe("The plaintext message text to send. End-to-end encrypted before transmission."),
|
|
96
|
-
waitSeconds: z.number().int().min(1).max(300).default(30).describe("How long to block waiting for a reply, in SECONDS (1–300, default 30). Returns the reply if one arrives in time, otherwise a 'no reply' note."),
|
|
97
|
-
messageType: z.string().default(DEFAULT_MESSAGE_TYPE).describe(`The rine message type (default \`${DEFAULT_MESSAGE_TYPE}\`).`)
|
|
98
|
-
});
|
|
99
|
-
const checkInboxInput = z.object({ limit: z.number().int().min(1).max(100).default(20).describe("Maximum number of new messages to fetch and decrypt (1–100, default 20). Fetched messages are marked delivered so a later check returns only newer mail.") });
|
|
100
|
-
const readInput = z.object({ messageId: z.string().describe("The UUID of the message to fetch and decrypt. Returns the decrypted body and signature status.") });
|
|
101
|
-
const replyInput = z.object({
|
|
102
|
-
messageId: z.string().describe("The UUID of the message you are replying to. The reply threads into the same conversation."),
|
|
103
|
-
body: z.string().describe("The plaintext reply text. End-to-end encrypted before transmission."),
|
|
104
|
-
messageType: z.string().default(DEFAULT_REPLY_TYPE).describe(`The rine message type for the reply (default \`${DEFAULT_REPLY_TYPE}\`).`)
|
|
105
|
-
});
|
|
106
|
-
const threadInput = z.object({
|
|
107
|
-
conversationId: z.string().describe("The UUID of the conversation to fetch the transcript of. Returns every turn (yours and the peer's) decrypted and role-tagged, oldest→newest."),
|
|
108
|
-
limit: z.number().int().min(1).max(100).optional().describe("Optional max number of most-recent turns to return (1–100). Omit for the server default.")
|
|
109
|
-
});
|
|
110
|
-
const discoverInput = z.object({
|
|
111
|
-
q: z.string().optional().describe("Free-text search query matched against agent names, handles, and descriptions."),
|
|
112
|
-
category: z.string().optional().describe("Filter by agent category (e.g. `research`, `support`)."),
|
|
113
|
-
language: z.string().optional().describe("Filter by the agent's working language (e.g. `en`, `de`)."),
|
|
114
|
-
verified: z.boolean().optional().describe("When true, return only verified agents; when false, only unverified; omit for both."),
|
|
115
|
-
limit: z.number().int().min(1).max(100).default(10).describe("Maximum number of agents to return (1–100, default 10).")
|
|
116
|
-
});
|
|
117
|
-
const inspectInput = z.object({ handleOrId: z.string().describe("An agent handle (`name@org`, resolved via WebFinger) or a UUID. Returns the full public profile.") });
|
|
118
|
-
//#endregion
|
|
119
|
-
//#region src/tools/discovery.ts
|
|
120
|
-
/**
|
|
121
|
-
* The 2 discovery tool factories: `rine_discover`, `rine_inspect`. Both are
|
|
122
|
-
* unauthenticated directory reads.
|
|
123
|
-
*/
|
|
124
|
-
/** `rine_discover` — search the public agent directory. */
|
|
125
|
-
function rineDiscoverTool(opts = {}) {
|
|
126
|
-
return defineTool({
|
|
127
|
-
description: "Search the public rine agent directory by free text, category, language, and/or verification status. Returns a numbered list of matching agents with their handles. Use this to find an agent's handle before messaging it.",
|
|
128
|
-
inputSchema: jsonSchema(discoverInput),
|
|
129
|
-
outputSchema: STRING_OUTPUT,
|
|
130
|
-
execute: makeExecute(discoverInput, opts, async (client, i) => {
|
|
131
|
-
return renderDiscover((await client.discover({
|
|
132
|
-
q: i.q,
|
|
133
|
-
category: i.category,
|
|
134
|
-
language: i.language,
|
|
135
|
-
verified: i.verified,
|
|
136
|
-
limit: i.limit
|
|
137
|
-
})).items);
|
|
138
|
-
})
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
/** `rine_inspect` — fetch one agent's full public profile. */
|
|
142
|
-
function rineInspectTool(opts = {}) {
|
|
143
|
-
return defineTool({
|
|
144
|
-
description: "Fetch the full public profile of an agent by its handle (`name@org`) or UUID — name, description, category, verification, and human-oversight status.",
|
|
145
|
-
inputSchema: jsonSchema(inspectInput),
|
|
146
|
-
outputSchema: STRING_OUTPUT,
|
|
147
|
-
execute: makeExecute(inspectInput, opts, async (client, i) => {
|
|
148
|
-
return renderProfile(await client.inspect(i.handleOrId));
|
|
149
|
-
})
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
//#endregion
|
|
153
|
-
//#region src/tools/groups.ts
|
|
154
|
-
/**
|
|
155
|
-
* The 6 group tool factories: `rine_group_create`, `rine_group_invite`,
|
|
156
|
-
* `rine_group_remove`, `rine_group_inspect`, `rine_group_join`,
|
|
157
|
-
* `rine_group_invites`. Groups are MLS-by-default.
|
|
158
|
-
*
|
|
159
|
-
* The TS SDK's `groups.invite`/`removeMember` take BRANDED UUIDs positionally, so
|
|
160
|
-
* invite/remove/inspect PRE-RESOLVE handle→UUID here:
|
|
161
|
-
* - a group → `groups.list()` + local match (`findGroup`),
|
|
162
|
-
* - an agent → `resolveToUuid` (WebFinger) → its UUID (or pass a UUID through),
|
|
163
|
-
* so unlisted agents resolve too.
|
|
164
|
-
* `join` resolves a handle the same way but against the caller's PENDING
|
|
165
|
-
* INVITES (`groups.listInvites()`) — an invitee isn't a member yet, so it can't
|
|
166
|
-
* appear in `groups.list()`. A bare UUID always passes through unchanged (the
|
|
167
|
-
* path for a publicly discovered open-enrollment group with no invite record).
|
|
168
|
-
*/
|
|
169
|
-
/** True for a bare UUID string (no `@`, matches the rine UUID shape). */
|
|
170
|
-
function isUuid(s) {
|
|
171
|
-
return UUID_RE.test(s);
|
|
172
|
-
}
|
|
173
|
-
/** A handle's bare local name: `#ops@acme` / `ops` → `ops`. */
|
|
174
|
-
function bareLocalName(handle) {
|
|
175
|
-
return handle.replace(/^#/, "").split("@")[0] ?? handle;
|
|
176
|
-
}
|
|
177
|
-
/** Match a group among the caller's groups by UUID, full handle, or bare name. */
|
|
178
|
-
function findGroup(groups, target) {
|
|
179
|
-
if (isUuid(target)) return groups.find((g) => g.id === target);
|
|
180
|
-
if (!target.includes("@")) {
|
|
181
|
-
const want = bareLocalName(target);
|
|
182
|
-
return groups.find((g) => bareLocalName(g.handle) === want);
|
|
183
|
-
}
|
|
184
|
-
const want = normalizeHandle(target.startsWith("#") ? target : `#${target}`);
|
|
185
|
-
return groups.find((g) => normalizeHandle(g.handle) === want);
|
|
186
|
-
}
|
|
187
|
-
/** Resolve a group handle/UUID to its `GroupUuid` via the caller's group list. */
|
|
188
|
-
async function resolveGroupUuid(client, target) {
|
|
189
|
-
if (isUuid(target)) return asGroupUuid(target);
|
|
190
|
-
const match = findGroup((await client.groups.list()).items, target);
|
|
191
|
-
if (!match) throw new NotFoundError(`No group '${target}' among the groups this agent belongs to`);
|
|
192
|
-
return asGroupUuid(match.id);
|
|
193
|
-
}
|
|
194
|
-
/** Resolve an agent handle/UUID to its `AgentUuid` (UUIDs pass through). */
|
|
195
|
-
async function resolveAgentUuid(apiUrl, target) {
|
|
196
|
-
if (isUuid(target)) return asAgentUuid(target);
|
|
197
|
-
return asAgentUuid(await resolveToUuid(apiUrl, target));
|
|
198
|
-
}
|
|
199
|
-
/** Match a pending invite among the caller's invites by UUID, full handle, or bare name. */
|
|
200
|
-
function findInvite(invites, target) {
|
|
201
|
-
if (isUuid(target)) return invites.find((inv) => inv.group_id === target);
|
|
202
|
-
if (!target.includes("@")) {
|
|
203
|
-
const want = bareLocalName(target);
|
|
204
|
-
return invites.find((inv) => inv.group_handle && bareLocalName(inv.group_handle) === want || inv.group_name === target);
|
|
205
|
-
}
|
|
206
|
-
const want = normalizeHandle(target.startsWith("#") ? target : `#${target}`);
|
|
207
|
-
return invites.find((inv) => inv.group_handle && normalizeHandle(inv.group_handle) === want);
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Resolve a group handle/UUID to its `GroupUuid` for `rine_group_join`. A bare
|
|
211
|
-
* UUID passes straight through (the open-enrollment discovery case); a handle
|
|
212
|
-
* is resolved against the caller's PENDING INVITES, since an invitee isn't a
|
|
213
|
-
* member yet and so can't appear in `groups.list()`.
|
|
214
|
-
*/
|
|
215
|
-
async function resolveGroupUuidForJoin(client, target) {
|
|
216
|
-
if (isUuid(target)) return asGroupUuid(target);
|
|
217
|
-
const match = findInvite(await client.groups.listInvites(), target);
|
|
218
|
-
if (!match) throw new NotFoundError(`No pending invite for group '${target}' — pass the group UUID directly for an open-enrollment group, or check rine_group_invites`);
|
|
219
|
-
return asGroupUuid(match.group_id);
|
|
220
|
-
}
|
|
221
|
-
/** `rine_group_create` — create an MLS-by-default coordination group. */
|
|
222
|
-
function rineGroupCreateTool(opts = {}) {
|
|
223
|
-
return defineTool({
|
|
224
|
-
description: "Create a new end-to-end-encrypted coordination group. By default the group uses MLS (RFC 9420) encryption with forward secrecy. This is a real, irreversible network action. Returns the new group handle, id, E2EE mode, and enrollment policy.",
|
|
225
|
-
inputSchema: jsonSchema(groupCreateInput),
|
|
226
|
-
outputSchema: STRING_OUTPUT,
|
|
227
|
-
needsApproval: approvalGate(opts),
|
|
228
|
-
execute: makeExecute(groupCreateInput, opts, async (client, i) => {
|
|
229
|
-
const g = await client.groups.create(i.name, {
|
|
230
|
-
description: i.description,
|
|
231
|
-
enrollment: i.enrollment,
|
|
232
|
-
visibility: i.visibility,
|
|
233
|
-
enableMls: i.enableMls
|
|
234
|
-
});
|
|
235
|
-
const mode = groupIsMls(g) ? "MLS" : "sender-key";
|
|
236
|
-
return `Created group ${g.handle} (id ${g.id}, ${mode} E2EE, enrollment ${g.enrollment_policy}).`;
|
|
237
|
-
})
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
/** `rine_group_invite` — invite an agent into a group (handle→UUID pre-resolved). */
|
|
241
|
-
function rineGroupInviteTool(opts = {}) {
|
|
242
|
-
return defineTool({
|
|
243
|
-
description: "Invite an agent into a group your agent administers (group and agent may be handles or UUIDs). This is a real, irreversible network action. Returns the invite status.",
|
|
244
|
-
inputSchema: jsonSchema(groupInviteInput),
|
|
245
|
-
outputSchema: STRING_OUTPUT,
|
|
246
|
-
needsApproval: approvalGate(opts),
|
|
247
|
-
execute: makeExecute(groupInviteInput, opts, async (client, i, apiUrl) => {
|
|
248
|
-
const groupId = await resolveGroupUuid(client, i.group);
|
|
249
|
-
const agentId = await resolveAgentUuid(apiUrl, i.agentToInvite);
|
|
250
|
-
const result = await client.groups.invite(groupId, agentId, { message: i.message });
|
|
251
|
-
return `Invited ${i.agentToInvite} to ${i.group} (status ${result.status}).`;
|
|
252
|
-
})
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
/** `rine_group_remove` — remove a member; group keys rotate (handle→UUID pre-resolved). */
|
|
256
|
-
function rineGroupRemoveTool(opts = {}) {
|
|
257
|
-
return defineTool({
|
|
258
|
-
description: "Remove a member from a group your agent administers (group and agent may be handles or UUIDs). Group keys are rotated for forward secrecy. This is a real, irreversible network action.",
|
|
259
|
-
inputSchema: jsonSchema(groupRemoveInput),
|
|
260
|
-
outputSchema: STRING_OUTPUT,
|
|
261
|
-
needsApproval: approvalGate(opts),
|
|
262
|
-
execute: makeExecute(groupRemoveInput, opts, async (client, i, apiUrl) => {
|
|
263
|
-
const groupId = await resolveGroupUuid(client, i.group);
|
|
264
|
-
const agentId = await resolveAgentUuid(apiUrl, i.agentId);
|
|
265
|
-
await client.groups.removeMember(groupId, agentId);
|
|
266
|
-
return `Removed ${i.agentId} from ${i.group}; keys rotated.`;
|
|
267
|
-
})
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
/** `rine_group_inspect` — report a group's E2EE mode + policy. */
|
|
271
|
-
function rineGroupInspectTool(opts = {}) {
|
|
272
|
-
return defineTool({
|
|
273
|
-
description: "Show a group's details and encryption status (MLS vs sender-key) so you can confirm your agent can read and post to it. Accepts a group handle or UUID.",
|
|
274
|
-
inputSchema: jsonSchema(groupInspectInput),
|
|
275
|
-
outputSchema: STRING_OUTPUT,
|
|
276
|
-
execute: makeExecute(groupInspectInput, opts, async (client, i) => {
|
|
277
|
-
const match = findGroup((await client.groups.list()).items, i.group);
|
|
278
|
-
if (!match) throw new NotFoundError(`No group '${i.group}' among the groups this agent belongs to`);
|
|
279
|
-
return renderGroup(match);
|
|
280
|
-
})
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
/** `rine_group_join` — accept an invite (or self-join an open group). */
|
|
284
|
-
function rineGroupJoinTool(opts = {}) {
|
|
285
|
-
return defineTool({
|
|
286
|
-
description: "Join a group: accept a pending invite, or self-join a publicly discovered open-enrollment group by UUID. Instant for open enrollment; for closed/majority/unanimity groups this submits a request that members vote on. This is a real, irreversible network action.",
|
|
287
|
-
inputSchema: jsonSchema(groupJoinInput),
|
|
288
|
-
outputSchema: STRING_OUTPUT,
|
|
289
|
-
needsApproval: approvalGate(opts),
|
|
290
|
-
execute: makeExecute(groupJoinInput, opts, async (client, i) => {
|
|
291
|
-
const groupId = await resolveGroupUuidForJoin(client, i.group);
|
|
292
|
-
const result = await client.groups.join(groupId, { message: i.message });
|
|
293
|
-
return renderJoinResult(i.group, result);
|
|
294
|
-
})
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
/** `rine_group_invites` — list the caller's pending group invites. */
|
|
298
|
-
function rineGroupInvitesTool(opts = {}) {
|
|
299
|
-
return defineTool({
|
|
300
|
-
description: "List your agent's pending group invites — group, who invited you, status, and any message. Join one with rine_group_join using the group handle or id.",
|
|
301
|
-
inputSchema: jsonSchema(groupInvitesInput),
|
|
302
|
-
outputSchema: STRING_OUTPUT,
|
|
303
|
-
execute: makeExecute(groupInvitesInput, opts, async (client) => {
|
|
304
|
-
return renderInvites(await client.groups.listInvites());
|
|
305
|
-
})
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
//#endregion
|
|
309
|
-
//#region src/tools/messaging.ts
|
|
310
|
-
/**
|
|
311
|
-
* The 5 messaging tool factories: `rine_send`, `rine_send_and_wait`,
|
|
312
|
-
* `rine_check_inbox`, `rine_read`, `rine_reply`. Each returns an Eve `defineTool`
|
|
313
|
-
* descriptor — one `AsyncRineClient` call rendered to a string, wrapped by
|
|
314
|
-
* `makeExecute` (lazy env client + formatError). The runtime tool NAME comes from
|
|
315
|
-
* the filename slug of the scaffolded `agent/tools/<name>.ts`, not from here.
|
|
316
|
-
*
|
|
317
|
-
* Renderers read only plaintext/decrypt_error/verification,
|
|
318
|
-
* never the ciphertext envelope. `read`/`check_inbox` add a `toModelOutput`
|
|
319
|
-
* redactor as defence-in-depth.
|
|
320
|
-
*/
|
|
321
|
-
/** `rine_send` — send a 1:1 or `#`-group message (the SDK auto-routes groups). */
|
|
322
|
-
function rineSendTool(opts = {}) {
|
|
323
|
-
return defineTool({
|
|
324
|
-
description: "Send an end-to-end-encrypted message to another agent (`name@org` / UUID) or, with a `#`-prefixed handle, to a whole group over its E2EE channel. This is a real, irreversible network action: the message is delivered to a live recipient. Returns the new message id and conversation id.",
|
|
325
|
-
inputSchema: jsonSchema(sendInput),
|
|
326
|
-
outputSchema: STRING_OUTPUT,
|
|
327
|
-
needsApproval: approvalGate(opts),
|
|
328
|
-
execute: makeExecute(sendInput, opts, async (client, i) => {
|
|
329
|
-
const msg = await client.send(asRecipient(i.to), { text: i.body }, {
|
|
330
|
-
type: i.messageType,
|
|
331
|
-
idempotencyKey: i.idempotencyKey
|
|
332
|
-
});
|
|
333
|
-
return `Sent message ${msg.id} to ${i.to} (conversation ${msg.conversation_id}).`;
|
|
334
|
-
})
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
/** `rine_send_and_wait` — 1:1 send that blocks for a reply (ms timeout). */
|
|
338
|
-
function rineSendAndWaitTool(opts = {}) {
|
|
339
|
-
return defineTool({
|
|
340
|
-
description: "Send an end-to-end-encrypted message to a single agent (`name@org` / UUID) and block up to `waitSeconds` for a reply, returning the decrypted reply if one arrives. 1:1 only — use rine_send for groups. This is a real, irreversible network action.",
|
|
341
|
-
inputSchema: jsonSchema(sendAndWaitInput),
|
|
342
|
-
outputSchema: STRING_OUTPUT,
|
|
343
|
-
needsApproval: approvalGate(opts),
|
|
344
|
-
execute: makeExecute(sendAndWaitInput, opts, async (client, i) => {
|
|
345
|
-
try {
|
|
346
|
-
const { sent, reply } = await client.sendAndWait(asRecipient(i.to), { text: i.body }, {
|
|
347
|
-
timeout: i.waitSeconds * 1e3,
|
|
348
|
-
type: i.messageType
|
|
349
|
-
});
|
|
350
|
-
if (!reply) return `Sent ${sent.id}; no reply within ${i.waitSeconds}s.`;
|
|
351
|
-
return `Reply: ${renderMessageBody(reply)} (${verifiedNote(reply)})`;
|
|
352
|
-
} catch (err) {
|
|
353
|
-
if (isGroupUnsupportedOnWait(err)) return GROUP_ON_WAIT_MESSAGE;
|
|
354
|
-
throw err;
|
|
355
|
-
}
|
|
356
|
-
})
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* `rine_check_inbox` — poll the newest new messages, decrypt them, then
|
|
361
|
-
* best-effort `markDelivered` the decryptable ids so a later check returns only
|
|
362
|
-
* newer mail. On ack failure: warn but still return the reads.
|
|
363
|
-
*/
|
|
364
|
-
function rineCheckInboxTool(opts = {}) {
|
|
365
|
-
return defineTool({
|
|
366
|
-
description: "Fetch and decrypt your newest unread messages (1:1 and group), then mark them delivered so a later check returns only newer mail. Returns a numbered list of decrypted messages, or 'No new messages.'.",
|
|
367
|
-
inputSchema: jsonSchema(checkInboxInput),
|
|
368
|
-
outputSchema: STRING_OUTPUT,
|
|
369
|
-
toModelOutput: redactToText,
|
|
370
|
-
execute: makeExecute(checkInboxInput, opts, async (client, i) => {
|
|
371
|
-
const items = (await client.inbox({
|
|
372
|
-
status: "new",
|
|
373
|
-
limit: i.limit
|
|
374
|
-
})).items;
|
|
375
|
-
const rendered = renderInbox(items);
|
|
376
|
-
const decryptableIds = items.filter((m) => !m.decrypt_error).map((m) => m.id);
|
|
377
|
-
if (decryptableIds.length === 0) return rendered;
|
|
378
|
-
try {
|
|
379
|
-
await client.markDelivered(decryptableIds);
|
|
380
|
-
return rendered;
|
|
381
|
-
} catch {
|
|
382
|
-
return `${rendered}\n[WARN] could not mark messages delivered; they may reappear on the next check.`;
|
|
383
|
-
}
|
|
384
|
-
})
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
/** `rine_read` — fetch + decrypt one message by id. */
|
|
388
|
-
function rineReadTool(opts = {}) {
|
|
389
|
-
return defineTool({
|
|
390
|
-
description: "Fetch and decrypt a single message by its UUID. Returns the sender, type, decrypted body, and signature status.",
|
|
391
|
-
inputSchema: jsonSchema(readInput),
|
|
392
|
-
outputSchema: STRING_OUTPUT,
|
|
393
|
-
toModelOutput: redactToText,
|
|
394
|
-
execute: makeExecute(readInput, opts, async (client, i) => {
|
|
395
|
-
return renderSingleMessage(await client.read(asMessageUuid(i.messageId)));
|
|
396
|
-
})
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
/** `rine_thread` — fetch the both-sided, decrypted transcript of a conversation. */
|
|
400
|
-
function rineThreadTool(opts = {}) {
|
|
401
|
-
return defineTool({
|
|
402
|
-
description: "Fetch the both-sided, decrypted transcript of a conversation by its UUID. Returns every turn (yours and the peer's) ordered oldest→newest, each role-tagged (`[sent] you:` / `[received] handle:`). A turn you cannot decrypt renders `[unavailable]`. Use to recover the full context of a conversation on demand.",
|
|
403
|
-
inputSchema: jsonSchema(threadInput),
|
|
404
|
-
outputSchema: STRING_OUTPUT,
|
|
405
|
-
toModelOutput: redactToText,
|
|
406
|
-
execute: makeExecute(threadInput, opts, async (client, i) => {
|
|
407
|
-
return renderThread(await client.thread(i.conversationId, { limit: i.limit }));
|
|
408
|
-
})
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
/** `rine_reply` — reply to a message, threading into the same conversation. */
|
|
412
|
-
function rineReplyTool(opts = {}) {
|
|
413
|
-
return defineTool({
|
|
414
|
-
description: "Send an end-to-end-encrypted reply to a message (by its UUID), threading into the same conversation. This is a real, irreversible network action. Returns the reply's message id.",
|
|
415
|
-
inputSchema: jsonSchema(replyInput),
|
|
416
|
-
outputSchema: STRING_OUTPUT,
|
|
417
|
-
needsApproval: approvalGate(opts),
|
|
418
|
-
execute: makeExecute(replyInput, opts, async (client, i) => {
|
|
419
|
-
const reply = await client.reply(asMessageUuid(i.messageId), { text: i.body }, { type: i.messageType });
|
|
420
|
-
return `Replied to ${i.messageId} -> ${reply.id}.`;
|
|
421
|
-
})
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
//#endregion
|
|
425
|
-
//#region src/tools/payments.ts
|
|
426
|
-
/**
|
|
427
|
-
* The 2 x402 payment tool factories: `rine_pay` (payer) and `rine_fulfill`
|
|
428
|
-
* (payee). Thin adapters over the ts-sdk `client.payments` facade — signing,
|
|
429
|
-
* spend policy, journal, and facilitator verify/settle all live in rine-core; the
|
|
430
|
-
* wallet key is never surfaced. Each returns an Eve `defineTool` descriptor whose
|
|
431
|
-
* `execute` resolves to a TYPED STATUS STRING (never a reject for an expected
|
|
432
|
-
* refusal), so the agent reasons over the outcome.
|
|
433
|
-
*
|
|
434
|
-
* `rine_pay` reuses the shipped `rine_pay` MCP status vocabulary VERBATIM:
|
|
435
|
-
* `payment-submitted` / `no-wallet` / `not-payment-required` / `policy-refused` /
|
|
436
|
-
* `above-auto-pay-threshold` / `already-paid` / `wallet-busy`. `rine_fulfill`
|
|
437
|
-
* reports the PINNED payee vocabulary (`settled` / `settlement-failed` /
|
|
438
|
-
* `verification-failed` / `facilitator-error` / `no-facilitator` / `not-payment`),
|
|
439
|
-
* identical across every surface (CLI/MCP/eve/mastra), with the facilitator's
|
|
440
|
-
* network slug stored VERBATIM (never CAIP-2 string-matched).
|
|
441
|
-
*/
|
|
442
|
-
/** The `rine_pay` terminal statuses, reused verbatim from the MCP payer tool. */
|
|
443
|
-
const PAY_STATUS = {
|
|
444
|
-
SUBMITTED: "payment-submitted",
|
|
445
|
-
NO_WALLET: "no-wallet",
|
|
446
|
-
NOT_PAYMENT_REQUIRED: "not-payment-required",
|
|
447
|
-
POLICY_REFUSED: "policy-refused",
|
|
448
|
-
ABOVE_AUTO_PAY_THRESHOLD: "above-auto-pay-threshold",
|
|
449
|
-
ALREADY_PAID: "already-paid",
|
|
450
|
-
WALLET_BUSY: "wallet-busy"
|
|
451
|
-
};
|
|
452
|
-
/**
|
|
453
|
-
* The `rine_fulfill` payee statuses — PINNED across every surface (CLI/MCP/eve/
|
|
454
|
-
* mastra) so an LLM or operator script parses one vocabulary everywhere. Mirrors
|
|
455
|
-
* the MCP `rine_fulfill` reference set; eve emits the subset it can reach (the
|
|
456
|
-
* ts-sdk `fulfill` facade owns decryption, so `no-keys` never surfaces here).
|
|
457
|
-
*/
|
|
458
|
-
const FULFILL_STATUS = {
|
|
459
|
-
SETTLED: "settled",
|
|
460
|
-
SETTLEMENT_FAILED: "settlement-failed",
|
|
461
|
-
VERIFICATION_FAILED: "verification-failed",
|
|
462
|
-
FACILITATOR_ERROR: "facilitator-error",
|
|
463
|
-
NO_FACILITATOR: "no-facilitator",
|
|
464
|
-
NOT_PAYMENT: "not-payment"
|
|
465
|
-
};
|
|
466
|
-
/** `<status> — <detail>`: the stable, parseable typed-status line. */
|
|
467
|
-
function status(word, detail) {
|
|
468
|
-
return `${word} — ${detail}`;
|
|
469
|
-
}
|
|
470
|
-
/** Atomic-unit amount of a requirement (x402 V2 `amount`, else V1 spelling). */
|
|
471
|
-
function requirementSummary(r) {
|
|
472
|
-
return `${r.amount ?? r.maxAmountRequired ?? "?"} of ${r.asset} on ${r.network} → ${r.payTo}`;
|
|
473
|
-
}
|
|
474
|
-
/** Map an x402 pay refusal to its typed status line (parity with MCP rine_pay). */
|
|
475
|
-
function mapPayError(err, autoPay) {
|
|
476
|
-
if (err instanceof X402Error) switch (err.code) {
|
|
477
|
-
case X402_ERROR.ALREADY_PAID: return status(PAY_STATUS.ALREADY_PAID, `${err.message}. Pass allowRepay to pay it again.`);
|
|
478
|
-
case X402_ERROR.WALLET_BUSY: return status(PAY_STATUS.WALLET_BUSY, err.message);
|
|
479
|
-
case X402_ERROR.PER_TX_CAP_EXCEEDED:
|
|
480
|
-
if (autoPay) return status(PAY_STATUS.ABOVE_AUTO_PAY_THRESHOLD, `${err.message}. Re-run without autoPay to authorize explicitly.`);
|
|
481
|
-
return status(PAY_STATUS.POLICY_REFUSED, err.message);
|
|
482
|
-
default: return status(PAY_STATUS.POLICY_REFUSED, err.message);
|
|
483
|
-
}
|
|
484
|
-
throw err;
|
|
485
|
-
}
|
|
486
|
-
/** `rine_pay` — pay a received x402 quote in-thread (payer). */
|
|
487
|
-
function rinePayTool(opts = {}) {
|
|
488
|
-
return defineTool({
|
|
489
|
-
description: "Pay a received x402 payment request (rine.v1.x402_payment_required) in-thread. Decrypts the quote, selects an acceptable requirement under your local spend policy (deny-by-default, caps), signs an EIP-3009 stablecoin authorization with your wallet, and sends the signed payment back in the same conversation. The spend is reserved as the last act before the send (fail-closed, permanent, no refund). Returns a typed `status` — `payment-submitted` on success, else `no-wallet` / `not-payment-required` / `policy-refused` / `above-auto-pay-threshold` / `already-paid` / `wallet-busy`. Does NOT wait for settlement; the receipt arrives later as an ordinary inbox message.",
|
|
490
|
-
inputSchema: jsonSchema(payInput),
|
|
491
|
-
outputSchema: STRING_OUTPUT,
|
|
492
|
-
needsApproval: approvalGate(opts),
|
|
493
|
-
execute: makeExecute(payInput, opts, async (client, i) => {
|
|
494
|
-
const msg = await client.read(asMessageUuid(i.messageId));
|
|
495
|
-
if (msg.type !== X402_MESSAGE_TYPE.PAYMENT_REQUIRED) return status(PAY_STATUS.NOT_PAYMENT_REQUIRED, `message ${i.messageId} is type '${msg.type}', not an x402 payment request.`);
|
|
496
|
-
try {
|
|
497
|
-
await client.payments.walletAddress();
|
|
498
|
-
} catch {
|
|
499
|
-
return status(PAY_STATUS.NO_WALLET, "no payment wallet is configured for this agent; create one before paying.");
|
|
500
|
-
}
|
|
501
|
-
try {
|
|
502
|
-
const res = await client.payments.pay(msg, {
|
|
503
|
-
autoPay: i.autoPay,
|
|
504
|
-
emitMarker: i.emitMarker,
|
|
505
|
-
allowRepay: i.allowRepay
|
|
506
|
-
});
|
|
507
|
-
return status(PAY_STATUS.SUBMITTED, `sent x402 payment ${res.payment.id} (${requirementSummary(res.requirement)}). The settlement receipt will arrive as a later inbox message.`);
|
|
508
|
-
} catch (err) {
|
|
509
|
-
return mapPayError(err, i.autoPay);
|
|
510
|
-
}
|
|
511
|
-
})
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Resolve the facilitator config from factory opts or `RINE_FACILITATOR`. A
|
|
516
|
-
* `null` return means none is configured (surfaced as `no-facilitator`). An
|
|
517
|
-
* unrecognised reference — neither a preset name nor an `http(s)://` base URL —
|
|
518
|
-
* throws an actionable config error instead of being handed to `fetch` as a
|
|
519
|
-
* bogus URL: parity with the CLI/MCP `resolveFacilitator`, so a typo like
|
|
520
|
-
* `payia` surfaces as a config error naming the bad value, not an opaque
|
|
521
|
-
* `facilitator-error` from a doomed network call.
|
|
522
|
-
*/
|
|
523
|
-
function resolveFacilitator(opts) {
|
|
524
|
-
const ref = opts.facilitator ?? process.env.RINE_FACILITATOR;
|
|
525
|
-
if (!ref) return null;
|
|
526
|
-
const headers = opts.facilitatorHeaders;
|
|
527
|
-
const preset = FACILITATOR_PRESET[ref];
|
|
528
|
-
if (preset) return headers ? {
|
|
529
|
-
...preset,
|
|
530
|
-
headers
|
|
531
|
-
} : preset;
|
|
532
|
-
if (!/^https?:\/\//.test(ref)) throw new Error(`Unknown facilitator '${ref}'. Use a preset (${Object.keys(FACILITATOR_PRESET).join(" | ")}) or an http(s):// base URL.`);
|
|
533
|
-
return headers ? {
|
|
534
|
-
url: ref,
|
|
535
|
-
headers
|
|
536
|
-
} : { url: ref };
|
|
537
|
-
}
|
|
538
|
-
/** Render a settle-first {@link FulfillResult} to a typed outcome line. */
|
|
539
|
-
function renderFulfill(res) {
|
|
540
|
-
if (!res.verification.isValid) return status(FULFILL_STATUS.VERIFICATION_FAILED, `verification failed (${res.verification.invalidReason ?? "verification_failed"}); a failure receipt was sent so the payer reaches a terminal state.`);
|
|
541
|
-
const s = res.settlement;
|
|
542
|
-
if (s?.success) return status(FULFILL_STATUS.SETTLED, `receipt sent; tx ${s.transaction} on ${s.network}${s.payer ? `, payer ${s.payer}` : ""}.`);
|
|
543
|
-
return status(FULFILL_STATUS.SETTLEMENT_FAILED, `settlement did not succeed (${s?.errorReason ?? "unknown"}); receipt sent.`);
|
|
544
|
-
}
|
|
545
|
-
/** `rine_fulfill` — verify + settle a received payment and send the receipt (payee). */
|
|
546
|
-
function rineFulfillTool(opts = {}) {
|
|
547
|
-
return defineTool({
|
|
548
|
-
description: "Fulfill a received x402 payment (rine.v1.x402_payment): verify the signed authorization and settle it on-chain via your configured facilitator, then send the settlement receipt back in-thread. Settle-first — on a failed verification, a `success:false` receipt is sent so the payer reaches a terminal state. Facilitator verify/settle is plain external HTTP, never a rine endpoint. Returns a typed `status` — `settled` on success, else `settlement-failed` / `verification-failed` / `facilitator-error` / `no-facilitator` / `not-payment`.",
|
|
549
|
-
inputSchema: jsonSchema(fulfillInput),
|
|
550
|
-
outputSchema: STRING_OUTPUT,
|
|
551
|
-
needsApproval: approvalGate(opts),
|
|
552
|
-
execute: makeExecute(fulfillInput, opts, async (client, i) => {
|
|
553
|
-
const msg = await client.read(asMessageUuid(i.messageId));
|
|
554
|
-
if (msg.type !== X402_MESSAGE_TYPE.PAYMENT) return status(FULFILL_STATUS.NOT_PAYMENT, `message ${i.messageId} is type '${msg.type}', not an x402 payment authorization.`);
|
|
555
|
-
const facilitator = resolveFacilitator(opts);
|
|
556
|
-
if (!facilitator) return status(FULFILL_STATUS.NO_FACILITATOR, "no facilitator is configured; set RINE_FACILITATOR (a preset name — cdp/payai/x402-rs — or a base URL) to verify and settle payments.");
|
|
557
|
-
try {
|
|
558
|
-
return renderFulfill(await client.payments.fulfill(msg, {
|
|
559
|
-
facilitator,
|
|
560
|
-
emitMarker: i.emitMarker
|
|
561
|
-
}));
|
|
562
|
-
} catch (err) {
|
|
563
|
-
if (err instanceof X402FacilitatorError) return status(FULFILL_STATUS.FACILITATOR_ERROR, err.message);
|
|
564
|
-
throw err;
|
|
565
|
-
}
|
|
566
|
-
})
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
//#endregion
|
|
570
|
-
//#region src/tools/index.ts
|
|
571
|
-
const FACTORIES = {
|
|
572
|
-
rineSendTool,
|
|
573
|
-
rineSendAndWaitTool,
|
|
574
|
-
rineCheckInboxTool,
|
|
575
|
-
rineReadTool,
|
|
576
|
-
rineReplyTool,
|
|
577
|
-
rineThreadTool,
|
|
578
|
-
rineDiscoverTool,
|
|
579
|
-
rineInspectTool,
|
|
580
|
-
rineGroupCreateTool,
|
|
581
|
-
rineGroupInviteTool,
|
|
582
|
-
rineGroupRemoveTool,
|
|
583
|
-
rineGroupInspectTool,
|
|
584
|
-
rineGroupJoinTool,
|
|
585
|
-
rineGroupInvitesTool,
|
|
586
|
-
rinePayTool,
|
|
587
|
-
rineFulfillTool
|
|
588
|
-
};
|
|
589
|
-
/** The metadata registry with live factories attached (programmatic use). */
|
|
590
|
-
const RINE_TOOLS = RINE_TOOL_META.map((m) => ({
|
|
591
|
-
...m,
|
|
592
|
-
factory: FACTORIES[m.factoryName]
|
|
593
|
-
}));
|
|
594
|
-
//#endregion
|
|
595
|
-
export { rineInspectTool as _, rineReadTool as a, rineSendTool as c, rineGroupInspectTool as d, rineGroupInviteTool as f, rineDiscoverTool as g, rineGroupRemoveTool as h, rineCheckInboxTool as i, rineThreadTool as l, rineGroupJoinTool as m, rineFulfillTool as n, rineReplyTool as o, rineGroupInvitesTool as p, rinePayTool as r, rineSendAndWaitTool as s, RINE_TOOLS as t, rineGroupCreateTool as u };
|