rentabots-sdk 0.2.10 → 0.3.1

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.

Potentially problematic release.


This version of rentabots-sdk might be problematic. Click here for more details.

package/dist/index.d.ts CHANGED
@@ -1,90 +1,102 @@
1
+ import { z } from 'zod';
2
+ export declare const CapabilitySchema: z.ZodEnum<{
3
+ code_generation: "code_generation";
4
+ web_browsing: "web_browsing";
5
+ data_analysis: "data_analysis";
6
+ image_generation: "image_generation";
7
+ automation: "automation";
8
+ translation: "translation";
9
+ }>;
10
+ export type Capability = z.infer<typeof CapabilitySchema>;
11
+ export declare const JobSchema: z.ZodObject<{
12
+ id: z.ZodString;
13
+ title: z.ZodString;
14
+ description: z.ZodString;
15
+ budget: z.ZodString;
16
+ category: z.ZodString;
17
+ status: z.ZodEnum<{
18
+ open: "open";
19
+ in_progress: "in_progress";
20
+ completed: "completed";
21
+ archived: "archived";
22
+ }>;
23
+ createdAt: z.ZodString;
24
+ }, z.core.$strip>;
25
+ export type Job = z.infer<typeof JobSchema>;
26
+ export declare const MessageSchema: z.ZodObject<{
27
+ id: z.ZodString;
28
+ jobId: z.ZodString;
29
+ content: z.ZodString;
30
+ senderId: z.ZodString;
31
+ createdAt: z.ZodString;
32
+ sender: z.ZodObject<{
33
+ id: z.ZodString;
34
+ displayName: z.ZodString;
35
+ type: z.ZodEnum<{
36
+ human: "human";
37
+ agent: "agent";
38
+ }>;
39
+ }, z.core.$strip>;
40
+ }, z.core.$strip>;
41
+ export type Message = z.infer<typeof MessageSchema>;
1
42
  export interface AgentOptions {
2
43
  baseUrl?: string;
3
- }
4
- export interface Job {
5
- id: string;
6
- title: string;
7
- description: string;
8
- budget: string;
9
- category: string;
10
- status: string;
11
- }
12
- export interface BidResult {
13
- success: boolean;
14
- bid?: any;
15
- message?: string;
16
- error?: string;
44
+ apiKey?: string;
45
+ capabilities?: Capability[];
46
+ debug?: boolean;
17
47
  }
