cascade-ai 0.12.5 → 0.12.7

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.
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import cron from 'node-cron';
35
35
 
36
36
 
37
37
  // src/constants.ts
38
- var CASCADE_VERSION = "0.12.5";
38
+ var CASCADE_VERSION = "0.12.7";
39
39
  var CASCADE_CONFIG_DIR = ".cascade";
40
40
  var CASCADE_MD_FILE = "CASCADE.md";
41
41
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -104,6 +104,30 @@ var MODELS = {
104
104
  supportsStreaming: true,
105
105
  isLocal: false
106
106
  },
107
+ "claude-opus-4-8": {
108
+ id: "claude-opus-4-8",
109
+ name: "Claude Opus 4.8",
110
+ provider: "anthropic",
111
+ contextWindow: 2e5,
112
+ isVisionCapable: true,
113
+ inputCostPer1kTokens: 0.015,
114
+ outputCostPer1kTokens: 0.075,
115
+ maxOutputTokens: 32e3,
116
+ supportsStreaming: true,
117
+ isLocal: false
118
+ },
119
+ "claude-sonnet-4-6": {
120
+ id: "claude-sonnet-4-6",
121
+ name: "Claude Sonnet 4.6",
122
+ provider: "anthropic",
123
+ contextWindow: 2e5,
124
+ isVisionCapable: true,
125
+ inputCostPer1kTokens: 3e-3,
126
+ outputCostPer1kTokens: 0.015,
127
+ maxOutputTokens: 16e3,
128
+ supportsStreaming: true,
129
+ isLocal: false
130
+ },
107
131
  // OpenAI
