@whisperr/wizard 0.1.11 → 0.1.12

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/dist/index.js +51 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25,7 +25,13 @@ function resolveConfig(flags = {}) {
25
25
  llmBaseUrl,
26
26
  model: flags.model ?? process.env.WHISPERR_WIZARD_MODEL ?? DEFAULT_MODEL,
27
27
  effort: resolveEffort(),
28
- maxTurns: Number(process.env.WHISPERR_WIZARD_MAX_TURNS ?? 55),
28
+ // Cost is the real limiter (budgetUsd below). maxTurns is only a high safety
29
+ // backstop against a stuck loop — it should NOT bind on a normal run. (It
30
+ // used to be 55, which guillotined high-effort multi-phase runs mid-work.)
31
+ maxTurns: Number(process.env.WHISPERR_WIZARD_MAX_TURNS) || 200,
32
+ // Hard ceiling on TOTAL spend across all phases. If hit, the run stops
33
+ // cleanly and keeps whatever already landed. Real runs finish well under it.
34
+ budgetUsd: Number(process.env.WHISPERR_WIZARD_BUDGET_USD) || 10,
29
35
  directAnthropicKey,
30
36
  offline
31
37
  };
@@ -1208,14 +1214,21 @@ async function runIntegrationAgent(opts) {
1208
1214
  repoPath,
1209
1215
  model: config.model,
1210
1216
  effort: config.effort,
1211
- maxTurns: 35,
1217
+ maxTurns: 50,
1218
+ budgetUsd: config.budgetUsd - costUsd,
1212
1219
  progress
1213
1220
  });
1214
1221
  costUsd += core.costUsd;
1215
1222
  if (core.summary) summaries.push(`Core setup:
1216
1223
  ${core.summary}`);
1224
+ const BUDGET_FLOOR = 0.25;
1217
1225
  let eventsComplete = true;
1218
- if (manifest.events.length > 0) {
1226
+ if (manifest.events.length > 0 && config.budgetUsd - costUsd <= BUDGET_FLOOR) {
1227
+ eventsComplete = false;
1228
+ summaries.push(
1229
+ "Events: skipped \u2014 the spend limit was reached during core setup. Re-run with a higher WHISPERR_WIZARD_BUDGET_USD to instrument events."
1230
+ );
1231
+ } else if (manifest.events.length > 0) {
1219
1232
  progress?.onPhase?.("Instrumenting your events");
1220
1233
  const eventsPrompt = [
1221
1234
  `The Whisperr ${playbook.target.displayName} SDK is already installed and`,
@@ -1241,6 +1254,7 @@ ${core.summary}`);
1241
1254
  model: config.model,
1242
1255
  effort: config.effort,
1243
1256
  maxTurns: config.maxTurns,
1257
+ budgetUsd: config.budgetUsd - costUsd,
1244
1258
  progress
1245
1259
  });
1246
1260
  costUsd += events.costUsd;
@@ -1248,7 +1262,7 @@ ${core.summary}`);
1248
1262
  if (events.summary) summaries.push(`Events:
1249
1263
  ${events.summary}`);
1250
1264
  }
1251
- if (core.ok) {
1265
+ if (core.ok && config.budgetUsd - costUsd > BUDGET_FLOOR) {
1252
1266
  progress?.onPhase?.("Reviewing & correcting placements");
1253
1267
  const reviewPrompt = [
1254
1268
  `You wired the Whisperr ${playbook.target.displayName} SDK into this repo.`,
@@ -1279,7 +1293,8 @@ ${events.summary}`);
1279
1293
  repoPath,
1280
1294
  model: config.model,
1281
1295
  effort: config.effort,
1282
- maxTurns: 25,
1296
+ maxTurns: 40,
1297
+ budgetUsd: config.budgetUsd - costUsd,
1283
1298
  progress
1284
1299
  });
1285
1300
  costUsd += review.costUsd;
@@ -1294,8 +1309,12 @@ ${review.summary}`);
1294
1309
  eventsComplete
1295
1310
  };
1296
1311
  }
1312
+ function isLimitStop(err) {
1313
+ const msg = err?.message ?? "";
1314
+ return /max(imum)?[\s_-]*(turn|budget)|budget.*exceeded|number of turns/i.test(msg);
1315
+ }
1297
1316
  async function runPass(opts) {
1298
- const { prompt, systemPrompt: systemPrompt9, repoPath, model, effort, maxTurns, progress } = opts;
1317
+ const { prompt, systemPrompt: systemPrompt9, repoPath, model, effort, maxTurns, budgetUsd, progress } = opts;
1299
1318
  let summary = "";
1300
1319
  let costUsd = 0;
1301
1320
  let ok = false;
@@ -1314,23 +1333,36 @@ async function runPass(opts) {
1314
1333
  allowedTools: ["Read", "Edit", "Write", "Bash", "Glob", "Grep"],
1315
1334
  permissionMode: "bypassPermissions",
1316
1335
  maxTurns,
1336
+ // Native SDK hard cost cap. Stops this pass with an `error_max_budget_usd`
1337
+ // result once spend exceeds the remaining budget — this, not maxTurns, is
1338
+ // the real limiter. Omitted when there's no positive budget left.
1339
+ ...budgetUsd && budgetUsd > 0 ? { maxBudgetUsd: budgetUsd } : {},
1317
1340
  settingSources: []
1318
1341
  }
1319
1342
  });
1320
- for await (const message of response) {
1321
- if (message.type === "assistant") {
1322
- for (const block of message.message?.content ?? []) {
1323
- if (isTextBlock(block) && block.text?.trim()) {
1324
- progress?.onActivity?.(firstLine(block.text));
1325
- } else if (isToolUseBlock(block)) {
1326
- progress?.onActivity?.(describeToolUse(block));
1343
+ try {
1344
+ for await (const message of response) {
1345
+ if (message.type === "assistant") {
1346
+ for (const block of message.message?.content ?? []) {
1347
+ if (isTextBlock(block) && block.text?.trim()) {
1348
+ progress?.onActivity?.(firstLine(block.text));
1349
+ } else if (isToolUseBlock(block)) {
1350
+ progress?.onActivity?.(describeToolUse(block));
1351
+ }
1327
1352
  }
1353
+ } else if (message.type === "result") {
1354
+ ok = message.subtype === "success";
1355
+ const sub = message.subtype ?? "";
1356
+ maxedOut = sub.includes("max_turns") || sub.includes("max_budget");
1357
+ costUsd = message.total_cost_usd ?? 0;
1358
+ summary = message.result ?? extractLastText(message) ?? summary;
1328
1359
  }
1329
- } else if (message.type === "result") {
1330
- ok = message.subtype === "success";
1331
- maxedOut = (message.subtype ?? "").includes("max_turns");
1332
- costUsd = message.total_cost_usd ?? 0;
1333
- summary = message.result ?? extractLastText(message) ?? summary;
1360
+ }
1361
+ } catch (err) {
1362
+ if (isLimitStop(err)) {
1363
+ maxedOut = true;
1364
+ } else {
1365
+ throw err;
1334
1366
  }
1335
1367
  }
1336
1368
  return { summary, costUsd, ok, maxedOut };
@@ -1890,7 +1922,7 @@ async function main() {
1890
1922
  return;
1891
1923
  }
1892
1924
  if ("version" in parsed) {
1893
- console.log("0.1.11");
1925
+ console.log("0.1.12");
1894
1926
  return;
1895
1927
  }
1896
1928
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whisperr/wizard",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Whisperr Wizard — one command to integrate the Whisperr SDK into your app. Authenticates with your onboarded account and uses an AI coding agent to wire up identify() and your business events automatically.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,