bereach-openclaw 0.2.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.
@@ -0,0 +1,567 @@
1
+ /**
2
+ * Tool definitions generated from the BeReach OpenAPI spec.
3
+ *
4
+ * Source of truth: apps/web2/apps/web/src/lib/openapi/schemas/linkedin.ts
5
+ * apps/web2/apps/web/src/lib/openapi/schemas/campaigns.ts
6
+ *
7
+ * Each definition maps 1:1 to an OpenAPI endpoint and an SDK method.
8
+ * Deprecated fields (actionSlug) are excluded.
9
+ */
10
+
11
+ export interface ToolDefinition {
12
+ name: string;
13
+ description: string;
14
+ parameters: Record<string, unknown>;
15
+ handler: string;
16
+ }
17
+
18
+ export const definitions: ToolDefinition[] = [
19
+ // ── LinkedIn Scrapers ──────────────────────────────────────────────
20
+
21
+ {
22
+ name: "bereach_collect_likes",
23
+ description: "Scrape LinkedIn post likes. Returns paginated list of profiles who liked a post.",
24
+ handler: "linkedinScrapers.collectLikes",
25
+ parameters: {
26
+ type: "object",
27
+ required: ["postUrl"],
28
+ properties: {
29
+ postUrl: { type: "string", description: "LinkedIn post URL to inspect for reactions." },
30
+ start: { type: "integer", minimum: 0, description: "Pagination offset (multiples of 200)." },
31
+ count: { type: "integer", minimum: 0, maximum: 200, description: "Number of likes to fetch per page (0-200, default 200). Use count=0 for a free total-only check." },
32
+ },
33
+ },
34
+ },
35
+
36
+ {
37
+ name: "bereach_collect_comments",
38
+ description: "Scrape LinkedIn post comments. Returns paginated list of commenters with comment text and URNs.",
39
+ handler: "linkedinScrapers.collectComments",
40
+ parameters: {
41
+ type: "object",
42
+ required: ["postUrl"],
43
+ properties: {
44
+ postUrl: { type: "string", description: "LinkedIn post URL to inspect for comments." },
45
+ start: { type: "integer", minimum: 0, description: "Pagination offset (multiples of 100)." },
46
+ count: { type: "integer", minimum: 0, maximum: 100, description: "Number of comments to fetch per page (0-100, default 100). Use count=0 for a free total-only check." },
47
+ campaignSlug: { type: "string", description: "When provided, each profile includes actionsCompleted and knownDistance for campaign-aware scraping." },
48
+ },
49
+ },
50
+ },
51
+
52
+ {
53
+ name: "bereach_collect_comment_replies",
54
+ description: "Scrape replies to a LinkedIn comment. Returns paginated replies for a specific comment URN.",
55
+ handler: "linkedinScrapers.collectCommentReplies",
56
+ parameters: {
57
+ type: "object",
58
+ required: ["commentUrn"],
59
+ properties: {
60
+ commentUrn: { type: "string", description: "Comment URN returned by the comments endpoint (e.g., 'urn:li:comment:(activity:123456,789)')." },
61
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
62
+ count: { type: "integer", minimum: 0, maximum: 100, description: "Number of replies to fetch per page (0-100, default 100). Use count=0 for a free total-only check." },
63
+ },
64
+ },
65
+ },
66
+
67
+ {
68
+ name: "bereach_collect_posts",
69
+ description: "Scrape LinkedIn profile posts. Returns paginated list of posts from a profile.",
70
+ handler: "linkedinScrapers.collectPosts",
71
+ parameters: {
72
+ type: "object",
73
+ required: ["profileUrl"],
74
+ properties: {
75
+ profileUrl: { type: "string", description: "LinkedIn profile URL to fetch posts from." },
76
+ count: { type: "integer", minimum: 0, maximum: 100, description: "Number of posts to fetch (0-100, default 20). Use count=0 for a free total-only check." },
77
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
78
+ paginationToken: { type: "string", description: "Pagination token from a previous response to fetch the next page." },
79
+ },
80
+ },
81
+ },
82
+
83
+ {
84
+ name: "bereach_visit_profile",
85
+ description: "Visit LinkedIn profile and extract contact data. Distance-1 profiles cached 24h. No dedup — always executes.",
86
+ handler: "linkedinScrapers.visitProfile",
87
+ parameters: {
88
+ type: "object",
89
+ required: ["profile"],
90
+ properties: {
91
+ profile: { type: "string", description: "LinkedIn profile URL or profile URN." },
92
+ campaignSlug: { type: "string", description: "Optional campaign identifier for tracking only. No dedup — visit always executes." },
93
+ includePosts: { type: "boolean", description: "When true, fetches the last 5 posts from the profile. Defaults to false." },
94
+ },
95
+ },
96
+ },
97
+
98
+ {
99
+ name: "bereach_visit_company",
100
+ description: "Visit LinkedIn company page and extract profile data including description, industry, employee count, headquarters, and more.",
101
+ handler: "linkedinScrapers.visitCompany",
102
+ parameters: {
103
+ type: "object",
104
+ required: ["companyUrl"],
105
+ properties: {
106
+ companyUrl: { type: "string", description: "LinkedIn company URL (e.g., 'https://www.linkedin.com/company/openai') or universal name (e.g., 'openai')." },
107
+ includeWorkplacePolicy: { type: "boolean", description: "Include workplace policy data such as hybrid/remote status and benefits. Costs 1 extra credit." },
108
+ },
109
+ },
110
+ },
111
+
112
+ // ── LinkedIn Search ────────────────────────────────────────────────
113
+
114
+ {
115
+ name: "bereach_unified_search",
116
+ description: "Unified LinkedIn Search — search posts, people, companies, or jobs with a single endpoint. Supports all filter types via category selection.",
117
+ handler: "linkedinSearch.unifiedSearch",
118
+ parameters: {
119
+ type: "object",
120
+ properties: {
121
+ category: { type: "string", enum: ["posts", "people", "companies", "jobs"], description: "Type of search to perform (required unless url is provided)." },
122
+ url: { type: "string", description: "LinkedIn search URL — category and filters are extracted automatically." },
123
+ keywords: { type: "string", description: "Search keywords. Supports LinkedIn Boolean syntax." },
124
+ sortBy: { type: "string", enum: ["relevance", "date"], description: "Sort order (posts & jobs)." },
125
+ datePosted: { type: "string", enum: ["past-24h", "past-week", "past-month"], description: "Time filter (posts & jobs)." },
126
+ contentType: { type: "string", enum: ["images", "videos", "documents"], description: "Media type filter (posts only)." },
127
+ authorIndustry: { type: "array", items: { type: "string" }, description: "Author industry IDs (posts only, resolve via /search/parameters)." },
128
+ authorCompany: { type: "array", items: { type: "string" }, description: "Author company IDs (posts only, resolve via /search/parameters)." },
129
+ connectionDegree: { type: "array", items: { type: "string", enum: ["F", "S", "O"] }, description: "Connection degree: F=1st, S=2nd, O=3rd+ (people only)." },
130
+ firstName: { type: "string", description: "First name filter (people only)." },
131
+ lastName: { type: "string", description: "Last name filter (people only)." },
132
+ title: { type: "string", description: "Job title filter, supports OR syntax (people only)." },
133
+ connectionOf: { type: "string", description: "Profile URN to find connections of (people only)." },
134
+ profileLanguage: { type: "array", items: { type: "string" }, description: "Profile language codes e.g. ['en','fr'] (people only)." },
135
+ school: { type: "array", items: { type: "string" }, description: "School IDs (people only, resolve via /search/parameters)." },
136
+ location: { type: "array", items: { type: "string" }, description: "Geo IDs (people, companies, jobs — resolve via /search/parameters)." },
137
+ industry: { type: "array", items: { type: "string" }, description: "Industry IDs (people, companies — resolve via /search/parameters)." },
138
+ currentCompany: { type: "array", items: { type: "string" }, description: "Current company IDs (people only, resolve via /search/parameters)." },
139
+ pastCompany: { type: "array", items: { type: "string" }, description: "Past company IDs (people only, resolve via /search/parameters)." },
140
+ companySize: { type: "array", items: { type: "string", enum: ["A", "B", "C", "D", "E", "F", "G", "H", "I"] }, description: "Company size: A=1-10, B=11-50, C=51-200, D=201-500, E=501-1K, F=1K-5K, G=5K-10K, H=10K+, I=self (companies only)." },
141
+ jobType: { type: "array", items: { type: "string", enum: ["F", "P", "C", "T", "I", "V", "O"] }, description: "Job type: F=Full-time, P=Part-time, C=Contract, T=Temporary, I=Internship, V=Volunteer, O=Other (jobs only)." },
142
+ experienceLevel: { type: "array", items: { type: "string", enum: ["1", "2", "3", "4", "5", "6"] }, description: "Experience level: 1=Internship, 2=Entry, 3=Associate, 4=Mid-Senior, 5=Director, 6=Executive (jobs only)." },
143
+ workplaceType: { type: "array", items: { type: "string", enum: ["1", "2", "3"] }, description: "Workplace type: 1=On-site, 2=Remote, 3=Hybrid (jobs only)." },
144
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
145
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Results per page (default 10, max 50)." },
146
+ },
147
+ },
148
+ },
149
+
150
+ {
151
+ name: "bereach_search_posts",
152
+ description: "Search LinkedIn posts by keywords with optional filters for date, content type, author industry, and author company.",
153
+ handler: "linkedinSearch.searchPosts",
154
+ parameters: {
155
+ type: "object",
156
+ required: ["keywords"],
157
+ properties: {
158
+ keywords: { type: "string", description: "Search keywords (required). Supports LinkedIn Boolean syntax." },
159
+ url: { type: "string", description: "Optional LinkedIn search URL. Explicit params override URL-derived values." },
160
+ sortBy: { type: "string", enum: ["relevance", "date"], description: "Sort order." },
161
+ datePosted: { type: "string", enum: ["past-24h", "past-week", "past-month"], description: "Filter by publication date." },
162
+ contentType: { type: "string", enum: ["images", "videos", "documents"], description: "Filter by media type." },
163
+ authorIndustry: { type: "array", items: { type: "string" }, description: "Author industry IDs (resolve via bereach_resolve_parameters)." },
164
+ authorCompany: { type: "array", items: { type: "string" }, description: "Author company IDs (resolve via bereach_resolve_parameters)." },
165
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
166
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Results per page (default 10, max 50)." },
167
+ },
168
+ },
169
+ },
170
+
171
+ {
172
+ name: "bereach_search_people",
173
+ description: "Search LinkedIn people by keywords, connection degree, name, title, location, industry, company, and school.",
174
+ handler: "linkedinSearch.searchPeople",
175
+ parameters: {
176
+ type: "object",
177
+ properties: {
178
+ keywords: { type: "string", description: "Search keywords. Matches against name, headline, company, skills, and bio." },
179
+ url: { type: "string", description: "Optional LinkedIn search URL." },
180
+ connectionDegree: { type: "array", items: { type: "string", enum: ["F", "S", "O"] }, description: "Connection degree: F=1st, S=2nd, O=3rd+." },
181
+ firstName: { type: "string", description: "Filter by first name (case-insensitive)." },
182
+ lastName: { type: "string", description: "Filter by last name (case-insensitive)." },
183
+ title: { type: "string", description: "Filter by job title. Supports OR syntax with '|' separator." },
184
+ connectionOf: { type: "string", description: "Profile URN to find connections of." },
185
+ profileLanguage: { type: "array", items: { type: "string" }, description: "Profile language codes (ISO 639-1)." },
186
+ school: { type: "array", items: { type: "string" }, description: "School IDs (resolve via bereach_resolve_parameters)." },
187
+ location: { type: "array", items: { type: "string" }, description: "Geo IDs (resolve via bereach_resolve_parameters)." },
188
+ industry: { type: "array", items: { type: "string" }, description: "Industry IDs (resolve via bereach_resolve_parameters)." },
189
+ currentCompany: { type: "array", items: { type: "string" }, description: "Current company IDs (resolve via bereach_resolve_parameters)." },
190
+ pastCompany: { type: "array", items: { type: "string" }, description: "Past company IDs (resolve via bereach_resolve_parameters)." },
191
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
192
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Results per page (default 10, max 50)." },
193
+ },
194
+ },
195
+ },
196
+
197
+ {
198
+ name: "bereach_search_companies",
199
+ description: "Search LinkedIn companies by keywords, location, industry, and company size.",
200
+ handler: "linkedinSearch.searchCompanies",
201
+ parameters: {
202
+ type: "object",
203
+ properties: {
204
+ keywords: { type: "string", description: "Search keywords. Matches against company name, description, and specialties." },
205
+ url: { type: "string", description: "Optional LinkedIn search URL." },
206
+ location: { type: "array", items: { type: "string" }, description: "Geo IDs (resolve via bereach_resolve_parameters)." },
207
+ industry: { type: "array", items: { type: "string" }, description: "Industry IDs (resolve via bereach_resolve_parameters)." },
208
+ companySize: { type: "array", items: { type: "string", enum: ["A", "B", "C", "D", "E", "F", "G", "H", "I"] }, description: "Employee count: A=1-10, B=11-50, C=51-200, D=201-500, E=501-1K, F=1K-5K, G=5K-10K, H=10K+, I=self." },
209
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
210
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Results per page (default 10, max 50)." },
211
+ },
212
+ },
213
+ },
214
+
215
+ {
216
+ name: "bereach_search_jobs",
217
+ description: "Search LinkedIn jobs by keywords, location, job type, experience level, and workplace type.",
218
+ handler: "linkedinSearch.searchJobs",
219
+ parameters: {
220
+ type: "object",
221
+ properties: {
222
+ keywords: { type: "string", description: "Search keywords. Matches against job title, company name, and description." },
223
+ url: { type: "string", description: "Optional LinkedIn search URL." },
224
+ location: { type: "array", items: { type: "string" }, description: "Geo IDs (resolve via bereach_resolve_parameters)." },
225
+ datePosted: { type: "string", enum: ["past-24h", "past-week", "past-month"], description: "Filter by posting date." },
226
+ sortBy: { type: "string", enum: ["relevance", "date"], description: "Sort order." },
227
+ jobType: { type: "array", items: { type: "string", enum: ["F", "P", "C", "T", "I", "V", "O"] }, description: "Employment type: F=Full-time, P=Part-time, C=Contract, T=Temporary, I=Internship, V=Volunteer, O=Other." },
228
+ experienceLevel: { type: "array", items: { type: "string", enum: ["1", "2", "3", "4", "5", "6"] }, description: "Seniority: 1=Internship, 2=Entry, 3=Associate, 4=Mid-Senior, 5=Director, 6=Executive." },
229
+ workplaceType: { type: "array", items: { type: "string", enum: ["1", "2", "3"] }, description: "Workplace: 1=On-site, 2=Remote, 3=Hybrid." },
230
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
231
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Results per page (default 10, max 50)." },
232
+ },
233
+ },
234
+ },
235
+
236
+ {
237
+ name: "bereach_search_by_url",
238
+ description: "Search LinkedIn by URL. Automatically extracts category, keywords, and filters from a LinkedIn search URL.",
239
+ handler: "linkedinSearch.searchByUrl",
240
+ parameters: {
241
+ type: "object",
242
+ required: ["url"],
243
+ properties: {
244
+ url: { type: "string", description: "A LinkedIn search URL. Category and filters are extracted automatically." },
245
+ start: { type: "integer", minimum: 0, description: "Override pagination offset." },
246
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Override results per page (default 10, max 50)." },
247
+ },
248
+ },
249
+ },
250
+
251
+ {
252
+ name: "bereach_resolve_parameters",
253
+ description: "Resolve text to LinkedIn search parameter IDs (typeahead). Prerequisite for using location, industry, company, or school filters.",
254
+ handler: "linkedinSearch.resolveParameters",
255
+ parameters: {
256
+ type: "object",
257
+ required: ["type", "keywords"],
258
+ properties: {
259
+ type: { type: "string", enum: ["GEO", "COMPANY", "INDUSTRY", "SCHOOL", "CONNECTIONS", "PEOPLE"], description: "Parameter type to resolve." },
260
+ keywords: { type: "string", description: "Text to resolve into LinkedIn IDs." },
261
+ limit: { type: "integer", minimum: 1, maximum: 50, description: "Max results (default 10, max 50)." },
262
+ },
263
+ },
264
+ },
265
+
266
+ // ── LinkedIn Actions ───────────────────────────────────────────────
267
+
268
+ {
269
+ name: "bereach_connect_profile",
270
+ description: "Send LinkedIn connection request. Deduplicates by profile within a campaign.",
271
+ handler: "linkedinActions.connectProfile",
272
+ parameters: {
273
+ type: "object",
274
+ required: ["profile"],
275
+ properties: {
276
+ profile: { type: "string", description: "LinkedIn profile URL or profile URN." },
277
+ campaignSlug: { type: "string", description: "Campaign identifier for deduplication." },
278
+ },
279
+ },
280
+ },
281
+
282
+ {
283
+ name: "bereach_list_invitations",
284
+ description: "List received LinkedIn connection invitations. Returns pending invitations with IDs needed to accept them.",
285
+ handler: "linkedinActions.listInvitations",
286
+ parameters: {
287
+ type: "object",
288
+ properties: {
289
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
290
+ count: { type: "integer", minimum: 1, maximum: 100, description: "Number of invitations to return (default 10, max 100)." },
291
+ },
292
+ },
293
+ },
294
+
295
+ {
296
+ name: "bereach_accept_invitation",
297
+ description: "Accept a LinkedIn connection invitation. Requires invitationId and sharedSecret from the list invitations endpoint.",
298
+ handler: "linkedinActions.acceptInvitation",
299
+ parameters: {
300
+ type: "object",
301
+ required: ["invitationId", "sharedSecret"],
302
+ properties: {
303
+ invitationId: { type: "string", description: "Invitation ID (from the list invitations endpoint)." },
304
+ sharedSecret: { type: "string", description: "Shared secret / validation token (from the list invitations endpoint)." },
305
+ senderProfileId: { type: "string", description: "Sender's profile ID. Recommended for reliability." },
306
+ firstName: { type: "string", description: "Sender's first name. Recommended for reliability." },
307
+ lastName: { type: "string", description: "Sender's last name. Recommended for reliability." },
308
+ },
309
+ },
310
+ },
311
+
312
+ {
313
+ name: "bereach_send_message",
314
+ description: "Send LinkedIn message. Rate limited to 80 messages per day.",
315
+ handler: "linkedinActions.sendMessage",
316
+ parameters: {
317
+ type: "object",
318
+ required: ["profile", "message"],
319
+ properties: {
320
+ profile: { type: "string", description: "LinkedIn profile URL or profile URN." },
321
+ message: { type: "string", description: "Message content to send." },
322
+ campaignSlug: { type: "string", description: "Campaign identifier for deduplication." },
323
+ },
324
+ },
325
+ },
326
+
327
+ {
328
+ name: "bereach_reply_to_comment",
329
+ description: "Reply to a LinkedIn comment. Use the commentUrn from the comments endpoint directly.",
330
+ handler: "linkedinActions.replyToComment",
331
+ parameters: {
332
+ type: "object",
333
+ required: ["commentUrn", "message"],
334
+ properties: {
335
+ commentUrn: { type: "string", description: "LinkedIn comment URN (e.g., 'urn:li:comment:(activity:123,456)')." },
336
+ message: { type: "string", description: "Reply message text." },
337
+ campaignSlug: { type: "string", description: "Campaign identifier for deduplication." },
338
+ },
339
+ },
340
+ },
341
+
342
+ {
343
+ name: "bereach_like_comment",
344
+ description: "Like (react to) a LinkedIn comment. Use the commentUrn from the comments endpoint directly.",
345
+ handler: "linkedinActions.likeComment",
346
+ parameters: {
347
+ type: "object",
348
+ required: ["commentUrn"],
349
+ properties: {
350
+ commentUrn: { type: "string", description: "LinkedIn comment URN." },
351
+ reactionType: { type: "string", enum: ["LIKE", "LOVE", "CELEBRATE", "SUPPORT", "FUNNY", "INSIGHTFUL"], description: "Reaction type (default: LIKE)." },
352
+ campaignSlug: { type: "string", description: "Campaign identifier for deduplication." },
353
+ },
354
+ },
355
+ },
356
+
357
+ {
358
+ name: "bereach_publish_post",
359
+ description: "Publish or schedule a LinkedIn post. Supports text, images, mentions, and visibility control.",
360
+ handler: "linkedinActions.publishPost",
361
+ parameters: {
362
+ type: "object",
363
+ required: ["text", "mode"],
364
+ properties: {
365
+ text: { type: "string", description: "Post commentary text." },
366
+ mode: { type: "string", enum: ["scheduled", "instant"], description: "Publish mode: 'instant' publishes immediately, 'scheduled' schedules for later." },
367
+ scheduledAt: { type: "integer", description: "Timestamp in milliseconds for scheduled posts (required when mode='scheduled')." },
368
+ imageUrl: { type: "string", description: "URL of an image to attach to the post." },
369
+ visibility: { type: "string", enum: ["ANYONE", "CONNECTIONS"], description: "Post visibility (default: ANYONE)." },
370
+ mentions: {
371
+ type: "array",
372
+ items: {
373
+ type: "object",
374
+ required: ["profileUrn", "start", "length"],
375
+ properties: {
376
+ profileUrn: { type: "string", description: "LinkedIn profile URN of the mentioned person." },
377
+ start: { type: "integer", description: "Start character offset where the mention begins." },
378
+ length: { type: "integer", description: "Length of the mention text in characters." },
379
+ },
380
+ },
381
+ description: "Profile mentions with text positions.",
382
+ },
383
+ campaignSlug: { type: "string", description: "Campaign identifier for deduplication." },
384
+ },
385
+ },
386
+ },
387
+
388
+ // ── LinkedIn Chat ──────────────────────────────────────────────────
389
+
390
+ {
391
+ name: "bereach_list_conversations",
392
+ description: "List LinkedIn inbox conversations with participants, last message, and read status.",
393
+ handler: "linkedinChat.listConversations",
394
+ parameters: {
395
+ type: "object",
396
+ properties: {
397
+ nextCursor: { type: "string", description: "Pagination cursor from a previous response." },
398
+ },
399
+ },
400
+ },
401
+
402
+ {
403
+ name: "bereach_search_conversations",
404
+ description: "Search LinkedIn inbox conversations by keyword. 0 credits.",
405
+ handler: "linkedinChat.searchConversations",
406
+ parameters: {
407
+ type: "object",
408
+ required: ["keywords"],
409
+ properties: {
410
+ keywords: { type: "string", description: "Search keywords." },
411
+ nextCursor: { type: "string", description: "Pagination cursor from a previous response." },
412
+ },
413
+ },
414
+ },
415
+
416
+ {
417
+ name: "bereach_find_conversation",
418
+ description: "Find a conversation with a specific person. Direct O(1) lookup via LinkedIn's compose API. 0 credits.",
419
+ handler: "linkedinChat.findConversation",
420
+ parameters: {
421
+ type: "object",
422
+ required: ["profile"],
423
+ properties: {
424
+ profile: { type: "string", description: "Profile URL or URN for direct conversation lookup." },
425
+ includeMessages: { type: "boolean", description: "If true, also return the conversation's recent messages (0 extra credits). Default: false." },
426
+ },
427
+ },
428
+ },
429
+
430
+ {
431
+ name: "bereach_get_messages",
432
+ description: "Read messages from a LinkedIn conversation. 0 credits.",
433
+ handler: "linkedinChat.getMessages",
434
+ parameters: {
435
+ type: "object",
436
+ required: ["conversationUrn"],
437
+ properties: {
438
+ conversationUrn: { type: "string", description: "Full conversation URN as returned by list/search conversations." },
439
+ deliveredAt: { type: "integer", description: "Timestamp (ms) of the oldest message from previous page — pass this to load older messages." },
440
+ },
441
+ },
442
+ },
443
+
444
+ // ── Profile ────────────────────────────────────────────────────────
445
+
446
+ {
447
+ name: "bereach_get_profile",
448
+ description: "Get authenticated user's LinkedIn profile from the database. No LinkedIn API call, 0 credits.",
449
+ handler: "profile.getLinkedInProfile",
450
+ parameters: { type: "object", properties: {} },
451
+ },
452
+
453
+ {
454
+ name: "bereach_refresh_profile",
455
+ description: "Refresh authenticated user's LinkedIn profile by fetching latest data from LinkedIn.",
456
+ handler: "profile.refresh",
457
+ parameters: { type: "object", properties: {} },
458
+ },
459
+
460
+ {
461
+ name: "bereach_get_own_posts",
462
+ description: "Get authenticated user's LinkedIn posts.",
463
+ handler: "profile.getPosts",
464
+ parameters: {
465
+ type: "object",
466
+ properties: {
467
+ count: { type: "integer", minimum: 1, maximum: 100, description: "Number of posts to fetch (default 20, max 100)." },
468
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
469
+ paginationToken: { type: "string", description: "Pagination token from a previous response." },
470
+ },
471
+ },
472
+ },
473
+
474
+ {
475
+ name: "bereach_get_followers",
476
+ description: "Get authenticated user's LinkedIn followers.",
477
+ handler: "profile.getFollowers",
478
+ parameters: {
479
+ type: "object",
480
+ properties: {
481
+ start: { type: "integer", minimum: 0, description: "Pagination offset (default 0)." },
482
+ count: { type: "integer", minimum: 1, maximum: 50, description: "Number of followers to fetch per page (default 10, max 50)." },
483
+ },
484
+ },
485
+ },
486
+
487
+ {
488
+ name: "bereach_get_limits",
489
+ description: "Get current LinkedIn rate limit status for all action types. 0 credits.",
490
+ handler: "profile.getLimits",
491
+ parameters: { type: "object", properties: {} },
492
+ },
493
+
494
+ {
495
+ name: "bereach_get_credits",
496
+ description: "Get current BeReach credit balance including used, remaining, and percentage. 0 credits.",
497
+ handler: "profile.getCredits",
498
+ parameters: { type: "object", properties: {} },
499
+ },
500
+
501
+ // ── Campaigns ──────────────────────────────────────────────────────
502
+
503
+ {
504
+ name: "bereach_campaign_status",
505
+ description: "Query per-profile action status within a campaign. Returns which actions have been completed for each profile. 0 credits.",
506
+ handler: "campaigns.getStatus",
507
+ parameters: {
508
+ type: "object",
509
+ required: ["campaignSlug", "profiles"],
510
+ properties: {
511
+ campaignSlug: { type: "string", pattern: "^[a-zA-Z0-9_-]+$", description: "Campaign identifier." },
512
+ profiles: {
513
+ type: "array",
514
+ items: { type: "string" },
515
+ minItems: 1,
516
+ maxItems: 500,
517
+ description: "LinkedIn profile URLs or URNs to check status for.",
518
+ },
519
+ },
520
+ },
521
+ },
522
+
523
+ {
524
+ name: "bereach_campaign_sync",
525
+ description: "Mark actions as completed without performing them on LinkedIn. Use when actions were performed outside the API. 0 credits.",
526
+ handler: "campaigns.syncActions",
527
+ parameters: {
528
+ type: "object",
529
+ required: ["campaignSlug", "profiles"],
530
+ properties: {
531
+ campaignSlug: { type: "string", pattern: "^[a-zA-Z0-9_-]+$", description: "Campaign identifier." },
532
+ profiles: {
533
+ type: "array",
534
+ items: {
535
+ type: "object",
536
+ required: ["profile", "actions"],
537
+ properties: {
538
+ profile: { type: "string", description: "LinkedIn profile URL or URN." },
539
+ actions: {
540
+ type: "array",
541
+ items: { type: "string", enum: ["message", "reply", "like", "visit", "connect"] },
542
+ minItems: 1,
543
+ description: "Action types to mark as completed.",
544
+ },
545
+ },
546
+ },
547
+ minItems: 1,
548
+ maxItems: 500,
549
+ description: "Profiles and actions to mark as completed.",
550
+ },
551
+ },
552
+ },
553
+ },
554
+
555
+ {
556
+ name: "bereach_campaign_stats",
557
+ description: "Get aggregate campaign statistics: per-action counts, unique profiles, and total credits used. 0 credits.",
558
+ handler: "campaigns.getStats",
559
+ parameters: {
560
+ type: "object",
561
+ required: ["campaignSlug"],
562
+ properties: {
563
+ campaignSlug: { type: "string", pattern: "^[a-zA-Z0-9_-]+$", description: "Campaign identifier." },
564
+ },
565
+ },
566
+ },
567
+ ];
@@ -0,0 +1,23 @@
1
+ import { definitions } from "./definitions";
2
+ import type { Bereach } from "bereach";
3
+
4
+ /**
5
+ * Registers all 33 BeReach tools with the OpenClaw agent.
6
+ * Each tool delegates to the corresponding SDK method via dot-path resolution.
7
+ */
8
+ export function registerAllTools(api: any, client: Bereach) {
9
+ for (const def of definitions) {
10
+ api.registerTool(
11
+ def.name,
12
+ {
13
+ description: def.description,
14
+ parameters: def.parameters,
15
+ },
16
+ async (params: Record<string, unknown>) => {
17
+ const [resource, method] = def.handler.split(".");
18
+ const result = await (client as any)[resource][method](params);
19
+ return result;
20
+ },
21
+ );
22
+ }
23
+ }
@@ -0,0 +1,15 @@
1
+ declare module "bereach" {
2
+ interface BereachOptions {
3
+ token: string;
4
+ }
5
+
6
+ export class Bereach {
7
+ constructor(options: BereachOptions);
8
+ linkedinScrapers: Record<string, (params: any) => Promise<any>>;
9
+ linkedinActions: Record<string, (params: any) => Promise<any>>;
10
+ linkedinChat: Record<string, (params: any) => Promise<any>>;
11
+ linkedinSearch: Record<string, (params: any) => Promise<any>>;
12
+ profile: Record<string, (params?: any) => Promise<any>>;
13
+ campaigns: Record<string, (params: any) => Promise<any>>;
14
+ }
15
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": true
12
+ },
13
+ "include": ["src/**/*.ts"],
14
+ "exclude": ["__tests__", "node_modules", "dist"]
15
+ }