@rely-ai/caliber 1.20.0-dev.1773696964 → 1.20.0-dev.1773698265

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/bin.js +74 -33
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -5827,18 +5827,21 @@ function trackLearnSessionAnalyzed(props) {
5827
5827
  had_learnings_available: props.hadLearningsAvailable,
5828
5828
  learnings_available_count: props.learningsAvailableCount,
5829
5829
  new_learnings_produced: props.newLearningsProduced,
5830
- waste_tokens: props.wasteTokens
5830
+ waste_tokens: props.wasteTokens,
5831
+ waste_seconds: props.wasteSeconds
5831
5832
  });
5832
5833
  }
5833
5834
  function trackLearnROISnapshot(props) {
5834
5835
  trackEvent("learn_roi_snapshot", {
5835
5836
  total_waste_tokens: props.totalWasteTokens,
5837
+ total_waste_seconds: props.totalWasteSeconds,
5836
5838
  total_sessions: props.totalSessions,
5837
5839
  sessions_with_learnings: props.sessionsWithLearnings,
5838
5840
  sessions_without_learnings: props.sessionsWithoutLearnings,
5839
5841
  failure_rate_with_learnings: props.failureRateWithLearnings,
5840
5842
  failure_rate_without_learnings: props.failureRateWithoutLearnings,
5841
5843
  estimated_savings_tokens: props.estimatedSavingsTokens,
5844
+ estimated_savings_seconds: props.estimatedSavingsSeconds,
5842
5845
  learning_count: props.learningCount
5843
5846
  });
5844
5847
  }
@@ -6535,7 +6538,7 @@ function validateSetup(setup, dir, checkExists = existsSync9) {
6535
6538
  }
6536
6539
  function buildFeedbackMessage(issues) {
6537
6540
  const lines = [
6538
- "Your generated config has these scoring issues. Fix ONLY these \u2014 do not rewrite, restructure, or make cosmetic changes to anything else:\n"
6541
+ "Fix ONLY these scoring issues \u2014 do not rewrite, restructure, or make cosmetic changes:\n"
6539
6542
  ];
6540
6543
  for (let i = 0; i < issues.length; i++) {
6541
6544
  const issue = issues[i];
@@ -6543,7 +6546,6 @@ function buildFeedbackMessage(issues) {
6543
6546
  lines.push(` Action: ${issue.fixInstruction}
6544
6547
  `);
6545
6548
  }
6546
- lines.push("Return the complete updated AgentSetup JSON with only these fixes applied.");
6547
6549
  return lines.join("\n");
6548
6550
  }
6549
6551
  function countIssuePoints(issues) {
@@ -6576,12 +6578,20 @@ async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
6576
6578
  const issueNames = issues.map((i) => i.check).join(", ");
6577
6579
  callbacks.onStatus(`Fixing ${issues.length} scoring issue${issues.length === 1 ? "" : "s"}: ${issueNames}...`);
6578
6580
  }
6579
- const patched = await applyTargetedFixes(currentSetup, issues, sessionHistory);
6580
- if (!patched) {
6581
+ const refined = await applyTargetedFixes(currentSetup, issues);
6582
+ if (!refined) {
6581
6583
  if (callbacks?.onStatus) callbacks.onStatus("Refinement failed, keeping current setup");
6582
6584
  return bestSetup;
6583
6585
  }
6584
- currentSetup = patched;
6586
+ sessionHistory.push({
6587
+ role: "user",
6588
+ content: `Fix scoring issues: ${issues.map((i) => i.check).join(", ")}`
6589
+ });
6590
+ sessionHistory.push({
6591
+ role: "assistant",
6592
+ content: `Applied scoring fixes for: ${issues.map((i) => i.check).join(", ")}`
6593
+ });
6594
+ currentSetup = refined;
6585
6595
  }
6586
6596
  const finalIssues = validateSetup(currentSetup, dir, cachedExists);
6587
6597
  const finalLostPoints = countIssuePoints(finalIssues);
@@ -6590,41 +6600,44 @@ async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
6590
6600
  }
6591
6601
  return bestSetup;
6592
6602
  }
