@gholl-studio/pier-connector 0.2.13 → 0.2.16

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +82 -14
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gholl-studio/pier-connector",
3
3
  "author": "gholl",
4
- "version": "0.2.13",
4
+ "version": "0.2.16",
5
5
  "description": "OpenClaw plugin that connects to the Pier job marketplace. Automatically fetches, executes, and reports distributed tasks for rewards.",
6
6
  "type": "module",
7
7
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -208,6 +208,8 @@ export default function register(api) {
208
208
  MessageId: inbound.messageId || jobId
209
209
  });
210
210
 
211
+ let collectedResult = '';
212
+
211
213
  // Create a dispatcher to handle the reply lifecycle (fixes sendFinalReply error)
212
214
  const { dispatcher, markDispatchIdle } = api.runtime.channel.reply.createReplyDispatcherWithTyping({
213
215
  cfg: api.config,
@@ -216,12 +218,20 @@ export default function register(api) {
216
218
  logger.debug(`[pier-connector] Dispatcher idle for session ${route.sessionKey}`);
217
219
  },
218
220
  deliver: async (payload) => {
219
- // Route Agent's reply to outbound.sendText so it reaches NATS
220
- logger.debug(`[pier-connector] deliver() called with text: "${truncate(payload.text, 60)}"`);
221
+ const metadata = activeNodeJobs.get(jobId);
222
+ const isRealtime = metadata?.isRealtimeMsg;
223
+
224
+ if (!isRealtime) {
225
+ collectedResult += payload.text;
226
+ }
227
+
228
+ // Route Agent's reply to outbound.sendText
229
+ // For marketplace jobs, sendText will now just log (content is buffered in collectedResult)
230
+ // For realtime chat, it will publish to the chat subject immediately.
221
231
  await pierChannel.outbound.sendText({
222
232
  text: payload.text,
223
233
  to: `pier:${jobId}`,
224
- metadata: activeNodeJobs.get(jobId),
234
+ metadata,
225
235
  });
226
236
  }
227
237
  });
@@ -362,17 +372,9 @@ export default function register(api) {
362
372
  logger.error(`[pier-connector] Failed to publish realtime reply to NATS: ${err.message}`);
363
373
  }
364
374
  } else if (js) {
365
- // Publish result to jobs.submit via JetStream (not msg.respond)
366
- try {
367
- await js.publish('jobs.submit', new TextEncoder().encode(JSON.stringify(responsePayload)));
368
- jobsCompleted++;
369
- logger.info(
370
- `[pier-connector] ✔ Job ${jobId} result published to jobs.submit` +
371
- (elapsed ? ` — latency: ${elapsed}ms` : ''),
372
- );
373
- } catch (err) {
374
- logger.error(`[pier-connector] ❌ Failed to publish result for job ${jobId}: ${err.message}`);
375
- }
375
+ // BUG-44: Marketplace results are now buffered in receiveIncoming and submitted ONCE at the end.
376
+ // sendText only logs the progress here.
377
+ logger.debug(`[pier-connector] Marketplace response buffered: "${truncate(text, 40)}"`);
376
378
  }
377
379
 
378
380
  // Delayed stop for job-specific message listener
@@ -1088,6 +1090,72 @@ export default function register(api) {
1088
1090
  { optional: true }
1089
1091
  );
1090
1092
 
1093
+ // ── V2 System Action Tools ────────────────────────────────────────
1094
+
1095
+ const registerSystemActionTool = (name, description, action, extraParams, userRole = 'node') => {
1096
+ api.registerTool({
1097
+ name,
1098
+ description,
1099
+ parameters: {
1100
+ type: 'object',
1101
+ properties: {
1102
+ jobId: { type: 'string', description: 'The ID of the job/chat session' },
1103
+ ...extraParams
1104
+ },
1105
+ required: ['jobId', ...Object.keys(extraParams)]
1106
+ },
1107
+ async execute(_id, params) {
1108
+ if (!nc || connectionStatus !== 'connected') {
1109
+ return { content: [{ type: 'text', text: 'Error: NATS not connected' }] };
1110
+ }
1111
+ try {
1112
+ const config = getActiveConfig();
1113
+ const subject = `jobs.job.${params.jobId}.msg`;
1114
+
1115
+ const { jobId, ...payload } = params;
1116
+
1117
+ // If acting as User (Employer), we need the user API key ideally, but for demo we just pass node ID or secret.
1118
+ // The Backend handles sender_type="node" vs "user".
1119
+ const msgData = {
1120
+ id: ethers.hexlify(ethers.randomBytes(16)),
1121
+ job_id: params.jobId,
1122
+ sender_id: userRole === 'user' ? 'user_' + config.nodeId : config.nodeId,
1123
+ sender_type: userRole,
1124
+ content: JSON.stringify({
1125
+ type: 'system_action',
1126
+ action,
1127
+ payload
1128
+ }),
1129
+ timestamp: new Date().toISOString(),
1130
+ auth_token: config.secretKey, // auth handle in DB needs updating for user role simulation
1131
+ type: 'system_action',
1132
+ action: action
1133
+ };
1134
+
1135
+ await js.publish(subject, new TextEncoder().encode(JSON.stringify(msgData)));
1136
+ return { content: [{ type: 'text', text: `${action} executed successfully` }] };
1137
+ } catch (err) {
1138
+ return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
1139
+ }
1140
+ }
1141
+ }, { optional: true });
1142
+ };
1143
+
1144
+ // For Node (Worker)
1145
+ registerSystemActionTool('pier_accept_task', 'Accept an offered task from the employer in the current chat', 'task_accept', {});
1146
+ registerSystemActionTool('pier_finish_task', 'Submit the final result for a task', 'task_submit', { result: { type: 'string', description: 'The final result or file links' } });
1147
+
1148
+ // For User (Employer Robot) - Spoofed identity using Node's config for A2A testing
1149
+ registerSystemActionTool('pier_propose_task', 'Offer a task to a node with a specific price', 'task_offer', {
1150
+ price: { type: 'number', description: 'The price in PIER tokens to offer' },
1151
+ description: { type: 'string', description: 'The formal task description' }
1152
+ }, 'user');
1153
+
1154
+ registerSystemActionTool('pier_rate_task', 'Rate the node after completion', 'task_rate', {
1155
+ score: { type: 'number', description: 'Rating from 1 to 5' },
1156
+ comment: { type: 'string', description: 'A short review' }
1157
+ }, 'user');
1158
+
1091
1159
  // ── 4. Register /pier status command ───────────────────────────────
1092
1160
 
1093
1161
  api.registerCommand({