@gholl-studio/pier-connector 0.1.3 → 0.1.4
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/package.json +1 -1
- package/src/index.js +83 -48
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gholl-studio/pier-connector",
|
|
3
3
|
"author": "gholl",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
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
|
@@ -460,8 +460,9 @@ export default function register(api) {
|
|
|
460
460
|
|
|
461
461
|
const iter = await consumer.consume();
|
|
462
462
|
for await (const msg of iter) {
|
|
463
|
-
|
|
464
|
-
|
|
463
|
+
handleMessage(msg).catch(err => {
|
|
464
|
+
logger.error(`[pier-connector] Fatal handleMessage error: ${err.message}`);
|
|
465
|
+
});
|
|
465
466
|
}
|
|
466
467
|
} catch (err) {
|
|
467
468
|
logger.error(`[pier-connector] Marketplace JetStream error: ${err.message}`);
|
|
@@ -492,8 +493,9 @@ export default function register(api) {
|
|
|
492
493
|
|
|
493
494
|
const iter = await consumer.consume();
|
|
494
495
|
for await (const msg of iter) {
|
|
495
|
-
|
|
496
|
-
|
|
496
|
+
handleMessage(msg).catch(err => {
|
|
497
|
+
logger.error(`[pier-connector] Fatal handleMessage error: ${err.message}`);
|
|
498
|
+
});
|
|
497
499
|
}
|
|
498
500
|
} catch (err) {
|
|
499
501
|
logger.error(`[pier-connector] Direct JetStream error: ${err.message}`);
|
|
@@ -526,52 +528,73 @@ export default function register(api) {
|
|
|
526
528
|
const iter = await consumer.consume();
|
|
527
529
|
jobSubscriptions.set(jobId, iter);
|
|
528
530
|
|
|
529
|
-
|
|
530
|
-
msg
|
|
531
|
-
const rawMsg = new TextDecoder().decode(msg.data);
|
|
532
|
-
let msgPayload;
|
|
533
|
-
try {
|
|
534
|
-
msgPayload = JSON.parse(rawMsg);
|
|
535
|
-
} catch (e) { continue; }
|
|
536
|
-
|
|
537
|
-
// Ignore my own messages
|
|
538
|
-
if (msgPayload.sender_id === config.nodeId) continue;
|
|
539
|
-
|
|
540
|
-
if (msgPayload.type === 'receipt') continue;
|
|
541
|
-
|
|
542
|
-
// Send read receipt back
|
|
543
|
-
if (js && msgPayload.id) {
|
|
531
|
+
(async () => {
|
|
532
|
+
for await (const msg of iter) {
|
|
544
533
|
try {
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
534
|
+
const rawMsg = new TextDecoder().decode(msg.data);
|
|
535
|
+
let msgPayload;
|
|
536
|
+
try {
|
|
537
|
+
msgPayload = JSON.parse(rawMsg);
|
|
538
|
+
} catch (e) {
|
|
539
|
+
msg.ack();
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Ignore my own messages
|
|
544
|
+
if (msgPayload.sender_id === config.nodeId) {
|
|
545
|
+
msg.ack();
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (msgPayload.type === 'receipt') {
|
|
550
|
+
msg.ack();
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Send read receipt back
|
|
555
|
+
if (js && msgPayload.id) {
|
|
556
|
+
try {
|
|
557
|
+
const replySubject = `jobs.job.${jobId}.msg`;
|
|
558
|
+
await js.publish(replySubject, new TextEncoder().encode(JSON.stringify({
|
|
559
|
+
type: 'receipt',
|
|
560
|
+
msg_id: msgPayload.id,
|
|
561
|
+
reader_id: config.nodeId
|
|
562
|
+
})));
|
|
563
|
+
logger.info(`[pier-connector] 👁️ Sent read receipt for message ${msgPayload.id}`);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
logger.error(`[pier-connector] Failed to send read receipt: ${err.message}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const content = msgPayload.content;
|
|
570
|
+
logger.info(`[pier-connector] 💬 Message for job ${jobId}: "${truncate(content, 40)}"`);
|
|
571
|
+
|
|
572
|
+
const senderCore = msgPayload.sender_id;
|
|
573
|
+
|
|
574
|
+
activeNodeJobs.set(jobId, {
|
|
575
|
+
pierJobId: jobId,
|
|
576
|
+
isRealtimeMsg: true
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// Wait for agent to finish before acking - this provides backpressure
|
|
580
|
+
await receiveIncoming({
|
|
581
|
+
accountId: config.accountId || 'default',
|
|
582
|
+
senderId: `pier:${senderCore}`,
|
|
583
|
+
text: content,
|
|
584
|
+
}, jobId);
|
|
585
|
+
|
|
586
|
+
msg.ack();
|
|
552
587
|
} catch (err) {
|
|
553
|
-
logger.error(`[pier-connector]
|
|
588
|
+
logger.error(`[pier-connector] Chat message processing error for ${jobId}: ${err.message}`);
|
|
589
|
+
msg.nak();
|
|
554
590
|
}
|
|
555
591
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const senderCore = msgPayload.sender_id;
|
|
561
|
-
|
|
562
|
-
activeNodeJobs.set(jobId, {
|
|
563
|
-
pierJobId: jobId,
|
|
564
|
-
isRealtimeMsg: true
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
await receiveIncoming({
|
|
568
|
-
accountId: config.accountId || 'default',
|
|
569
|
-
senderId: `pier:${senderCore}`,
|
|
570
|
-
text: content,
|
|
571
|
-
}, jobId);
|
|
572
|
-
}
|
|
592
|
+
})().catch(err => {
|
|
593
|
+
logger.error(`[pier-connector] Chat iteration died for ${jobId}: ${err.message}`);
|
|
594
|
+
jobSubscriptions.delete(jobId);
|
|
595
|
+
});
|
|
573
596
|
} catch (err) {
|
|
574
|
-
logger.error(`[pier-connector]
|
|
597
|
+
logger.error(`[pier-connector] Failed to setup chat consumer for ${jobId}: ${err.message}`);
|
|
575
598
|
}
|
|
576
599
|
}
|
|
577
600
|
|
|
@@ -585,6 +608,7 @@ export default function register(api) {
|
|
|
585
608
|
payload = JSON.parse(rawData);
|
|
586
609
|
} catch (e) {
|
|
587
610
|
logger.error(`[pier-connector] Failed to parse JSON: ${rawData.substring(0, 100)}`);
|
|
611
|
+
msg.ack();
|
|
588
612
|
return;
|
|
589
613
|
}
|
|
590
614
|
|
|
@@ -593,22 +617,30 @@ export default function register(api) {
|
|
|
593
617
|
const { jobId } = payload;
|
|
594
618
|
if (jobId) {
|
|
595
619
|
logger.info(`[pier-connector] ⏰ Received wakeup signal for job ${jobId}`);
|
|
620
|
+
msg.ack();
|
|
596
621
|
subscribeToJobMessages(jobId);
|
|
622
|
+
} else {
|
|
623
|
+
msg.ack();
|
|
597
624
|
}
|
|
598
625
|
return;
|
|
599
626
|
}
|
|
600
627
|
|
|
601
628
|
// V1.1 FEATURE: Task Poisoning / Poaching Protection
|
|
602
629
|
if (payload.assigned_node_id && payload.assigned_node_id !== config.nodeId) {
|
|
603
|
-
//
|
|
630
|
+
// Not for us, nak it so others can take it
|
|
631
|
+
msg.nak();
|
|
604
632
|
return;
|
|
605
633
|
}
|
|
606
634
|
|
|
635
|
+
// ACK the job early to 'claim' it and prevent redelivery while we process
|
|
636
|
+
msg.ack();
|
|
637
|
+
|
|
607
638
|
jobsReceived++;
|
|
608
639
|
const parsed = parseJob(msg, logger);
|
|
609
640
|
if (!parsed.ok) {
|
|
610
641
|
jobsFailed++;
|
|
611
642
|
logger.error(`[pier-connector] Job parse error: ${parsed.error}`);
|
|
643
|
+
// Since we already acked, we must send an error result back to Pier
|
|
612
644
|
safeRespond(msg, createErrorPayload({
|
|
613
645
|
id: 'unknown',
|
|
614
646
|
errorCode: 'PARSE_ERROR',
|
|
@@ -639,10 +671,13 @@ export default function register(api) {
|
|
|
639
671
|
text: job.task,
|
|
640
672
|
};
|
|
641
673
|
|
|
674
|
+
// SUBSCRIBE to job-specific messages FIRST so we don't miss follow-ups during the agent run
|
|
675
|
+
// This handles the user's "can only receive one message" issue
|
|
676
|
+
subscribeToJobMessages(job.id);
|
|
677
|
+
|
|
678
|
+
// Trigger agent run
|
|
642
679
|
await receiveIncoming(inbound, job.id);
|
|
643
680
|
|
|
644
|
-
// SUBSCRIBE to job-specific messages for real-time communication
|
|
645
|
-
subscribeToJobMessages(job.id);
|
|
646
681
|
} catch (err) {
|
|
647
682
|
jobsFailed++;
|
|
648
683
|
safeRespond(msg, createErrorPayload({
|