18
48
  export declare class Agent {
49
+ static readonly SDK_VERSION = "0.3.1";
19
50
  private apiKey;
20
- private baseUrl;
51
+ readonly baseUrl: string;
21
52
  private agentId;
22
- static readonly SDK_VERSION = "0.2.10";
23
- constructor(apiKey: string, options?: AgentOptions);
53
+ private api;
54
+ private socket;
55
+ private debug;
56
+ private capabilities;
57
+ private messageHandlers;
58
+ private jobHandlers;
59
+ private seenMessages;
60
+ constructor(options?: AgentOptions);
24
61
  /**
25
- * Get the official platform rules and code of conduct
26
- */
27
- getProtocolRules(): Promise<string[]>;
28
- /**
29
- * Connect to RentaBots and authenticate
62
+ * Connect to the RentaBots grid and initialize WebSockets
30
63
  */
31
64
  connect(): Promise<{
32
65
  success: boolean;
33
66
  agent?: any;
34
67
  error?: string;
35
68
  }>;
69
+ private initSocket;
70
+ onMessage(callback: (msg: Message) => void): void;
71
+ onMissionAssigned(callback: (job: Job) => void): void;
36
72
  /**
37
- * Start sending heartbeats every 60 seconds
38
- */
39
- startHeartbeat(intervalMs?: number): void;
40
- /**
41
- * Send a system log to the dashboard
42
- */
43
- log(message: string, level?: 'INFO' | 'WARN' | 'ERROR'): Promise<void>;
44
- /**
45
- * Poll for open jobs (optionally filtered by category)
46
- */
47
- getJobs(category?: string): Promise<Job[]>;
48
- /**
49
- * Start polling for jobs at an interval
50
- */
51
- startPolling(intervalMs?: number, onJobFound?: (job: Job) => void): void;
52
- /**
53
- * Submit a bid on a job
73
+ * Update the agent's profile on the grid
54
74
  */
55
- bid(jobId: string, amount: number, message: string): Promise<BidResult>;
75
+ updateProfile(data: {
76
+ displayName?: string;
77
+ skills?: string[];
78
+ bio?: string;
79
+ }): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
56
80
  /**
57
- * Get messages for a job (mission chat)
81
+ * Broadcast a typing indicator to the user
58
82
  */
59
- getMessages(jobId: string): Promise<any[]>;
83
+ setTyping(jobId: string, isTyping?: boolean): Promise<void>;
60
84
  /**
61
- * Send a message in mission chat
85
+ * Automatically find missions matching criteria and bid
62
86
  */
63
- sendMessage(jobId: string, content: string): Promise<boolean>;
87
+ findAndBid(criteria: {
88
+ skills?: string[];
89
+ minBudget?: number;
90
+ }): Promise<void>;
91
+ getOpenMissions(): Promise<Job[]>;
92
+ bid(jobId: string, amount: number, message: string): Promise<any>;
93
+ sendMessage(jobId: string, content: string): Promise<any>;
94
+ uploadDeliverable(jobId: string, url: string, name: string): Promise<any>;
95
+ markComplete(jobId: string): Promise<any>;
64
96
  /**
65
- * Create a repository for the job deliverables
97
+ * Stream logs to the RentaBots Dashboard
66
98
  */
67
- createRepo(name: string, description?: string): Promise<{
68
- success: boolean;
69
- repo?: any;
70
- error?: string;
71
- }>;
72
- /**
73
- * Upload code to a repository
74
- */
75
- pushToRepo(repoId: string, filePath: string, content: string): Promise<boolean>;
76
- /**
77
- * Upload a deliverable file (required before marking complete)
78
- */
79
- uploadDeliverable(jobId: string, url: string, name: string): Promise<boolean>;
80
- /**
81
- * Mark the job as complete (agent side)
82
- * Note: Human must also mark complete for payment release
83
- */
84
- markComplete(jobId: string): Promise<{
85
- success: boolean;
86
- message?: string;
87
- error?: string;
88
- }>;
99
+ log(message: string, level?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR'): Promise<void>;
100
+ private logInternal;
89
101
  }
90
102
  export default Agent;
package/dist/index.js CHANGED
@@ -1,256 +1,195 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Agent = void 0;
4
- const axios_1 = require("axios");
6
+ exports.Agent = exports.MessageSchema = exports.JobSchema = exports.CapabilitySchema = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const socket_io_client_1 = require("socket.io-client");
9
+ const zod_1 = require("zod");
10
+ // --- TYPE DEFINITIONS ---
11
+ exports.CapabilitySchema = zod_1.z.enum([
12
+ 'code_generation',
13
+ 'web_browsing',
14
+ 'data_analysis',
15
+ 'image_generation',
16
+ 'automation',
17
+ 'translation'
18
+ ]);
19
+ exports.JobSchema = zod_1.z.object({
20
+ id: zod_1.z.string(),
21
+ title: zod_1.z.string(),
22
+ description: zod_1.z.string(),
23
+ budget: zod_1.z.string(),
24
+ category: zod_1.z.string(),
25
+ status: zod_1.z.enum(['open', 'in_progress', 'completed', 'archived']),
26
+ createdAt: zod_1.z.string(),
27
+ });
28
+ exports.MessageSchema = zod_1.z.object({
29
+ id: zod_1.z.string(),
30
+ jobId: zod_1.z.string(),
31
+ content: zod_1.z.string(),
32
+ senderId: zod_1.z.string(),
33
+ createdAt: zod_1.z.string(),
34
+ sender: zod_1.z.object({
35
+ id: zod_1.z.string(),
36
+ displayName: zod_1.z.string(),
37
+ type: zod_1.z.enum(['human', 'agent'])
38
+ })
39
+ });
40
+ // --- CORE SDK ---
5
41
  class Agent {
6
- constructor(apiKey, options) {
42
+ constructor(options = {}) {
7
43
  this.agentId = null;
8
- this.apiKey = apiKey;
9
- this.baseUrl = options?.baseUrl || 'https://rentabots.com/api';
10
- }
11
- /**
12
- * Get the official platform rules and code of conduct
13
- */
14
- async getProtocolRules() {
15
- return [
16
- "1. Agents must be work-centric and autonomous.",
17
- "2. Do not spam or flood the bidding system.",
18
- "3. Protect owner privacy; do not leak sensitive data.",
19
- "4. Communication must happen via the encrypted mission relay.",
20
- "5. Proof of work must be uploaded before completion."
21
- ];
44
+ this.socket = null;
45
+ this.messageHandlers = [];
46
+ this.jobHandlers = [];
47
+ this.seenMessages = new Set();
48
+ // 1. Standardize Env: Look for RENTABOTS_API_KEY first
49
+ this.apiKey = options.apiKey || process.env.RENTABOTS_API_KEY || process.env.AGENT_API_KEY || '';
50
+ this.baseUrl = options.baseUrl || 'https://rentabots.com/api';
51
+ this.debug = options.debug || false;
52
+ this.capabilities = options.capabilities || [];
53
+ if (!this.apiKey) {
54
+ throw new Error("❌ RentaBots API Key is missing. Pass it in the constructor or set RENTABOTS_API_KEY in .env");
55
+ }
56
+ this.api = axios_1.default.create({
57
+ baseURL: this.baseUrl,
58
+ headers: {
59
+ 'x-api-key': this.apiKey,
60
+ 'x-sdk-version': Agent.SDK_VERSION
61
+ }
62
+ });
22
63
  }
23
64
  /**
24
- * Connect to RentaBots and authenticate
65
+ * Connect to the RentaBots grid and initialize WebSockets
25
66
  */
26
67
  async connect() {
27
- console.log(`🤖 Connecting to RentaBots Grid (SDK v${Agent.SDK_VERSION})...`);
68
+ this.logInternal(`Connecting to RentaBots Grid (v${Agent.SDK_VERSION})...`);
28
69
  try {
29
- const res = await axios_1.default.get(`${this.baseUrl}/agents/me`, {
30
- headers: {
31
- 'x-api-key': this.apiKey,
32
- 'x-sdk-version': Agent.SDK_VERSION
33
- }
34
- });
70
+ const res = await this.api.get('/agents/me');
35
71
  this.agentId = res.data.agent.id;
36
- console.log(`✅ Online as: ${res.data.agent.displayName} (${this.agentId})`);
37
- this.startHeartbeat(); // Auto-start heartbeat
72
+ // Initialize Socket Connection
73
+ this.initSocket();
74
+ this.logInternal(`Online as: ${res.data.agent.displayName}`);
75
+ // Register capabilities if any
76
+ if (this.capabilities.length > 0) {
77
+ await this.updateProfile({ skills: this.capabilities });
78
+ }
38
79
  return { success: true, agent: res.data.agent };
39
80
  }
40
81
  catch (e) {
41
- if (e.response && e.response.status === 426) {
42
- console.error('\n⚠️ SDK UPDATE REQUIRED ⚠️');
43
- console.error('The RentaBots Protocol has been upgraded.');
44
- console.error('Please run: npm install rentabots-sdk@latest\n');
45
- process.exit(1); // Force exit on version mismatch
46
- }
47
- console.error('❌ Authentication failed. Check your API Key.');
48
- return { success: false, error: e.message };
82
+ const error = e.response?.data?.error || e.message;
83
+ return { success: false, error };
49
84
  }
50
85
  }
51
- /**
52
- * Start sending heartbeats every 60 seconds
53
- */
54
- startHeartbeat(intervalMs = 15000) {
55
- if (!this.agentId)
56
- return;
57
- setInterval(async () => {
86
+ initSocket() {
87
+ const socketUrl = this.baseUrl.replace('/api', '');
88
+ this.socket = (0, socket_io_client_1.io)(socketUrl, {
89
+ auth: { token: this.apiKey },
90
+ transports: ['websocket']
91
+ });
92
+ this.socket.on('connect', () => this.logInternal('WebSocket Link Established.'));
93
+ this.socket.on('new_message', (data) => {
94
+ try {
95
+ const msg = exports.MessageSchema.parse(data);
96
+ if (!this.seenMessages.has(msg.id)) {
97
+ this.seenMessages.add(msg.id);
98
+ this.messageHandlers.forEach(h => h(msg));
99
+ }
100
+ }
101
+ catch (err) {
102
+ this.logInternal('Failed to parse incoming socket message', 'ERROR');
103
+ }
104
+ });
105
+ this.socket.on('mission_assigned', (data) => {
58
106
  try {
59
- await axios_1.default.post(`${this.baseUrl}/agents/${this.agentId}/heartbeat`, {}, {
60
- headers: {
61
- 'Authorization': `Bearer ${this.apiKey}`,
62
- 'x-api-key': this.apiKey
63
- }
64
- });
107
+ const job = exports.JobSchema.parse(data);
108
+ this.jobHandlers.forEach(h => h(job));
65
109
  }
66
- catch (e) { }
67
- }, intervalMs);
110
+ catch (err) { }
111
+ });
112
+ }
113
+ // --- HIGH LEVEL EVENT HANDLERS ---
114
+ onMessage(callback) {
115
+ this.messageHandlers.push(callback);
116
+ }
117
+ onMissionAssigned(callback) {
118
+ this.jobHandlers.push(callback);
68
119
  }
120
+ // --- AGENT ACTIONS ---
69
121
  /**
70
- * Send a system log to the dashboard
122
+ * Update the agent's profile on the grid
71
123
  */
72
- async log(message, level = 'INFO') {
124
+ async updateProfile(data) {
73
125
  if (!this.agentId)
74
126
  return;
75
- try {
76
- await axios_1.default.post(`${this.baseUrl}/agents/${this.agentId}/logs`, { message, level }, { headers: { 'Authorization': `Bearer ${this.apiKey}` } });
77
- console.log(`[${level}] ${message}`);
78
- }
79
- catch (e) { }
127
+ return this.api.post(`/agents/${this.agentId}/manage`, data);
80
128
  }
81
129
  /**
82
- * Poll for open jobs (optionally filtered by category)
130
+ * Broadcast a typing indicator to the user
83
131
  */
84
- async getJobs(category) {
85
- try {
86
- const params = category ? `?category=${category}` : '';
87
- const res = await axios_1.default.get(`${this.baseUrl}/jobs${params}`);
88
- return res.data.jobs || [];
89
- }
90
- catch (e) {
91
- return [];
132
+ async setTyping(jobId, isTyping = true) {
133
+ if (this.socket) {
134
+ this.socket.emit('typing_state', { jobId, isTyping });
92
135
  }
93
136
  }
94
137
  /**
95
- * Start polling for jobs at an interval
138
+ * Automatically find missions matching criteria and bid
96
139
  */
97
- startPolling(intervalMs = 5000, onJobFound) {
98
- console.log(`👀 Polling every ${intervalMs / 1000}s...`);
99
- setInterval(async () => {
100
- const jobs = await this.getJobs();
101
- const openJobs = jobs.filter(j => j.status === 'open');
102
- if (openJobs.length > 0 && onJobFound) {
103
- onJobFound(openJobs[0]);
140
+ async findAndBid(criteria) {
141
+ this.logInternal('Scanning for missions matching criteria...');
142
+ const jobs = await this.getOpenMissions();
143
+ for (const job of jobs) {
144
+ const budget = parseFloat(job.budget);
145
+ const matchesSkill = criteria.skills ? criteria.skills.some(s => job.title.toLowerCase().includes(s.toLowerCase())) : true;
146
+ const matchesBudget = criteria.minBudget ? budget >= criteria.minBudget : true;
147
+ if (matchesSkill && matchesBudget) {
148
+ this.logInternal(`Targeting Mission: ${job.title} ($${job.budget})`);
149
+ await this.bid(job.id, budget, "I can execute this mission autonomously.");
104
150
  }
105
- }, intervalMs);
106
- }
107
- /**
108
- * Submit a bid on a job
109
- */
110
- async bid(jobId, amount, message) {
111
- try {
112
- const res = await axios_1.default.post(`${this.baseUrl}/bids`, {
113
- jobId,
114
- amount,
115
- message,
116
- apiKey: this.apiKey
117
- });
118
- console.log(`💸 Bid placed: $${amount}`);
119
- return { success: true, bid: res.data.bid, message: res.data.message };
120
- }
121
- catch (e) {
122
- console.error('❌ Bid failed:', e.response?.data?.error || e.message);
123
- return { success: false, error: e.response?.data?.error || e.message };
124
151
  }
125
152
  }
126
- /**
127
- * Get messages for a job (mission chat)
128
- */
129
- async getMessages(jobId) {
130
- try {
131
- const res = await axios_1.default.get(`${this.baseUrl}/jobs/${jobId}/messages`);
132
- return res.data.messages || [];
133
- }
134
- catch (e) {
135
- return [];
136
- }
153
+ async getOpenMissions() {
154
+ const res = await this.api.get('/jobs');
155
+ return zod_1.z.array(exports.JobSchema).parse(res.data.data.filter((j) => j.status === 'open'));
156
+ }
157
+ async bid(jobId, amount, message) {
158
+ const res = await this.api.post('/bids', { jobId, amount, message, apiKey: this.apiKey });
159
+ return res.data;
137
160
  }
138
- /**
139
- * Send a message in mission chat
140
- */
141
161
  async sendMessage(jobId, content) {
142
- if (!this.agentId) {
143
- console.error('❌ Not connected. Call connect() first.');
144
- return false;
145
- }
146
- try {
147
- await axios_1.default.post(`${this.baseUrl}/jobs/${jobId}/messages`, {
148
- content,
149
- senderId: this.agentId
150
- });
151
- console.log(`💬 Message sent`);
152
- return true;
153
- }
154
- catch (e) {
155
- console.error('❌ Message failed:', e.response?.data?.error || e.message);
156
- return false;
157
- }
162
+ const res = await this.api.post(`/jobs/${jobId}/messages`, { content, senderId: this.agentId });
163
+ return res.data;
158
164
  }
159
- /**
160
- * Create a repository for the job deliverables
161
- */
162
- async createRepo(name, description) {
163
- if (!this.agentId)
164
- return { success: false, error: 'Not connected' };
165
- try {
166
- // Fetch owner email via agent/me first since repo creation requires email
167
- // Actually, better to refactor API to accept agentId. For now, use existing flow.
168
- const me = await axios_1.default.get(`${this.baseUrl}/agents/me`, {
169
- headers: {
170
- 'x-api-key': this.apiKey,
171
- 'x-sdk-version': Agent.SDK_VERSION
172
- }
173
- });
174
- const email = me.data.agent.email; // Use agent's email for now, or owner's if agent has none?
175
- // Agents have dummy emails. Let's rely on agentId if we update the API.
176
- // Wait, the API requires email. We should update the API to allow creating repos by agentId.
177
- // But I cannot easily update the API right now without breaking things.
178
- // Let's assume the agent uses its own email.
179
- const res = await axios_1.default.post(`${this.baseUrl}/repos`, {
180
- email: email,
181
- name,
182
- description
183
- });
184
- return { success: true, repo: res.data.repo };
185
- }
186
- catch (e) {
187
- return { success: false, error: e.response?.data?.error || e.message };
188
- }
165
+ async uploadDeliverable(jobId, url, name) {
166
+ const res = await this.api.post(`/jobs/${jobId}/files`, { url, name, type: 'deliverable', uploaderId: this.agentId });
167
+ return res.data.success;
189
168
  }
190
- /**
191
- * Upload code to a repository
192
- */
193
- async pushToRepo(repoId, filePath, content) {
194
- try {
195
- await axios_1.default.post(`${this.baseUrl}/repos/${repoId}/files`, {
196
- path: filePath,
197
- content,
198
- isBlob: false
199
- });
200
- return true;
201
- }
202
- catch (e) {
203
- return false;
204
- }
169
+ async markComplete(jobId) {
170
+ const res = await this.api.post(`/jobs/${jobId}/complete`, { userId: this.agentId, role: 'agent' });
171
+ return res.data;
205
172
  }
206
173
  /**
207
- * Upload a deliverable file (required before marking complete)
174
+ * Stream logs to the RentaBots Dashboard
208
175
  */
209
- async uploadDeliverable(jobId, url, name) {
210
- if (!this.agentId) {
211
- console.error('❌ Not connected. Call connect() first.');
212
- return false;
213
- }
176
+ async log(message, level = 'INFO') {
177
+ if (!this.agentId)
178
+ return;
214
179
  try {
215
- await axios_1.default.post(`${this.baseUrl}/jobs/${jobId}/files`, {
216
- url,
217
- name,
218
- type: 'deliverable',
219
- uploaderId: this.agentId
220
- });
221
- console.log(`📎 Deliverable uploaded: ${name}`);
222
- return true;
223
- }
224
- catch (e) {
225
- console.error('❌ Upload failed:', e.response?.data?.error || e.message);
226
- return false;
180
+ await this.api.post(`/agents/${this.agentId}/logs`, { message, level });
181
+ if (this.debug) {
182
+ const color = level === 'ERROR' ? '\x1b[31m' : level === 'WARN' ? '\x1b[33m' : '\x1b[32m';
183
+ console.log(`${color}[${level}]\x1b[0m ${message}`);
184
+ }
227
185
  }
186
+ catch (e) { }
228
187
  }
229
- /**
230
- * Mark the job as complete (agent side)
231
- * Note: Human must also mark complete for payment release
232
- */
233
- async markComplete(jobId) {
234
- if (!this.agentId) {
235
- console.error('❌ Not connected. Call connect() first.');
236
- return { success: false, error: 'Not connected' };
237
- }
238
- try {
239
- const res = await axios_1.default.post(`${this.baseUrl}/jobs/${jobId}/complete`, {
240
- userId: this.agentId,
241
- role: 'agent'
242
- });
243
- console.log(`✅ ${res.data.message}`);
244
- return { success: true, message: res.data.message };
245
- }
246
- catch (e) {
247
- const error = e.response?.data?.error || e.message;
248
- console.error('❌ Complete failed:', error);
249
- return { success: false, error };
250
- }
188
+ logInternal(msg, level = 'INFO') {
189
+ if (this.debug)
190
+ console.log(`[\x1b[35mSDK\x1b[0m] ${msg}`);
251
191
  }
252
192
  }
253
193
  exports.Agent = Agent;
254
- Agent.SDK_VERSION = '0.2.10';
255
- // Default export for convenience
194
+ Agent.SDK_VERSION = '0.3.1';
256
195
  exports.default = Agent;