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.cjs CHANGED
@@ -165,7 +165,7 @@ var require_keytar2 = __commonJS({
165
165
  });
166
166
 
167
167
  // src/constants.ts
168
- var CASCADE_VERSION = "0.2.12";
168
+ var CASCADE_VERSION = "0.4.0";
169
169
  var CASCADE_CONFIG_DIR = ".cascade";
170
170
  var CASCADE_MD_FILE = "CASCADE.md";
171
171
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -903,19 +903,21 @@ var OpenAIProvider = class extends BaseProvider {
903
903
  // src/providers/azure.ts
904
904
  var AzureOpenAIProvider = class extends OpenAIProvider {
905
905
  constructor(config, model) {
906
- const baseUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
906
+ const rawUrl = config.baseUrl ?? AZURE_BASE_URL_TEMPLATE.replace("{resource}", "YOUR_RESOURCE");
907
+ const endpoint = rawUrl.replace(/\/+$/, "");
907
908
  super(
908
909
  {
909
910
  ...config,
910
- baseUrl: `${baseUrl}/openai/deployments/${config.deploymentName ?? model.id}`
911
+ baseUrl: endpoint
912
+ // Kept for superclass compatibility if it reads it
911
913
  },
912
914
  model
913
915
  );
914
- this.client = new OpenAI__default.default({
916
+ this.client = new OpenAI.AzureOpenAI({
915
917
  apiKey: config.apiKey,
916
- baseURL: `${baseUrl}/openai/deployments/${config.deploymentName ?? model.id}`,
917
- defaultQuery: { "api-version": config.apiVersion ?? "2024-08-01-preview" },
918
- defaultHeaders: { "api-key": config.apiKey ?? "" }
918
+ endpoint,
919
+ deployment: config.deploymentName ?? model.id,
920
+ apiVersion: config.apiVersion ?? "2024-08-01-preview"
919
921
  });
920
922
  }
921
923
  async listModels() {
@@ -1673,7 +1675,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
1673
1675
  if (!model) {
1674
1676
  throw new Error(`Configured model "${override}" for ${tier} could not be loaded. Check provider availability and exact model name.`);
1675
1677
  }
1676
- if (model.id !== override) {
1678
+ if (model.id !== override && `${model.provider}:${model.id}` !== override) {
1677
1679
  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}).`);
1678
1680
  }
1679
1681
  this.tierModels.set(tier, model);
@@ -2036,7 +2038,7 @@ var BaseTier = class extends EventEmitter__default.default {
2036
2038
  getStatus() {
2037
2039
  return this.status;
2038
2040
  }
2039
- setStatus(status) {
2041
+ setStatus(status, output) {
2040
2042
  this.status = status;
2041
2043
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2042
2044
  const event = {
@@ -2045,7 +2047,8 @@ var BaseTier = class extends EventEmitter__default.default {
2045
2047
  parentId: this.parentId,
2046
2048
  label: this.label,
2047
2049
  status,
2048
- timestamp
2050
+ timestamp,
2051
+ output
2049
2052
  };
2050
2053
  this.emit("status", event);
2051
2054
  this.emit("tier:status", event);
@@ -2071,7 +2074,8 @@ var BaseTier = class extends EventEmitter__default.default {
2071
2074
  status: this.status,
2072
2075
  currentAction: update.currentAction,
2073
2076
  progressPct: update.progressPct,
2074
- timestamp
2077
+ timestamp,
2078
+ output: update.output
2075
2079
  });
2076
2080
  }
2077
2081
  buildMessage(type, to, payload) {
@@ -2451,16 +2455,17 @@ Now execute your subtask using this context where relevant.`
2451
2455
  return this.buildResult("ESCALATED", output, { checksRun, passed, failed }, issues, correctionAttempts);
2452
2456
  }
2453
2457
  }
2454
- this.setStatus("COMPLETED");
2455
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS" });
2458
+ this.setStatus("COMPLETED", output);
2459
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Subtask complete", status: "IN_PROGRESS", output });
2456
2460
  this.peerBus?.publish(this.id, assignment.subtaskId, output, "COMPLETED");
2457
2461
  return this.buildResult("COMPLETED", output, { checksRun, passed, failed }, issues, correctionAttempts);
2458
2462
  } catch (err) {
2459
2463
  const errMsg = err instanceof Error ? err.message : String(err);
2460
2464
  issues.push(`Execution error: ${errMsg}`);
2461
- this.setStatus("FAILED");
2462
- this.peerBus?.publish(this.id, assignment.subtaskId, errMsg, "FAILED");
2463
- return this.buildResult("ESCALATED", output || errMsg, { checksRun, passed, failed }, issues, correctionAttempts);
2465
+ const finalOutput = output || errMsg;
2466
+ this.setStatus("FAILED", finalOutput);
2467
+ this.peerBus?.publish(this.id, assignment.subtaskId, finalOutput, "FAILED");
2468
+ return this.buildResult("ESCALATED", finalOutput, { checksRun, passed, failed }, issues, correctionAttempts);
2464
2469
  }
2465
2470
  }
2466
2471
  sendToPeer(toId, content) {
@@ -2514,6 +2519,10 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
2514
2519
  await this.context.addMessage({ role: "assistant", content: result.content, toolCalls: result.toolCalls });
2515
2520
  if (!result.toolCalls?.length) {
2516
2521
  if (requiresArtifact) {
2522
+ const artifactCheck = await this.verifyArtifacts(this.assignment);
2523
+ if (artifactCheck.ok) {
2524
+ return { output: result.content, toolCalls: allToolCalls };
2525
+ }
2517
2526
  stalledArtifactIterations += 1;
2518
2527
  if (stalledArtifactIterations >= 2) {
2519
2528
  if (stalledArtifactIterations === 2) {
@@ -2523,15 +2532,22 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
2523
2532
  }
2524
2533
  await this.context.addMessage({
2525
2534
  role: "user",
2526
- 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."
2535
+ 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.`
2527
2536
  });
2528
2537
  continue;
2529
2538
  }
2530
2539
  return { output: result.content, toolCalls: allToolCalls };
2531
2540
  }
2532
2541
  stalledArtifactIterations = 0;
2533
- if (result.finishReason === "stop" && !requiresArtifact) {
2534
- return { output: result.content, toolCalls: allToolCalls };
2542
+ if (result.finishReason === "stop") {
2543
+ if (requiresArtifact) {
2544
+ const artifactCheck = await this.verifyArtifacts(this.assignment);
2545
+ if (artifactCheck.ok) {
2546
+ return { output: result.content, toolCalls: allToolCalls };
2547
+ }
2548
+ } else {
2549
+ return { output: result.content, toolCalls: allToolCalls };
2550
+ }
2535
2551
  }
2536
2552
  for (const tc of result.toolCalls) {
2537
2553
  allToolCalls.push(tc);
@@ -3143,8 +3159,9 @@ var T2Manager = class extends BaseTier {
3143
3159
  const summary = await this.aggregateResults(assignment, t3Results);
3144
3160
  const issues = t3Results.filter((r) => r.status !== "COMPLETED").flatMap((r) => r.issues);
3145
3161
  const overallStatus = this.determineStatus(t3Results);
3146
- this.setStatus(overallStatus === "COMPLETED" ? "COMPLETED" : "FAILED");
3147
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS" });
3162
+ const isOk = overallStatus === "COMPLETED" || overallStatus === "PARTIAL";
3163
+ this.setStatus(isOk ? "COMPLETED" : "FAILED", summary);
3164
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS", output: summary });
3148
3165
  const result = {
3149
3166
  sectionId: assignment.sectionId,
3150
3167
  sectionTitle: assignment.sectionTitle,
@@ -3157,7 +3174,7 @@ var T2Manager = class extends BaseTier {
3157
3174
  return result;
3158
3175
  } catch (err) {
3159
3176
  const errMsg = err instanceof Error ? err.message : String(err);
3160
- this.setStatus("FAILED");
3177
+ this.setStatus("FAILED", errMsg);
3161
3178
  const failedResult = {
3162
3179
  sectionId: assignment.sectionId,
3163
3180
  sectionTitle: assignment.sectionTitle,
@@ -3719,8 +3736,8 @@ Create a CORRECTION PLAN that contains only the new sections needed to fix the i
3719
3736
  status: "IN_PROGRESS"
3720
3737
  });
3721
3738
  const output = await this.compileFinalOutput(userPrompt, plan, allT2Results);
3722
- this.setStatus("COMPLETED");
3723
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS" });
3739
+ this.setStatus("COMPLETED", output);
3740
+ this.sendStatusUpdate({ progressPct: 100, currentAction: "Task complete", status: "IN_PROGRESS", output });
3724
3741
  return { output, t2Results: allT2Results, taskId: this.taskId, complexity: plan.complexity };
3725
3742
  }
3726
3743
  getEscalations() {
@@ -6124,10 +6141,17 @@ var Cascade = class extends EventEmitter__default.default {
6124
6141
  throw err;
6125
6142
  }
6126
6143
  }
6144
+ isCasualGreeting(prompt) {
6145
+ const casual = /^(hi|hello|hey|greetings|thanks|thank you|thx|bye|goodbye|cya)$/i.test(prompt.trim().replace(/[!?.]+$/, ""));
6146
+ return casual;
6147
+ }
6127
6148
  looksLikeSimpleArtifactTask(prompt) {
6128
6149
  return /create .*\.(txt|md|json|csv)\b/i.test(prompt) && !/(research|compare|thorough|pdf|report|analy[sz]e|architecture|multi-agent)/i.test(prompt);
6129
6150
  }
6130
6151
  async determineComplexity(prompt, workspacePath, conversationHistory = []) {
6152
+ if (this.isCasualGreeting(prompt)) {
6153
+ return "Simple";
6154
+ }
6131
6155
  if (this.looksLikeSimpleArtifactTask(prompt)) {
6132
6156
  return "Simple";
6133
6157
  }
@@ -6858,8 +6882,8 @@ Original error: ${err.message}`
6858
6882
  upsertRuntimeNode(node) {
6859
6883
  this.enqueueWrite(() => {
6860
6884
  this.db.prepare(`
6861
- INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global)
6862
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6885
+ INSERT INTO runtime_nodes (tier_id, session_id, parent_id, role, label, status, current_action, progress_pct, updated_at, workspace_path, is_global, output)
6886
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6863
6887
  ON CONFLICT(tier_id) DO UPDATE SET
6864
6888
  session_id = excluded.session_id,
6865
6889
  parent_id = excluded.parent_id,
@@ -6870,7 +6894,8 @@ Original error: ${err.message}`
6870
6894
  progress_pct = excluded.progress_pct,
6871
6895
  updated_at = excluded.updated_at,
6872
6896
  workspace_path = excluded.workspace_path,
6873
- is_global = excluded.is_global
6897
+ is_global = excluded.is_global,
6898
+ output = excluded.output
6874
6899
  `).run(
6875
6900
  node.tierId,
6876
6901
  node.sessionId,
@@ -6882,7 +6907,8 @@ Original error: ${err.message}`
6882
6907
  node.progressPct ?? null,
6883
6908
  node.updatedAt,
6884
6909
  node.workspacePath ?? null,
6885
- node.isGlobal ? 1 : 0
6910
+ node.isGlobal ? 1 : 0,
6911
+ node.output ?? null
6886
6912
  );
6887
6913
  });
6888
6914
  }
@@ -6903,14 +6929,15 @@ Original error: ${err.message}`
6903
6929
  progressPct: row.progress_pct ?? void 0,
6904
6930
  updatedAt: row.updated_at,
6905
6931
  workspacePath: row.workspace_path ?? void 0,
6906
- isGlobal: row.is_global === 1
6932
+ isGlobal: row.is_global === 1,
6933
+ output: row.output ?? void 0
6907
6934
  }));
6908
6935
  }
6909
6936
  addRuntimeNodeLog(log) {
6910
6937
  this.enqueueWrite(() => {
6911
6938
  this.db.prepare(`
6912
- INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global)
6913
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6939
+ INSERT INTO runtime_node_logs (id, session_id, tier_id, role, label, status, current_action, progress_pct, timestamp, workspace_path, is_global, output)
6940
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6914
6941
  `).run(
6915
6942
  log.id,
6916
6943
  log.sessionId,
@@ -6922,7 +6949,8 @@ Original error: ${err.message}`
6922
6949
  log.progressPct ?? null,
6923
6950
  log.timestamp,
6924
6951
  log.workspacePath ?? null,
6925
- log.isGlobal ? 1 : 0
6952
+ log.isGlobal ? 1 : 0,
6953
+ log.output ?? null
6926
6954
  );
6927
6955
  this.db.prepare(`
6928
6956
  DELETE FROM runtime_node_logs
@@ -6965,7 +6993,8 @@ Original error: ${err.message}`
6965
6993
  progressPct: row.progress_pct ?? void 0,
6966
6994
  timestamp: row.timestamp,
6967
6995
  workspacePath: row.workspace_path ?? void 0,
6968
- isGlobal: row.is_global === 1
6996
+ isGlobal: row.is_global === 1,
6997
+ output: row.output ?? void 0
6969
6998
  }));
6970
6999
  }
6971
7000
  // ── Messages ──────────────────────────────────
@@ -7292,7 +7321,8 @@ Original error: ${err.message}`
7292
7321
  progress_pct INTEGER,
7293
7322
  updated_at TEXT NOT NULL,
7294
7323
  workspace_path TEXT,
7295
- is_global INTEGER NOT NULL DEFAULT 0
7324
+ is_global INTEGER NOT NULL DEFAULT 0,
7325
+ output TEXT
7296
7326
  );
7297
7327
 
7298
7328
  CREATE INDEX IF NOT EXISTS idx_runtime_nodes_session ON runtime_nodes(session_id);
@@ -7309,7 +7339,8 @@ Original error: ${err.message}`
7309
7339
  progress_pct INTEGER,
7310
7340
  timestamp TEXT NOT NULL,
7311
7341
  workspace_path TEXT,
7312
- is_global INTEGER NOT NULL DEFAULT 0
7342
+ is_global INTEGER NOT NULL DEFAULT 0,
7343
+ output TEXT
7313
7344
  );
7314
7345
 
7315
7346
  CREATE TABLE IF NOT EXISTS model_cache (
@@ -7338,6 +7369,14 @@ Original error: ${err.message}`
7338
7369
 
7339
7370
  CREATE INDEX IF NOT EXISTS idx_file_snapshots_session ON file_snapshots(session_id);
7340
7371
  `);
7372
+ try {
7373
+ this.db.exec("ALTER TABLE runtime_nodes ADD COLUMN output TEXT");
7374
+ } catch {
7375
+ }
7376
+ try {
7377
+ this.db.exec("ALTER TABLE runtime_node_logs ADD COLUMN output TEXT");
7378
+ } catch {
7379
+ }
7341
7380
  }
7342
7381
  // ── Deserializers ─────────────────────────────
7343
7382
  deserializeSession(row, messages) {
@@ -8111,8 +8150,8 @@ var DashboardServer = class {
8111
8150
  void (async () => {
8112
8151
  const cascade = new Cascade(this.config, this.workspacePath, this.store);
8113
8152
  cascade.on("stream:token", (e) => {
8114
- this.socket.broadcast("stream:token", { sessionId, token: e.text });
8115
- this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, token: e.text });
8153
+ this.socket.broadcast("stream:token", { sessionId, tierId: e.tierId, text: e.text });
8154
+ this.socket.broadcastToRoom(`session:${sessionId}`, "stream:token", { sessionId, tierId: e.tierId, text: e.text });
8116
8155
  });
8117
8156
  cascade.on("tier:status", (e) => {
8118
8157
  this.socket.broadcast("tier:status", { sessionId, ...e });