cascade-ai 0.2.12 → 0.4.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.
package/dist/index.d.cts CHANGED
@@ -175,6 +175,7 @@ interface StatusUpdate {
175
175
  progressPct: number;
176
176
  currentAction: string;
177
177
  status: 'IN_PROGRESS' | 'BLOCKED' | 'ESCALATING';
178
+ output?: string;
178
179
  }
179
180
  interface T2Result {
180
181
  sectionId: string;
@@ -274,6 +275,7 @@ interface RuntimeNode {
274
275
  updatedAt: string;
275
276
  workspacePath?: string;
276
277
  isGlobal?: boolean;
278
+ output?: string;
277
279
  }
278
280
  interface RuntimeNodeLog {
279
281
  id: string;
@@ -287,6 +289,7 @@ interface RuntimeNodeLog {
287
289
  timestamp: string;
288
290
  workspacePath?: string;
289
291
  isGlobal?: boolean;
292
+ output?: string;
290
293
  }
291
294
  type RuntimeScope = 'workspace' | 'global';
292
295
  interface RuntimeSnapshotPayload {
@@ -893,6 +896,7 @@ declare class Cascade extends EventEmitter {
893
896
  /** Resolve a pending MCP server approval from a REPL / dashboard listener. */
894
897
  resolveMcpApproval(serverName: string, approved: boolean): void;
895
898
  init(): Promise<void>;
899
+ private isCasualGreeting;
896
900
  private looksLikeSimpleArtifactTask;
897
901
  private determineComplexity;
898
902
  run(options: CascadeRunOptions): Promise<CascadeRunResult>;
@@ -919,7 +923,7 @@ declare abstract class BaseTier extends EventEmitter {
919
923
  protected signal?: AbortSignal;
920
924
  constructor(role: TierRole, id?: string, parentId?: string);
921
925
  getStatus(): TierStatus;
922
- protected setStatus(status: TierStatus): void;
926
+ protected setStatus(status: TierStatus, output?: string): void;
923
927
  protected setLabel(label: string): void;
924
928
  setSystemPromptOverride(prompt: string): void;
925
929
  setHierarchyContext(context: string): void;
@@ -1581,7 +1585,7 @@ declare class Telemetry {
1581
1585
  shutdown(): Promise<void>;
1582
1586
  }
1583
1587
 
1584
- declare const CASCADE_VERSION = "0.2.12";
1588
+ declare const CASCADE_VERSION = "0.4.0";
1585
1589
  declare const CASCADE_CONFIG_DIR = ".cascade";
1586
1590
  declare const CASCADE_MD_FILE = "CASCADE.md";
1587
1591
  declare const CASCADE_IGNORE_FILE = ".cascadeignore";
package/dist/index.d.ts CHANGED
@@ -175,6 +175,7 @@ interface StatusUpdate {
175
175
  progressPct: number;
176
176
  currentAction: string;
177
177
  status: 'IN_PROGRESS' | 'BLOCKED' | 'ESCALATING';
178
+ output?: string;
178
179
  }
179
180
  interface T2Result {
180
181
  sectionId: string;
@@ -274,6 +275,7 @@ interface RuntimeNode {
274
275
  updatedAt: string;
275
276
  workspacePath?: string;
276
277
  isGlobal?: boolean;
278
+ output?: string;
277
279
  }
278
280
  interface RuntimeNodeLog {
279
281
  id: string;
@@ -287,6 +289,7 @@ interface RuntimeNodeLog {
287
289
  timestamp: string;
288
290
  workspacePath?: string;
289
291
  isGlobal?: boolean;
292
+ output?: string;
290
293
  }
291
294
  type RuntimeScope = 'workspace' | 'global';
292
295
  interface RuntimeSnapshotPayload {
@@ -893,6 +896,7 @@ declare class Cascade extends EventEmitter {
893
896
  /** Resolve a pending MCP server approval from a REPL / dashboard listener. */
894
897
  resolveMcpApproval(serverName: string, approved: boolean): void;
895
898
  init(): Promise<void>;
899
+ private isCasualGreeting;
896
900
  private looksLikeSimpleArtifactTask;
897
901
  private determineComplexity;
898
902
  run(options: CascadeRunOptions): Promise<CascadeRunResult>;
@@ -919,7 +923,7 @@ declare abstract class BaseTier extends EventEmitter {
919
923
  protected signal?: AbortSignal;
920
924
  constructor(role: TierRole, id?: string, parentId?: string);
921
925
  getStatus(): TierStatus;
922
- protected setStatus(status: TierStatus): void;
926
+ protected setStatus(status: TierStatus, output?: string): void;
923
927
  protected setLabel(label: string): void;
924
928
  setSystemPromptOverride(prompt: string): void;
925
929
  setHierarchyContext(context: string): void;
@@ -1581,7 +1585,7 @@ declare class Telemetry {
1581
1585
  shutdown(): Promise<void>;
1582
1586
  }
1583
1587
 
1584
- declare const CASCADE_VERSION = "0.2.12";
1588
+ declare const CASCADE_VERSION = "0.4.0";
1585
1589
  declare const CASCADE_CONFIG_DIR = ".cascade";
1586
1590
  declare const CASCADE_MD_FILE = "CASCADE.md";
1587
1591
  declare const CASCADE_IGNORE_FILE = ".cascadeignore";
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import EventEmitter from 'events';
2
2
  import crypto, { randomUUID, timingSafeEqual } from 'crypto';
3
3
  import { glob } from 'glob';
4
4
  import Anthropic from '@anthropic-ai/sdk';
5
- import OpenAI from 'openai';
5
+ import OpenAI, { AzureOpenAI } from 'openai';
6
6
  import { GoogleGenAI, HarmBlockThreshold, HarmCategory } from '@google/genai';
7
7
  import axios2 from 'axios';
8
8
  import fs2 from 'fs/promises';
@@ -124,7 +124,7 @@ var require_keytar2 = __commonJS({
124
124
  });
125
125
 
126
126
  // src/constants.ts
127
- var CASCADE_VERSION = "0.2.12";
127
+ var CASCADE_VERSION = "0.4.0";
128
128
  var CASCADE_CONFIG_DIR = ".cascade";
129
129
  var CASCADE_MD_FILE = "CASCADE.md";
130
130
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -862,19 +862,21 @@ var OpenAIProvider = class extends BaseProvider {
862
862
  // src/providers/azure.ts
863
863
  var AzureOpenAIProvider = class extends OpenAIProvider {
864
864
  constructor(config, model) {
865
- const baseUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
865
+ const rawUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
866
+ const endpoint = rawUrl.replace(/\/+$/, "");
866
867
  super(
867
868
  {
868
869
  ...config,
869
- baseUrl: `${baseUrl}/openai/deployments/${config.deploymentName ?? model.id}`
870
+ baseUrl: endpoint
871
+ // Kept for superclass compatibility if it reads it
870
872
  },
871
873
  model
872
874
  );
873
- this.client = new OpenAI({
875
+ this.client = new AzureOpenAI({
874
876
  apiKey: config.apiKey,
875
- baseURL: `${baseUrl}/openai/deployments/${config.deploymentName ?? model.id}`,
876
- defaultQuery: { "api-version": config.apiVersion ?? "2024-08-01-preview" },
877
- defaultHeaders: { "api-key": config.apiKey ?? "" }
877
+ endpoint,
878
+ deployment: config.deploymentName ?? model.id,
879
+ apiVersion: config.apiVersion ?? "2024-08-01-preview"
878
880
  });
879
881
  }
880
882
  async listModels() {
@@ -1632,7 +1634,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
1632
1634
  if (!model) {
1633
1635
  throw new Error(`Configured model "${override}" for ${tier} could not be loaded. Check provider availability and exact model name.`);
1634
1636
  }
1635
- if (model.id !== override) {
1637
+ if (model.id !== override && `${model.provider}:${model.id}` !== override) {
1636
1638
  throw new Error(`Configured model "${override}" for ${tier} resolved to "${model.id}". Use the exact provider model ID or prefix the provider (e.g. gemini:${override}).`);
1637
1639
  }
1638
1640
  this.tierModels.set(tier, model);
@@ -1995,7 +1997,7 @@ var BaseTier = class extends EventEmitter {
1995
1997
  getStatus() {
1996
1998
  return this.status;
1997
1999
  }
1998
- setStatus(status) {
2000
+ setStatus(status, output) {
1999
2001
  this.status = status;
2000
2002
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2001
2003
  const event = {
@@ -2004,7 +2006,8 @@ var BaseTier = class extends EventEmitter {
2004
2006
  parentId: this.parentId,
2005
2007
  label: this.label,
2006
2008
  status,
2007
- timestamp
2009
+ timestamp,
2010
+ output
2008
2011
  };
2009
2012
  this.emit("status", event);
2010
2013
  this.emit("tier:status", event);
@@ -2030,7 +2033,8 @@ var BaseTier = class extends EventEmitter {
2030
2033
  status: this.status,
2031
2034
  currentAction: update.currentAction,
2032
2035
  progressPct: update.progressPct,
2033
- timestamp
2036
+ timestamp,
2037
+ output: update.output
2034
2038
  });
2035
2039
  }
2036
2040
  buildMessage(type, to, payload) {
@@ -2410,16 +2414,17 @@ Now execute your subtask using this context where relevant.`
2410
2414
  return this.buildResult("ESCALATED", output, { checksRun, passed, failed }, issues, correctionAttempts);
2411
2415
  }
2412
2416
  }
2413
- this.setStatus("COMPLETED");
2414
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS" });
2417
+ this.setStatus("COMPLETED", output);
2418
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS", output });
2415
2419
  this.peerBus?.publish(this.id, assignment.subtaskId, output, "COMPLETED");
2416
2420
  return this.buildResult("COMPLETED", output, { checksRun, passed, failed }, issues, correctionAttempts);
2417
2421
  } catch (err) {
2418
2422
  const errMsg = err instanceof Error ? err.message : String(err);
2419
2423
  issues.push(`Execution error: ${errMsg}`);
2420
- this.setStatus("FAILED");
2421
- this.peerBus?.publish(this.id, assignment.subtaskId, errMsg, "FAILED");
2422
- return this.buildResult("ESCALATED", output || errMsg, { checksRun, passed, failed }, issues, correctionAttempts);
2424
+ const finalOutput = output || errMsg;
2425
+ this.setStatus("FAILED", finalOutput);
2426
+ this.peerBus?.publish(this.id, assignment.subtaskId, finalOutput, "FAILED");
2427
+ return this.buildResult("ESCALATED", finalOutput, { checksRun, passed, failed }, issues, correctionAttempts);
2423
2428
  }
2424
2429
  }
2425
2430
  sendToPeer(toId, content) {
@@ -2473,6 +2478,10 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
2473
2478
  await this.context.addMessage({ role: "assistant", content: result.content, toolCalls: result.toolCalls });
2474
2479
  if (!result.toolCalls?.length) {
2475
2480
  if (requiresArtifact) {
2481
+ const artifactCheck = await this.verifyArtifacts(this.assignment);
2482
+ if (artifactCheck.ok) {
2483
+ return { output: result.content, toolCalls: allToolCalls };
2484
+ }
2476
2485
  stalledArtifactIterations += 1;
2477
2486
  if (stalledArtifactIterations >= 2) {
2478
2487
  if (stalledArtifactIterations === 2) {
@@ -2482,15 +2491,22 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
2482
2491
  }
2483
2492
  await this.context.addMessage({
2484
2493
  role: "user",
2485
- content: "You have not yet created and verified the required artifact. Use tools to create the file in the workspace, verify it exists, and inspect the result before concluding."
2494
+ content: `You have not yet created and verified the required artifact. Issues: ${artifactCheck.issues.join("; ")}. Use tools to create the file in the workspace, verify it exists, and inspect the result before concluding.`
2486
2495
  });
2487
2496
  continue;
2488
2497
  }
2489
2498
  return { output: result.content, toolCalls: allToolCalls };
2490
2499
  }
2491
2500
  stalledArtifactIterations = 0;
2492
- if (result.finishReason === "stop" && !requiresArtifact) {
2493
- return { output: result.content, toolCalls: allToolCalls };
2501
+ if (result.finishReason === "stop") {
2502
+ if (requiresArtifact) {
2503
+ const artifactCheck = await this.verifyArtifacts(this.assignment);
2504
+ if (artifactCheck.ok) {
2505
+ return { output: result.content, toolCalls: allToolCalls };
2506
+ }
2507
+ } else {
2508
+ return { output: result.content, toolCalls: allToolCalls };
2509
+ }
2494
2510
  }
2495
2511
  for (const tc of result.toolCalls) {
2496
2512
  allToolCalls.push(tc);
@@ -3102,8 +3118,9 @@ var T2Manager = class extends BaseTier {
3102
3118
  const summary = await this.aggregateResults(assignment, t3Results);
3103
3119
  const issues = t3Results.filter((r) => r.status !== "COMPLETED").flatMap((r) => r.issues);
3104
3120
  const overallStatus = this.determineStatus(t3Results);
3105
- this.setStatus(overallStatus === "COMPLETED" ? "COMPLETED" : "FAILED");
3106
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS" });
3121
+ const isOk = overallStatus === "COMPLETED" || overallStatus === "PARTIAL";
3122
+ this.setStatus(isOk ? "COMPLETED" : "FAILED", summary);
3123
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS", output: summary });
3107
3124
  const result = {
3108
3125
  sectionId: assignment.sectionId,
3109
3126
  sectionTitle: assignment.sectionTitle,
@@ -3116,7 +3133,7 @@ var T2Manager = class extends BaseTier {
3116
3133
  return result;
3117
3134
  } catch (err) {
3118
3135
  const errMsg = err instanceof Error ? err.message : String(err);
3119
- this.setStatus("FAILED");
3136
+ this.setStatus("FAILED", errMsg);
3120
3137
  const failedResult = {
3121
3138
  sectionId: assignment.sectionId,
3122
3139
  sectionTitle: assignment.sectionTitle,
@@ -3678,8 +3695,8 @@ Create a CORRECTION PLAN that contains only the new sections needed to fix the i
3678
3695
  status: "IN_PROGRESS"
3679
3696
  });
3680
3697
  const output = await this.compileFinalOutput(userPrompt, plan, allT2Results);
3681
- this.setStatus("COMPLETED");
3682
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS" });
3698
+ this.setStatus("COMPLETED", output);
3699
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS", output });
3683
3700
  return { output, t2Results: allT2Results, taskId: this.taskId, complexity: plan.complexity };
3684
3701
  }
3685
3702
  getEscalations() {
@@ -6083,10 +6100,17 @@ var Cascade = class extends EventEmitter {
6083
6100
  throw err;
6084
6101
  }
6085
6102
  }
6103
+ isCasualGreeting(prompt) {
6104
+ const casual = /^(hi|hello|hey|greetings|thanks|thank you|thx|bye|goodbye|cya)$/i.test(prompt.trim().replace(/[!?.]+$/, ""));
6105
+ return casual;
6106
+ }
6086
6107
  looksLikeSimpleArtifactTask(prompt) {
6087
6108
  return /create .*\.(txt|md|json|csv)\b/i.test(prompt) && !/(research|compare|thorough|pdf|report|analy[sz]e|architecture|multi-agent)/i.test(prompt);
6088
6109
  }
6089
6110
  async determineComplexity(prompt, workspacePath, conversationHistory = []) {
6111
+ if (this.isCasualGreeting(prompt)) {
6112
+ return "Simple";
6113
+ }
6090
6114
  if (this.looksLikeSimpleArtifactTask(prompt)) {
6091
6115
  return "Simple";
6092
6116
  }
@@ -6817,8 +6841,8 @@ Original error: ${err.message}`
6817
6841
  upsertRuntimeNode(node) {
6818
6842
  this.enqueueWrite(() => {
6819
6843
  this.db.prepare(`
6820
- INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global)
6821
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6844
+ INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global, output)
6845
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6822
6846
  ON CONFLICT(tier_id) DO UPDATE SET
6823
6847
  session_id = excluded.session_id,
6824
6848
  parent_id = excluded.parent_id,
@@ -6829,7 +6853,8 @@ Original error: ${err.message}`
6829
6853
  progress_pct = excluded.progress_pct,
6830
6854
  updated_at = excluded.updated_at,
6831
6855
  workspace_path = excluded.workspace_path,
6832
- is_global = excluded.is_global
6856
+ is_global = excluded.is_global,
6857
+ output = excluded.output
6833
6858
  `).run(
6834
6859
  node.tierId,
6835
6860
  node.sessionId,
@@ -6841,7 +6866,8 @@ Original error: ${err.message}`
6841
6866
  node.progressPct ?? null,
6842
6867
  node.updatedAt,
6843
6868
  node.workspacePath ?? null,
6844
- node.isGlobal ? 1 : 0
6869
+ node.isGlobal ? 1 : 0,
6870
+ node.output ?? null
6845
6871
  );
6846
6872
  });
6847
6873
  }
@@ -6862,14 +6888,15 @@ Original error: ${err.message}`
6862
6888
  progressPct: row.progress_pct ?? void 0,
6863
6889
  updatedAt: row.updated_at,
6864
6890
  workspacePath: row.workspace_path ?? void 0,
6865
- isGlobal: row.is_global === 1
6891
+ isGlobal: row.is_global === 1,
6892
+ output: row.output ?? void 0
6866
6893
  }));
6867
6894
  }
6868
6895
  addRuntimeNodeLog(log) {
6869
6896
  this.enqueueWrite(() => {
6870
6897
  this.db.prepare(`
6871
- INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global)
6872
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6898
+ INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global, output)
6899
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6873
6900
  `).run(
6874
6901
  log.id,
6875
6902
  log.sessionId,
@@ -6881,7 +6908,8 @@ Original error: ${err.message}`
6881
6908
  log.progressPct ?? null,
6882
6909
  log.timestamp,
6883
6910
  log.workspacePath ?? null,
6884
- log.isGlobal ? 1 : 0
6911
+ log.isGlobal ? 1 : 0,
6912
+ log.output ?? null
6885
6913
  );
6886
6914
  this.db.prepare(`
6887
6915
  DELETE FROM runtime_node_logs
@@ -6924,7 +6952,8 @@ Original error: ${err.message}`
6924
6952
  progressPct: row.progress_pct ?? void 0,
6925
6953
  timestamp: row.timestamp,
6926
6954
  workspacePath: row.workspace_path ?? void 0,
6927
- isGlobal: row.is_global === 1
6955
+ isGlobal: row.is_global === 1,
6956
+ output: row.output ?? void 0
6928
6957
  }));
6929
6958
  }
6930
6959
  // ── Messages ──────────────────────────────────
@@ -7251,7 +7280,8 @@ Original error: ${err.message}`
7251
7280
  progress_pct INTEGER,
7252
7281
  updated_at TEXT NOT NULL,
7253
7282
  workspace_path TEXT,
7254
- is_global INTEGER NOT NULL DEFAULT 0
7283
+ is_global INTEGER NOT NULL DEFAULT 0,
7284
+ output TEXT
7255
7285
  );
7256
7286
 
7257
7287
  CREATE INDEX IF NOT EXISTS idx_runtime_nodes_session ON runtime_nodes(session_id);
@@ -7268,7 +7298,8 @@ Original error: ${err.message}`
7268
7298
  progress_pct INTEGER,
7269
7299
  timestamp TEXT NOT NULL,
7270
7300
  workspace_path TEXT,
7271
- is_global INTEGER NOT NULL DEFAULT 0
7301
+ is_global INTEGER NOT NULL DEFAULT 0,
7302
+ output TEXT
7272
7303
  );
7273
7304
 
7274
7305
  CREATE TABLE IF NOT EXISTS model_cache (
@@ -7297,6 +7328,14 @@ Original error: ${err.message}`
7297
7328
 
7298
7329
  CREATE INDEX IF NOT EXISTS idx_file_snapshots_session ON file_snapshots(session_id);
7299
7330
  `);
7331
+ try {
7332
+ this.db.exec("ALTER TABLE runtime_nodes ADD COLUMN output TEXT");
7333
+ } catch {
7334
+ }
7335
+ try {
7336
+ this.db.exec("ALTER TABLE runtime_node_logs ADD COLUMN output TEXT");
7337
+ } catch {
7338
+ }
7300
7339
  }
7301
7340
  // ── Deserializers ─────────────────────────────
7302
7341
  deserializeSession(row, messages) {
@@ -8070,8 +8109,8 @@ var DashboardServer = class {
8070
8109
  void (async () => {
8071
8110
  const cascade = new Cascade(this.config, this.workspacePath, this.store);
8072
8111
  cascade.on("stream:token", (e) => {
8073
- this.socket.broadcast("stream:token", { sessionId, token: e.text });
8074
- this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, token: e.text });
8112
+ this.socket.broadcast("stream:token", { sessionId, tierId: e.tierId, text: e.text });
8113
+ this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, tierId: e.tierId, text: e.text });
8075
8114
  });
8076
8115
  cascade.on("tier:status", (e) => {
8077
8116
  this.socket.broadcast("tier:status", { sessionId, ...e });