108
132
  "gpt-4o": {
109
133
  id: "gpt-4o",
@@ -365,6 +389,24 @@ var PROVIDER_DISPLAY_NAMES = {
365
389
  ollama: "Ollama (Local)"
366
390
  };
367
391
 
392
+ // src/utils/cost.ts
393
+ function resolveModelPricing(model) {
394
+ let input = model.inputCostPer1kTokens;
395
+ let output = model.outputCostPer1kTokens;
396
+ if (input === 0 && output === 0 && model.id && !model.isLocal) {
397
+ const known = Object.values(MODELS).find((m) => m.id === model.id && !m.isLocal);
398
+ if (known) {
399
+ input = known.inputCostPer1kTokens;
400
+ output = known.outputCostPer1kTokens;
401
+ }
402
+ }
403
+ return { input, output };
404
+ }
405
+ function calculateCost(inputTokens, outputTokens, model) {
406
+ const { input, output } = resolveModelPricing(model);
407
+ return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
408
+ }
409
+
368
410
  // src/providers/base.ts
369
411
  var BaseProvider = class {
370
412
  config;
@@ -380,7 +422,7 @@ var BaseProvider = class {
380
422
  return this.model.isVisionCapable;
381
423
  }
382
424
  estimateCost(inputTokens, outputTokens) {
383
- return inputTokens / 1e3 * this.model.inputCostPer1kTokens + outputTokens / 1e3 * this.model.outputCostPer1kTokens;
425
+ return calculateCost(inputTokens, outputTokens, this.model);
384
426
  }
385
427
  makeUsage(inputTokens, outputTokens) {
386
428
  return {
@@ -1669,11 +1711,6 @@ var LocalRequestQueue = class {
1669
1711
  }
1670
1712
  };
1671
1713
 
1672
- // src/utils/cost.ts
1673
- function calculateCost(inputTokens, outputTokens, model) {
1674
- return inputTokens / 1e3 * model.inputCostPer1kTokens + outputTokens / 1e3 * model.outputCostPer1kTokens;
1675
- }
1676
-
1677
1714
  // src/utils/retry.ts
1678
1715
  var CascadeCancelledError = class extends Error {
1679
1716
  constructor(reason) {
@@ -3252,8 +3289,9 @@ var T3Worker = class extends BaseTier {
3252
3289
  const depOutputs = [];
3253
3290
  for (const depId of assignment.dependsOn) {
3254
3291
  try {
3255
- const dep = await this.peerBus.waitFor(depId);
3292
+ const dep = await this.peerBus.waitFor(depId, 6e4);
3256
3293
  if (dep.status === "FAILED" || dep.status === "ESCALATED") {
3294
+ this.peerBus.publish(this.id, assignment.subtaskId, `Blocked by failed dependency: ${depId}`, "FAILED");
3257
3295
  return this.buildResult(
3258
3296
  "ESCALATED",
3259
3297
  `Dependency ${depId} failed \u2014 cannot proceed`,
@@ -3265,6 +3303,7 @@ var T3Worker = class extends BaseTier {
3265
3303
  depOutputs.push(`[From ${dep.fromId} - ${dep.subtaskId}]:
3266
3304
  ${dep.output}`);
3267
3305
  } catch (err) {
3306
+ this.peerBus.publish(this.id, assignment.subtaskId, `Dependency timeout: ${depId}`, "FAILED");
3268
3307
  return this.buildResult(
3269
3308
  "ESCALATED",
3270
3309
  `Dependency timeout: ${depId}`,
@@ -4963,6 +5002,16 @@ function parseFirstJsonObject(input) {
4963
5002
  }
4964
5003
 
4965
5004
  // src/core/tiers/t1-administrator.ts
5005
+ function sharedKeywords(a = [], b = []) {
5006
+ const setB = new Set(b.map((k) => k.toLowerCase().trim()).filter(Boolean));
5007
+ return [...new Set(a.map((k) => k.toLowerCase().trim()).filter(Boolean))].filter((k) => setB.has(k));
5008
+ }
5009
+ function isStrongKeywordOverlap(a = [], b = []) {
5010
+ if (!a.length || !b.length) return false;
5011
+ const shared = sharedKeywords(a, b);
5012
+ const ratio = shared.length / Math.min(a.length, b.length);
5013
+ return shared.length >= 3 && ratio >= 0.6;
5014
+ }
4966
5015
  var T1_SYSTEM_PROMPT = `You are T1, the Administrator in the Cascade AI orchestration system.
4967
5016
 
4968
5017
  Your responsibilities:
@@ -5387,17 +5436,27 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
5387
5436
  siblingKeywords.set(payload.sectionId, [...new Set(existing)]);
5388
5437
  }
5389
5438
  }
5390
- const overlapSections = /* @__PURE__ */ new Set();
5391
- for (let i = 0; i < announcements.length; i++) {
5392
- for (let j = i + 1; j < announcements.length; j++) {
5393
- const a = announcements[i].payload;
5394
- const b = announcements[j].payload;
5395
- if (!a.keywords || !b.keywords || !a.sectionId || !b.sectionId) continue;
5396
- const shared = a.keywords.filter((k) => b.keywords.includes(k));
5397
- if (shared.length > 0) {
5398
- overlapSections.add(a.sectionId);
5399
- overlapSections.add(b.sectionId);
5400
- this.log(`T2 overlap detected between sections: ${a.sectionId} \u2194 ${b.sectionId} (shared: ${shared.join(", ")})`);
5439
+ const payloads = announcements.map((ann) => ann.payload).filter((p) => p?.type === "T2_PLAN_ANNOUNCEMENT" && !!p.sectionId);
5440
+ const softOverlap = /* @__PURE__ */ new Set();
5441
+ const orderOf = new Map(sections.map((s, i) => [s.sectionId, i]));
5442
+ for (let i = 0; i < payloads.length; i++) {
5443
+ for (let j = i + 1; j < payloads.length; j++) {
5444
+ const a = payloads[i];
5445
+ const b = payloads[j];
5446
+ const shared = sharedKeywords(a.keywords ?? [], b.keywords ?? []);
5447
+ if (shared.length === 0) continue;
5448
+ softOverlap.add(a.sectionId);
5449
+ softOverlap.add(b.sectionId);
5450
+ if (isStrongKeywordOverlap(a.keywords ?? [], b.keywords ?? [])) {
5451
+ const ai = orderOf.get(a.sectionId) ?? 0;
5452
+ const bi = orderOf.get(b.sectionId) ?? 0;
5453
+ const earlier = ai <= bi ? a.sectionId : b.sectionId;
5454
+ const later = ai <= bi ? b.sectionId : a.sectionId;
5455
+ const laterSection = sections.find((s) => s.sectionId === later);
5456
+ if (laterSection && earlier !== later && !(laterSection.dependsOn ?? []).includes(earlier)) {
5457
+ laterSection.dependsOn = [...laterSection.dependsOn || [], earlier];
5458
+ this.log(`Strong overlap ${earlier} \u2194 ${later} (shared: ${shared.slice(0, 5).join(", ")}) \u2014 serializing ${later} after ${earlier}`);
5459
+ }
5401
5460
  }
5402
5461
  }
5403
5462
  }
@@ -5409,20 +5468,10 @@ Leave dependsOn empty for sections that can run immediately in parallel.`;
5409
5468
  `You are T2 Manager for section: "${section.sectionTitle}".`,
5410
5469
  `Sibling sections being worked on in parallel: ${otherTitles.join(", ") || "none"}.`,
5411
5470
  myKeywords.length > 0 ? `Watch for overlap with: ${[...new Set(myKeywords)].slice(0, 10).join(", ")}.` : "",
5412
- overlapSections.has(section.sectionId) ? "NOTE: Potential overlap detected with a sibling section \u2014 be careful not to duplicate work." : ""
5471
+ softOverlap.has(section.sectionId) ? "NOTE: Potential overlap detected with a sibling section \u2014 be careful not to duplicate work." : ""
5413
5472
  ].filter(Boolean).join(" ");
5414
5473
  m.setHierarchyContext(context);
5415
5474
  });
5416
- if (overlapSections.size > 0) {
5417
- this.log("Overlap detected \u2014 adding sequential dependencies for conflicting sections to prevent race conditions");
5418
- const overlapArray = Array.from(overlapSections);
5419
- for (let i = 1; i < overlapArray.length; i++) {
5420
- const section = sections.find((s) => s.sectionId === overlapArray[i]);
5421
- if (section) {
5422
- section.dependsOn = [...section.dependsOn || [], overlapArray[i - 1]];
5423
- }
5424
- }
5425
- }
5426
5475
  const t2Results = [];
5427
5476
  try {
5428
5477
  t2Results.push(...await this.runT2sWithDependencies(sections, managers, this.taskId));