6593
- async function applyTargetedFixes(setup, issues, sessionHistory) {
6603
+ async function applyTargetedFixes(setup, issues) {
6594
6604
  const { claudeMd, agentsMd } = extractConfigContent(setup);
6595
- const content = claudeMd ?? agentsMd;
6596
- if (!content) return null;
6605
+ const targets = [];
6606
+ if (claudeMd) targets.push({ key: "claudeMd", label: "CLAUDE.md", content: claudeMd });
6607
+ if (agentsMd) targets.push({ key: "agentsMd", label: "AGENTS.md", content: agentsMd });
6608
+ if (targets.length === 0) return null;
6597
6609
  const feedbackMessage = buildFeedbackMessage(issues);
6598
- const contentLabel = claudeMd ? "CLAUDE.md" : "AGENTS.md";
6610
+ const contentBlock = targets.map(
6611
+ (t) => `### ${t.label}
6612
+ \`\`\`markdown
6613
+ ${t.content}
6614
+ \`\`\``
6615
+ ).join("\n\n");
6599
6616
  const prompt = [
6600
- `Here is the current ${contentLabel} content:
6601
- `,
6602
- "```markdown",
6603
- content,
6604
- "```\n",
6617
+ "Here are the config files with scoring issues:\n",
6618
+ contentBlock,
6619
+ "\n",
6605
6620
  feedbackMessage,
6606
6621
  `
6607
- Return ONLY the fixed ${contentLabel} content as raw markdown (no JSON, no code fences). Apply the fixes above and nothing else \u2014 do not rewrite, restructure, or make cosmetic changes.`
6622
+ Return ONLY the fixed content as a JSON object with keys ${targets.map((t) => `"${t.key}"`).join(", ")}. Each value is the fixed markdown string. No code fences, no explanations.`
6608
6623
  ].join("\n");
6609
6624
  try {
6610
6625
  const raw = await llmCall({
6611
- system: `You fix scoring issues in AI agent configuration files. Return only the fixed markdown content \u2014 no explanations, no JSON wrappers, no code fences.`,
6626
+ system: "You fix scoring issues in AI agent configuration files. Return only a JSON object with the fixed content \u2014 no explanations, no code fences.",
6612
6627
  prompt,
6613
6628
  maxTokens: 8e3
6614
6629
  });
6615
- const fixed = stripMarkdownFences(raw).trim();
6616
- if (!fixed || fixed.length < 50) return null;
6617
- const patched = JSON.parse(JSON.stringify(setup));
6618
- if (claudeMd) {
6619
- patched.claude.claudeMd = fixed;
6620
- } else {
6621
- patched.codex.agentsMd = fixed;
6630
+ const cleaned = stripMarkdownFences(raw);
6631
+ const jsonStart = cleaned.indexOf("{");
6632
+ const jsonToParse = jsonStart !== -1 ? cleaned.slice(jsonStart) : cleaned;
6633
+ const fixes = JSON.parse(jsonToParse);
6634
+ const patched = structuredClone(setup);
6635
+ for (const target of targets) {
6636
+ if (typeof fixes[target.key] === "string" && fixes[target.key].length > 50) {
6637
+ const parent = target.key === "claudeMd" ? patched.claude : patched.codex;
6638
+ if (parent) parent[target.key] = fixes[target.key];
6639
+ }
6622
6640
  }
6623
- sessionHistory.push({ role: "user", content: feedbackMessage });
6624
- sessionHistory.push({
6625
- role: "assistant",
6626
- content: `Applied scoring fixes for: ${issues.map((i) => i.check).join(", ")}`
6627
- });
6628
6641
  return patched;
6629
6642
  } catch {
6630
6643
  return null;
@@ -9123,20 +9136,28 @@ ${eventsText}`;
9123
9136
  }
9124
9137
  function calculateSessionWaste(events) {
9125
9138
  let totalWasteTokens = 0;
9139
+ let totalWasteSeconds = 0;
9126
9140
  let failureCount = 0;
9127
9141
  let promptCount = 0;
9128
- for (const event of events) {
9142
+ for (let i = 0; i < events.length; i++) {
9143
+ const event = events[i];
9129
9144
  if (event.hook_event_name === "PostToolUseFailure") {
9130
9145
  const te = event;
9131
9146
  const inputStr = JSON.stringify(te.tool_input);
9132
9147
  const responseStr = typeof te.tool_response === "object" && "_truncated" in te.tool_response ? String(te.tool_response._truncated) : JSON.stringify(te.tool_response);
9133
9148
  totalWasteTokens += estimateTokens(inputStr + responseStr);
9134
9149
  failureCount++;
9150
+ if (i > 0) {
9151
+ const prev = new Date(events[i - 1].timestamp).getTime();
9152
+ const curr = new Date(event.timestamp).getTime();
9153
+ const elapsed = (curr - prev) / 1e3;
9154
+ if (elapsed > 0 && elapsed < 600) totalWasteSeconds += elapsed;
9155
+ }
9135
9156
  } else if (event.hook_event_name === "UserPromptSubmit") {
9136
9157
  promptCount++;
9137
9158
  }
9138
9159
  }
9139
- return { totalWasteTokens, failureCount, promptCount };
9160
+ return { totalWasteTokens, totalWasteSeconds, failureCount, promptCount };
9140
9161
  }
9141
9162
 
9142
9163
  // src/commands/learn.ts
@@ -9148,11 +9169,13 @@ import fs32 from "fs";
9148
9169
  import path26 from "path";
9149
9170
  var DEFAULT_TOTALS = {
9150
9171
  totalWasteTokens: 0,
9172
+ totalWasteSeconds: 0,
9151
9173
  totalSessionsWithLearnings: 0,
9152
9174
  totalSessionsWithoutLearnings: 0,
9153
9175
  totalFailuresWithLearnings: 0,
9154
9176
  totalFailuresWithoutLearnings: 0,
9155
9177
  estimatedSavingsTokens: 0,
9178
+ estimatedSavingsSeconds: 0,
9156
9179
  firstSessionTimestamp: "",
9157
9180
  lastSessionTimestamp: ""
9158
9181
  };
@@ -9177,11 +9200,13 @@ function writeROIStats(stats) {
9177
9200
  function recalculateTotals(stats) {
9178
9201
  const totals = stats.totals;
9179
9202
  totals.totalWasteTokens = stats.learnings.reduce((sum, l) => sum + l.wasteTokens, 0);
9203
+ totals.totalWasteSeconds = 0;
9180
9204
  totals.totalSessionsWithLearnings = 0;
9181
9205
  totals.totalSessionsWithoutLearnings = 0;
9182
9206
  totals.totalFailuresWithLearnings = 0;
9183
9207
  totals.totalFailuresWithoutLearnings = 0;
9184
9208
  for (const s of stats.sessions) {
9209
+ totals.totalWasteSeconds += s.wasteSeconds || 0;
9185
9210
  if (s.hadLearningsAvailable) {
9186
9211
  totals.totalSessionsWithLearnings++;
9187
9212
  totals.totalFailuresWithLearnings += s.failureCount;
@@ -9191,6 +9216,7 @@ function recalculateTotals(stats) {
9191
9216
  }
9192
9217
  }
9193
9218
  totals.estimatedSavingsTokens = totals.totalWasteTokens * totals.totalSessionsWithLearnings;
9219
+ totals.estimatedSavingsSeconds = totals.totalWasteSeconds * totals.totalSessionsWithLearnings;
9194
9220
  if (stats.sessions.length > 0) {
9195
9221
  totals.firstSessionTimestamp = stats.sessions[0].timestamp;
9196
9222
  totals.lastSessionTimestamp = stats.sessions[stats.sessions.length - 1].timestamp;
@@ -9214,6 +9240,12 @@ function recordSession(summary, learnings) {
9214
9240
  writeROIStats(stats);
9215
9241
  return stats;
9216
9242
  }
9243
+ function formatDuration(seconds) {
9244
+ if (seconds < 60) return `${Math.round(seconds)}s`;
9245
+ const mins = Math.floor(seconds / 60);
9246
+ const secs = Math.round(seconds % 60);
9247
+ return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;
9248
+ }
9217
9249
  function formatROISummary(stats) {
9218
9250
  const t = stats.totals;
9219
9251
  const totalSessions = t.totalSessionsWithLearnings + t.totalSessionsWithoutLearnings;
@@ -9222,7 +9254,7 @@ function formatROISummary(stats) {
9222
9254
  lines.push(` Sessions tracked: ${totalSessions}`);
9223
9255
  lines.push(` Sessions with learnings: ${t.totalSessionsWithLearnings}`);
9224
9256
  if (t.totalSessionsWithoutLearnings > 0) {
9225
- const rateWithout = t.totalSessionsWithoutLearnings > 0 ? (t.totalFailuresWithoutLearnings / t.totalSessionsWithoutLearnings).toFixed(1) : "0.0";
9257
+ const rateWithout = (t.totalFailuresWithoutLearnings / t.totalSessionsWithoutLearnings).toFixed(1);
9226
9258
  lines.push(` Failure rate (no learnings): ${rateWithout}/session`);
9227
9259
  }
9228
9260
  if (t.totalSessionsWithLearnings > 0) {
@@ -9235,6 +9267,11 @@ function formatROISummary(stats) {
9235
9267
  if (t.estimatedSavingsTokens > 0) {
9236
9268
  lines.push(` Estimated savings: ~${t.estimatedSavingsTokens.toLocaleString()} tokens`);
9237
9269
  }
9270
+ if (t.estimatedSavingsSeconds > 0) {
9271
+ lines.push(` Time saved: at least ${formatDuration(t.estimatedSavingsSeconds)} (not counting human frustration)`);
9272
+ } else if (t.totalWasteSeconds > 0) {
9273
+ lines.push(` Time wasted on failures: ${formatDuration(t.totalWasteSeconds)} (and counting)`);
9274
+ }
9238
9275
  return lines.join("\n");
9239
9276
  }
9240
9277
 
@@ -9363,6 +9400,7 @@ async function learnFinalizeCommand(options) {
9363
9400
  eventCount: events.length,
9364
9401
  failureCount: waste.failureCount,
9365
9402
  promptCount: waste.promptCount,
9403
+ wasteSeconds: Math.round(waste.totalWasteSeconds),
9366
9404
  hadLearningsAvailable: hadLearnings,
9367
9405
  learningsCount: existingLearnedItems,
9368
9406
  newLearningsProduced
@@ -9375,18 +9413,21 @@ async function learnFinalizeCommand(options) {
9375
9413
  hadLearningsAvailable: hadLearnings,
9376
9414
  learningsAvailableCount: existingLearnedItems,
9377
9415
  newLearningsProduced,
9378
- wasteTokens: waste.totalWasteTokens
9416
+ wasteTokens: waste.totalWasteTokens,
9417
+ wasteSeconds: Math.round(waste.totalWasteSeconds)
9379
9418
  });
9380
9419
  const t = roiStats.totals;
9381
9420
  const totalSessions = t.totalSessionsWithLearnings + t.totalSessionsWithoutLearnings;
9382
9421
  trackLearnROISnapshot({
9383
9422
  totalWasteTokens: t.totalWasteTokens,
9423
+ totalWasteSeconds: t.totalWasteSeconds,
9384
9424
  totalSessions,
9385
9425
  sessionsWithLearnings: t.totalSessionsWithLearnings,
9386
9426
  sessionsWithoutLearnings: t.totalSessionsWithoutLearnings,
9387
9427
  failureRateWithLearnings: t.totalSessionsWithLearnings > 0 ? t.totalFailuresWithLearnings / t.totalSessionsWithLearnings : 0,
9388
9428
  failureRateWithoutLearnings: t.totalSessionsWithoutLearnings > 0 ? t.totalFailuresWithoutLearnings / t.totalSessionsWithoutLearnings : 0,
9389
9429
  estimatedSavingsTokens: t.estimatedSavingsTokens,
9430
+ estimatedSavingsSeconds: t.estimatedSavingsSeconds,
9390
9431
  learningCount: roiStats.learnings.length
9391
9432
  });
9392
9433
  if (t.estimatedSavingsTokens > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.20.0-dev.1773696964",
3
+ "version": "1.20.0-dev.1773698265",
4
4
  "description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
5
5
  "type": "module",
6
6
  "bin": {