@lucid-agents/taskmarket 1.18.0 → 1.19.0

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.
@@ -7,7 +7,7 @@ import {
7
7
  recordSessionEnd,
8
8
  recordSessionStart,
9
9
  uploadPlan
10
- } from "./chunk-ESPAXW2P.js";
10
+ } from "./chunk-3HCDMHXW.js";
11
11
  import {
12
12
  TaskOperationError,
13
13
  authorizeUploads,
@@ -27,7 +27,7 @@ import {
27
27
  signReadAuth,
28
28
  submitUploadedArtifacts,
29
29
  taskAccessGrantHeaders
30
- } from "./chunk-JJUF3KZY.js";
30
+ } from "./chunk-F2SZG7TC.js";
31
31
  import {
32
32
  terminalPrompter
33
33
  } from "./chunk-ZIC2YCLV.js";
@@ -67,7 +67,7 @@ import {
67
67
  sha256Hex,
68
68
  specHash,
69
69
  taskStage
70
- } from "./chunk-L6ZVRENW.js";
70
+ } from "./chunk-RKGRXJ5X.js";
71
71
  import {
72
72
  BrokerConnector,
73
73
  OutputLimitError,
@@ -79,7 +79,7 @@ import {
79
79
  serveSandboxChannel,
80
80
  withFileLock,
81
81
  writeAtomic
82
- } from "./chunk-64HQ7ZF2.js";
82
+ } from "./chunk-MJR2CZWZ.js";
83
83
  import {
84
84
  applyComputeCreditSetup,
85
85
  atomicToUsd,
@@ -89,7 +89,7 @@ import {
89
89
  planComputeCreditSetup,
90
90
  readComputeCreditBalance,
91
91
  usdToAtomic
92
- } from "./chunk-W7CXEYST.js";
92
+ } from "./chunk-6KJ5EFBN.js";
93
93
  import {
94
94
  MAX_RETIRED_RAILS,
95
95
  WORKSPACE_CONSENT_VERSION,
@@ -109,7 +109,7 @@ import {
109
109
  routeOfCatalogRow,
110
110
  saveAgentPolicy,
111
111
  settledRetiredRails
112
- } from "./chunk-MO5KMUTL.js";
112
+ } from "./chunk-7Y7IOFKT.js";
113
113
  import {
114
114
  BASE_CHANNEL_RAIL_ID,
115
115
  createBaseChannelPayer,
@@ -122,7 +122,7 @@ import {
122
122
  parseX402Policy,
123
123
  saveX402Policy,
124
124
  x402SpendWindowAvailability
125
- } from "./chunk-S4A6V3J3.js";
125
+ } from "./chunk-VMSV4EYS.js";
126
126
  import {
127
127
  IntentStatusResponseSchema,
128
128
  apiUrl,
@@ -132,7 +132,7 @@ import {
132
132
  keystoreExists,
133
133
  loadKeystore,
134
134
  selectedNetwork
135
- } from "./chunk-75LS6XS6.js";
135
+ } from "./chunk-PGXPZFVY.js";
136
136
  import {
137
137
  AGENT_VIEW_VERSION,
138
138
  formatUsdc
@@ -2269,11 +2269,11 @@ function registerBudgetUi(pi2, channel) {
2269
2269
  ctx.ui.notify("Buying compute credit needs the interactive session", "error");
2270
2270
  return;
2271
2271
  }
2272
- const approved = await ctx.ui.confirm(
2272
+ const approved2 = await ctx.ui.confirm(
2273
2273
  "Buy compute credit",
2274
2274
  `Buy $${size.amountUsd} of compute credit (${size.credits} credits at $${offer.usdPerCredit} each) in USDC from your compute allocation? Its daily and monthly caps apply.`
2275
2275
  );
2276
- if (!approved) return;
2276
+ if (!approved2) return;
2277
2277
  const bought = await channel.buyCredits(size.amountUsd);
2278
2278
  ctx.ui.notify(
2279
2279
  `Bought ${bought?.purchase?.credits ?? size.credits} credits; ${bought?.balance?.availableCredits ?? "?"} available`,
@@ -2533,9 +2533,9 @@ var ChannelXgateTransport = class _ChannelXgateTransport {
2533
2533
  * The person's answer to an action's dialog. Not abortable from the tool call: once sent, the
2534
2534
  * controller finishes (and journals) what it started.
2535
2535
  */
2536
- async marketActionAnswer(actionId, approved) {
2536
+ async marketActionAnswer(actionId, approved2) {
2537
2537
  return (await this.view(
2538
- { op: "market_action", phase: approved ? "confirm" : "decline", actionId },
2538
+ { op: "market_action", phase: approved2 ? "confirm" : "decline", actionId },
2539
2539
  void 0,
2540
2540
  ACTION_TIMEOUT_MS
2541
2541
  )).value;
@@ -3149,13 +3149,13 @@ function marketActionToolDefinitions(channel) {
3149
3149
  } catch {
3150
3150
  choice = void 0;
3151
3151
  }
3152
- const approved = choice === proposal.approveLabel && !signal?.aborted;
3152
+ const approved2 = choice === proposal.approveLabel && !signal?.aborted;
3153
3153
  let value;
3154
3154
  try {
3155
- value = await channel.marketActionAnswer(proposal.actionId, approved);
3155
+ value = await channel.marketActionAnswer(proposal.actionId, approved2);
3156
3156
  } catch (error) {
3157
3157
  const code = errorCode3(error);
3158
- if (!approved) {
3158
+ if (!approved2) {
3159
3159
  ctx.ui.notify("Declined. Nothing was signed or sent.", "info");
3160
3160
  throw new Error(actionFailure("declined_nothing_sent"));
3161
3161
  }
@@ -3333,6 +3333,34 @@ function registerMarketTools(pi2, channel) {
3333
3333
  for (const tool of marketToolDefinitions(channel)) pi2.registerTool(tool);
3334
3334
  }
3335
3335
 
3336
+ // src/lib/agent/provider-guard.ts
3337
+ init_cjs_shims();
3338
+ var XGATE_PROVIDER = "xgate";
3339
+ var XGATE_ONLY_TEXT = "taskmarket agent offers only the xgate models your policy approves";
3340
+ var NO_APPROVED_MODEL_TEXT = `${XGATE_ONLY_TEXT}; choose one with /model before the next turn`;
3341
+ function approved(model) {
3342
+ return model?.provider === XGATE_PROVIDER;
3343
+ }
3344
+ function registerProviderGuard(pi2) {
3345
+ pi2.on("model_select", async (event, ctx) => {
3346
+ if (approved(event.model)) return;
3347
+ const fallback = approved(event.previousModel) ? event.previousModel : ctx.modelRegistry.getAvailable().find(approved);
3348
+ const restored = fallback ? await pi2.setModel(fallback) : false;
3349
+ ctx.ui.notify(restored ? XGATE_ONLY_TEXT : NO_APPROVED_MODEL_TEXT, "warning");
3350
+ });
3351
+ pi2.on("input", async (_event, ctx) => {
3352
+ if (approved(ctx.model)) return { action: "continue" };
3353
+ ctx.ui.notify(NO_APPROVED_MODEL_TEXT, "error");
3354
+ return { action: "handled" };
3355
+ });
3356
+ pi2.on("before_provider_request", async (_event, ctx) => {
3357
+ if (approved(ctx.model)) return void 0;
3358
+ ctx.abort();
3359
+ ctx.ui.notify(NO_APPROVED_MODEL_TEXT, "error");
3360
+ return void 0;
3361
+ });
3362
+ }
3363
+
3336
3364
  // src/lib/agent/sync-ui.ts
3337
3365
  init_cjs_shims();
3338
3366
 
@@ -3569,11 +3597,6 @@ async function taskmarketXgate(pi2) {
3569
3597
  registerMarketTools(pi2, channel);
3570
3598
  registerMarketActionTools(pi2, channel);
3571
3599
  registerTaskRunUi(pi2, channel);
3572
- pi2.on("model_select", async (event, ctx) => {
3573
- if (event.model.provider === "xgate") return;
3574
- const fallback = event.previousModel?.provider === "xgate" ? event.previousModel : ctx.modelRegistry.getAvailable().find((model) => model.provider === "xgate");
3575
- if (fallback) await pi2.setModel(fallback);
3576
- ctx.ui.notify("taskmarket agent offers only the xgate models your policy approves", "warning");
3577
- });
3600
+ registerProviderGuard(pi2);
3578
3601
  }
3579
3602
  module.exports = module.exports.default;
@@ -3,14 +3,14 @@ import {
3
3
  channelView,
4
4
  openAgentChannels,
5
5
  selectChannel
6
- } from "./chunk-MO5KMUTL.js";
6
+ } from "./chunk-7Y7IOFKT.js";
7
7
  import {
8
8
  BASE_CHANNEL_RAIL_ID,
9
9
  X402_INVOCATION_ID_PATTERN,
10
10
  getX402JournalPath,
11
11
  listX402Payments
12
- } from "./chunk-S4A6V3J3.js";
13
- import "./chunk-75LS6XS6.js";
12
+ } from "./chunk-VMSV4EYS.js";
13
+ import "./chunk-PGXPZFVY.js";
14
14
  import {
15
15
  AGENT_VIEW_VERSION,
16
16
  LOST_RESPONSE_TEXT,
@@ -7,13 +7,13 @@ import {
7
7
  statusLines,
8
8
  syncLines,
9
9
  taskLines
10
- } from "./chunk-2QJMUHDT.js";
11
- import "./chunk-L6ZVRENW.js";
12
- import "./chunk-64HQ7ZF2.js";
13
- import "./chunk-W7CXEYST.js";
14
- import "./chunk-MO5KMUTL.js";
15
- import "./chunk-S4A6V3J3.js";
16
- import "./chunk-75LS6XS6.js";
10
+ } from "./chunk-U5F3Z2BR.js";
11
+ import "./chunk-RKGRXJ5X.js";
12
+ import "./chunk-MJR2CZWZ.js";
13
+ import "./chunk-6KJ5EFBN.js";
14
+ import "./chunk-7Y7IOFKT.js";
15
+ import "./chunk-VMSV4EYS.js";
16
+ import "./chunk-PGXPZFVY.js";
17
17
  import "./chunk-EB6OJBF5.js";
18
18
  import "./chunk-YM4S6IE4.js";
19
19
  import "./chunk-S7SJMJ2I.js";
@@ -11,9 +11,10 @@ import {
11
11
  savedWorkspace,
12
12
  summarize,
13
13
  unsavedPaths
14
- } from "./chunk-ESPAXW2P.js";
14
+ } from "./chunk-3HCDMHXW.js";
15
15
  import {
16
16
  BrokerConnector,
17
+ SandboxUnavailableError,
17
18
  SshSandboxBackend,
18
19
  applyChanges,
19
20
  captureProblem,
@@ -26,11 +27,11 @@ import {
26
27
  releaseClaim,
27
28
  unresolvedCount,
28
29
  updateSyncState
29
- } from "./chunk-64HQ7ZF2.js";
30
+ } from "./chunk-MJR2CZWZ.js";
30
31
  import {
31
32
  apiUrl,
32
33
  loadKeystore
33
- } from "./chunk-75LS6XS6.js";
34
+ } from "./chunk-PGXPZFVY.js";
34
35
  import {
35
36
  AgentLaunchError
36
37
  } from "./chunk-YM4S6IE4.js";
@@ -41,6 +42,10 @@ import { randomUUID } from "crypto";
41
42
  import { promises as fs } from "fs";
42
43
  var NONE = { clean: 0, conflict: 0, blocked: 0 };
43
44
  var RECOVER_TIMEOUT_MS = 3e5;
45
+ var RECOVER_BUSY_WAITS_MS = [5e3, 1e4, 2e4];
46
+ function sandboxBusy(error) {
47
+ return error instanceof SandboxUnavailableError && /\(409\): busy\b/.test(error.reason);
48
+ }
44
49
  async function brokerSandbox(sandboxId) {
45
50
  const keystore = await loadKeystore();
46
51
  const broker = new BrokerConnector({
@@ -173,14 +178,31 @@ async function pullClaimed(options, io, project, initial) {
173
178
  );
174
179
  }
175
180
  let opened;
176
- try {
177
- opened = await (io.openSandbox ?? brokerSandbox)(target.sandboxId);
178
- await opened.backend.connect();
179
- } catch (error) {
180
- throw new AgentLaunchError(
181
- "sync_recover_unavailable",
182
- `Sandbox ${target.sandboxId} cannot be reached (${error.message}); if it is gone, its changes are too. Drop the record with taskmarket agent pull --discard.`
183
- );
181
+ const waits = [...RECOVER_BUSY_WAITS_MS];
182
+ while (!opened) {
183
+ let attempt;
184
+ try {
185
+ attempt = await (io.openSandbox ?? brokerSandbox)(target.sandboxId);
186
+ await attempt.backend.connect();
187
+ opened = attempt;
188
+ } catch (error) {
189
+ await attempt?.close().catch(() => void 0);
190
+ if (!sandboxBusy(error)) {
191
+ throw new AgentLaunchError(
192
+ "sync_recover_unavailable",
193
+ `Sandbox ${target.sandboxId} cannot be reached (${error.message}); if it is gone, its changes are too. Drop the record with taskmarket agent pull --discard.`
194
+ );
195
+ }
196
+ const wait = waits.shift();
197
+ if (wait === void 0) {
198
+ throw new AgentLaunchError(
199
+ "sync_recover_busy",
200
+ `Sandbox ${target.sandboxId} is still busy with another request, so its changes are still there. Run taskmarket agent pull --recover again in a minute; do not discard them.`
201
+ );
202
+ }
203
+ io.say([`Sandbox ${target.sandboxId} is busy; trying again in ${wait / 1e3} s.`]);
204
+ await (io.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))))(wait);
205
+ }
184
206
  }
185
207
  let outcome;
186
208
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucid-agents/taskmarket",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "taskmarket": "./dist/index.js"