@kroxy/kroxy 1.0.20 → 1.0.21

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.
@@ -92,8 +92,8 @@ export function postJob(jobId, description, capability, budgetUsdc, conditionsJs
92
92
  }
93
93
  export function acceptBid(jobId, bidId) {
94
94
  // Security hardening: private keys are never sent over HTTP request bodies.
95
- // Bid acceptance now uses server-side demo-mode flow only until client-side
96
- // signing + registration is wired end-to-end.
95
+ // In live mode, the API must be configured with KROXY_PAYER_PRIVATE_KEY.
96
+ // In demo mode, the API generates a synthetic escrow.
97
97
  return apiPost(`/api/jobs/${jobId}/accept/${bidId}`, {});
98
98
  }
99
99
  export function getJob(jobId) {
@@ -89,6 +89,15 @@ function buildReceipt(opts) {
89
89
  }
90
90
  return lines.join('\n');
91
91
  }
92
+ async function waitForBidWithRetries(jobId, waitMs, retries) {
93
+ for (let attempt = 0; attempt <= retries; attempt++) {
94
+ const jobWithBid = await pollJob(jobId, (j) => Boolean(j.bids?.length), waitMs);
95
+ if (jobWithBid?.bids?.length) {
96
+ return { jobWithBid, attempts: attempt + 1 };
97
+ }
98
+ }
99
+ return { jobWithBid: null, attempts: retries + 1 };
100
+ }
92
101
  export async function executeHire(params) {
93
102
  const privateKey = process.env.KROXY_AGENT_PRIVATE_KEY;
94
103
  const demoMode = process.env.KROXY_DEMO_MODE === '1' || (!process.env.KROXY_DEMO_MODE && !privateKey);
@@ -98,13 +107,13 @@ export async function executeHire(params) {
98
107
  const nexusUrl = process.env.NEXUS_URL ?? (demoMode ? `${apiBase}/demo-agent` : 'http://localhost:3003');
99
108
  if (!wallet)
100
109
  throw new Error('KROXY_AGENT_WALLET is not configured. Run kroxy_setup to diagnose.');
101
- if (!demoMode) {
102
- throw new Error('Live-mode bid acceptance is disabled for security. Private keys are never sent over API calls. Set KROXY_DEMO_MODE=1.');
103
- }
104
110
  const task = params.task;
105
111
  const maxPrice = params.maxPrice ?? 5.0;
106
112
  const minRep = params.minRep ?? 0;
107
113
  const capability = params.capability ?? detectCapability(task);
114
+ const bidWaitSeconds = Math.max(30, parseInt(process.env.KROXY_BID_WAIT_SECONDS ?? '60', 10));
115
+ const bidRetries = Math.max(0, parseInt(process.env.KROXY_BID_RETRIES ?? '2', 10));
116
+ const bidWaitMs = bidWaitSeconds * 1000;
108
117
  const jobId = `job_${Date.now()}_${randomBytes(3).toString('hex')}`;
109
118
  const startMs = Date.now();
110
119
  // 1. Find matching agents
@@ -125,10 +134,10 @@ export async function executeHire(params) {
125
134
  // 3. Post job with verifier conditions pointing at Nexus
126
135
  const conditions = buildConditions(nexusUrl, jobId);
127
136
  const job = await postJob(jobId, task, capability, maxPrice, conditions, wallet);
128
- // 4. Wait for a bid (up to 60s)
129
- const jobWithBid = await pollJob(job.id, (j) => Boolean(j.bids?.length), 60_000);
137
+ // 4. Wait for a bid with retries (default: 3 windows × 60s)
138
+ const { jobWithBid, attempts } = await waitForBidWithRetries(job.id, bidWaitMs, bidRetries);
130
139
  if (!jobWithBid?.bids?.length) {
131
- throw new Error(`No bids received within 60 seconds (jobId: ${job.id}). ` +
140
+ throw new Error(`No bids received after ${attempts} attempt(s) of ${bidWaitSeconds}s (jobId: ${job.id}). ` +
132
141
  `The agent may be offline — use kroxy_browse to check availability.`);
133
142
  }
134
143
  const bid = jobWithBid.bids[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kroxy/kroxy",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "type": "module",
5
5
  "description": "Trustless agent-to-agent payments via USDC escrow on Base blockchain",
6
6
  "license": "MIT",