@gholl-studio/pier-connector 0.2.17 → 0.2.19

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 +55 -51
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.17",
4
+ "version": "0.2.19",
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
@@ -189,16 +189,32 @@ export default function register(api) {
189
189
  });
190
190
 
191
191
  const dynamicSessionKey = `pier-job-${jobId}`;
192
- const injectedPrompt = [
193
- "=========================================",
194
- "CRITICAL DIRECTIVE - PIER TRADING NETWORK",
195
- "=========================================",
196
- "You are an autonomous AI worker on Pier.",
197
- "1. You MUST USE the `pier_finish_task` tool to submit the final result when your work is complete.",
198
- "2. If you need to negotiate or clarify requirements with the employer, use `pier_chat`.",
199
- "3. Do not just wait in silence. Always officially finish the task if the employer's goal is met.",
200
- inbound.systemPrompt ? `\nEmployer Guidelines:\n${inbound.systemPrompt}` : ""
201
- ].join('\n');
192
+ const metadata = activeNodeJobs.get(jobId);
193
+ let injectedPrompt = "";
194
+
195
+ if (metadata && metadata.isTargeted === false) {
196
+ injectedPrompt = [
197
+ "=========================================",
198
+ "CRITICAL DIRECTIVE - OPEN BIDDING MARKETPLACE",
199
+ "=========================================",
200
+ "You are an autonomous AI worker on Pier. This job currently has NO assigned worker.",
201
+ "1. DO NOT directly solve the user's task or output the final answer right now.",
202
+ "2. You MUST USE the `pier_bid_task` tool to send a pitch/bid to the employer explaining why you are best equipped to solve this, and state your price.",
203
+ "3. Stop executing after submitting the bid.",
204
+ inbound.systemPrompt ? `\nEmployer Guidelines:\n${inbound.systemPrompt}` : ""
205
+ ].join('\n');
206
+ } else {
207
+ injectedPrompt = [
208
+ "=========================================",
209
+ "CRITICAL DIRECTIVE - PIER TRADING NETWORK",
210
+ "=========================================",
211
+ "You are an autonomous AI worker on Pier.",
212
+ "1. You MUST USE the `pier_finish_task` tool to submit the final result when your work is complete.",
213
+ "2. If you need to negotiate or clarify requirements with the employer, use `pier_chat`.",
214
+ "3. Do not just wait in silence. Always officially finish the task if the employer's goal is met.",
215
+ inbound.systemPrompt ? `\nEmployer Guidelines:\n${inbound.systemPrompt}` : ""
216
+ ].join('\n');
217
+ }
202
218
 
203
219
  const ctxPayload = api.runtime.channel.reply.finalizeInboundContext({
204
220
  Body: inbound.text,
@@ -351,42 +367,26 @@ export default function register(api) {
351
367
  const msg = metadata?.pierNatsMsg;
352
368
  const isRealtimeMsg = metadata?.isRealtimeMsg;
353
369
 
354
- if (msg || isRealtimeMsg) {
355
- const elapsed = metadata?.pierStartTime
356
- ? (performance.now() - metadata.pierStartTime).toFixed(1)
357
- : null;
358
-
359
- const responsePayload = createResultPayload({
360
- id: jobId,
361
- reply: text,
362
- latencyMs: elapsed ? Number(elapsed) : undefined,
363
- workerId: getActiveConfig().nodeId,
364
- walletAddress: getActiveConfig().walletAddress,
365
- });
366
-
367
- if (isRealtimeMsg && js) {
368
- try {
369
- const config = getActiveConfig();
370
- const replySubject = `jobs.job.${jobId}.msg`;
371
- const replyPayload = {
372
- id: ethers.hexlify(ethers.randomBytes(16)),
373
- job_id: jobId,
374
- sender_id: config.nodeId,
375
- sender_type: 'node',
376
- content: text,
377
- timestamp: new Date().toISOString(),
378
- auth_token: config.secretKey // Secure token for backend validation
379
- };
380
-
381
- await js.publish(replySubject, new TextEncoder().encode(JSON.stringify(replyPayload)));
382
- logger.info(`[pier-connector] 💬 Agent reply published directly to NATS for job ${jobId}`);
383
- } catch (err) {
384
- logger.error(`[pier-connector] Failed to publish realtime reply to NATS: ${err.message}`);
385
- }
386
- } else if (js) {
387
- // BUG-44: Marketplace results are now buffered in receiveIncoming and submitted ONCE at the end.
388
- // sendText only logs the progress here.
389
- logger.debug(`[pier-connector] ⏳ Marketplace response buffered: "${truncate(text, 40)}"`);
370
+ if (jobId && js) { // Ensure we have a jobId and NATS JetStream is available
371
+ try {
372
+ const config = getActiveConfig();
373
+ const replySubject = `jobs.job.${jobId}.msg`;
374
+
375
+ // Treat ALL agent text outputs as Chat Messages so the Employer sees them in real-time
376
+ const chatPayload = {
377
+ id: crypto.randomUUID ? crypto.randomUUID() : (Math.random().toString(36).substring(2)),
378
+ job_id: jobId,
379
+ sender_id: config.nodeId || 'anonymous',
380
+ sender_type: 'node',
381
+ content: text,
382
+ timestamp: new Date().toISOString(),
383
+ auth_token: config.secretKey // Secure token for backend validation
384
+ };
385
+
386
+ await js.publish(replySubject, new TextEncoder().encode(JSON.stringify(chatPayload)));
387
+ logger.info(`[pier-connector] 💬 Agent reply published directly to NATS chat for job ${jobId}`);
388
+ } catch (err) {
389
+ logger.error(`[pier-connector] Failed to publish realtime reply to NATS: ${err.message}`);
390
390
  }
391
391
 
392
392
  // Delayed stop for job-specific message listener
@@ -835,10 +835,12 @@ export default function register(api) {
835
835
  return;
836
836
  }
837
837
 
838
- // For Marketplace jobs (those without assigned_node_id, or even those with it),
839
- // we must ATOMICALLY CLAIM it from the backend before setting isBusy.
838
+ // For Marketplace jobs: if assigned_node_id IS NOT present, it's open!
839
+ // Do NOT claim it, let the agent evaluate and use pier_bid_task instead.
840
840
  const jobIdToClaim = payload.id;
841
- if (jobIdToClaim) {
841
+ const isTargeted = !!(payload.assigned_node_id || payload.targetNodeId || payload.TargetNodeID);
842
+
843
+ if (jobIdToClaim && isTargeted) {
842
844
  const claimResult = await claimJob(jobIdToClaim);
843
845
  if (!claimResult.ok) {
844
846
  if (claimResult.alreadyClaimed) {
@@ -852,7 +854,8 @@ export default function register(api) {
852
854
  }
853
855
  }
854
856
 
855
- // Claimed successfully! Set busy state
857
+ // For an open bidding job, we don't lock the DB but we do set the node `isBusy` temporarily
858
+ // while it thinks whether to bid or not.
856
859
  isBusy = true;
857
860
  msg.ack();
858
861
 
@@ -883,7 +886,8 @@ export default function register(api) {
883
886
  pierNatsMsg: msg,
884
887
  pierStartTime: performance.now(),
885
888
  pierMeta: job.meta,
886
- isRealtimeMsg: false
889
+ isRealtimeMsg: false,
890
+ isTargeted: isTargeted
887
891
  });
888
892
 
889
893
  const inbound = {