daedalus-cli 0.5.18 → 0.5.20

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
@@ -183,7 +183,7 @@ const COMMANDS = [
183
183
  '/index', '/find', '/refs', '/def',
184
184
  '/commit', '/undo', '/test', '/paste',
185
185
  '/models', '/tools', '/config', '/project', '/doctor', '/session', '/onboard',
186
- '/help', 'exit', 'quit', '?', '/prune', '/branch', '/pr', '/debug',
186
+ '/help', 'exit', 'quit', '?', '/prune', '/branch', '/pr', '/debug', '/ensemble',
187
187
  ];
188
188
  const rl = readline.createInterface({
189
189
  input: process.stdin,
@@ -773,11 +773,19 @@ async function callModelWithTools(userContent, imageBase64) {
773
773
  return { content: '', toolCalls: [] };
774
774
  }
775
775
  spinner.stop();
776
- console.error(pc.red(`\n[ERROR] Error calling model: ${error.message}`));
776
+ const firstLine = (error.message || '').split('\n')[0];
777
+ console.log(pc.yellow(`\n ${pc.bold('[WARN]')} Error calling model: ${firstLine}`));
778
+ console.log(pc.dim(` (Tip: Run /doctor to diagnose connection or loading issues)`));
777
779
  throw error;
778
780
  }
779
781
  currentAbortController = null;
780
- const toolCallArray = Array.from(toolCallMap.values()).filter(tc => tc.function.name);
782
+ let toolCallArray = Array.from(toolCallMap.values()).filter(tc => tc.function.name);
783
+ if (toolCallArray.length === 0) {
784
+ const parsedCalls = parseTextToolCalls(fullContent);
785
+ if (parsedCalls.length > 0) {
786
+ toolCallArray = parsedCalls;
787
+ }
788
+ }
781
789
  lastContent = fullContent;
782
790
  // Close assistant block after streaming, before tool results
783
791
  if (blockOpened) {
@@ -865,7 +873,7 @@ async function callModelWithFallback(userContent, imageBase64) {
865
873
  else {
866
874
  messages.push({ role: 'user', content: userContent });
867
875
  }
868
- console.log(pc.gray('[THINK] Thinking (fallback mode)...'));
876
+ console.log(pc.gray(' [THINK] Thinking (fallback mode)...'));
869
877
  try {
870
878
  const response = await router.chat.completions.create({
871
879
  model: 'auto',
@@ -882,7 +890,9 @@ async function callModelWithFallback(userContent, imageBase64) {
882
890
  return reply;
883
891
  }
884
892
  catch (error) {
885
- console.error(pc.red(`\n[ERROR] Fallback error: ${error.message}`));
893
+ const firstLine = (error.message || '').split('\n')[0];
894
+ console.log(pc.yellow(`\n ${pc.bold('[WARN]')} Fallback error: ${firstLine}`));
895
+ console.log(pc.dim(` (Tip: Run /doctor to diagnose connection or loading issues)`));
886
896
  throw error;
887
897
  }
888
898
  }
@@ -1035,6 +1045,50 @@ function writeAssistantChunk(chunk) {
1035
1045
  }
1036
1046
  }
1037
1047
  }
1048
+ export function parseTextToolCalls(text) {
1049
+ const toolCalls = [];
1050
+ const regex = /<(longcat_)?tool_call>([\s\S]*?)<\/(longcat_)?tool_call>/g;
1051
+ let match;
1052
+ while ((match = regex.exec(text)) !== null) {
1053
+ const blockContent = match[2].trim();
1054
+ const lines = blockContent.split('\n').map(l => l.trim()).filter(Boolean);
1055
+ if (lines.length === 0)
1056
+ continue;
1057
+ const toolName = lines[0].replace(/<[^>]+>/g, '').trim();
1058
+ const args = {};
1059
+ const keyRegex = /<(longcat_)?arg_key>([\s\S]*?)<\/(longcat_)?arg_key>/g;
1060
+ const valRegex = /<(longcat_)?arg_value>([\s\S]*?)<\/(longcat_)?arg_value>/g;
1061
+ const keys = [];
1062
+ const values = [];
1063
+ let keyMatch;
1064
+ while ((keyMatch = keyRegex.exec(blockContent)) !== null) {
1065
+ keys.push(keyMatch[2].trim());
1066
+ }
1067
+ let valMatch;
1068
+ while ((valMatch = valRegex.exec(blockContent)) !== null) {
1069
+ values.push(valMatch[2].trim());
1070
+ }
1071
+ for (let i = 0; i < Math.min(keys.length, values.length); i++) {
1072
+ const k = keys[i];
1073
+ const v = values[i];
1074
+ try {
1075
+ args[k] = JSON.parse(v);
1076
+ }
1077
+ catch {
1078
+ args[k] = v;
1079
+ }
1080
+ }
1081
+ toolCalls.push({
1082
+ id: `call_parsed_${Date.now()}_${toolCalls.length}`,
1083
+ type: 'function',
1084
+ function: {
1085
+ name: toolName,
1086
+ arguments: JSON.stringify(args),
1087
+ }
1088
+ });
1089
+ }
1090
+ return toolCalls;
1091
+ }
1038
1092
  function closeAssistantBlock(tokens, elapsedMs, toolCount) {
1039
1093
  if (_assistantLineBuf) {
1040
1094
  for (const part of wrapLine(_assistantLineBuf, termW)) {
@@ -1042,9 +1096,10 @@ function closeAssistantBlock(tokens, elapsedMs, toolCount) {
1042
1096
  }
1043
1097
  _assistantLineBuf = '';
1044
1098
  }
1099
+ const modelStr = router.lastRoutedModel ? `${router.lastRoutedModel} · ` : '';
1045
1100
  const meta = toolCount !== undefined
1046
- ? `${toolCount} tool(s) · ~${Math.round(tokens / 4)}t out · ${elapsedMs}ms`
1047
- : `~${Math.round(tokens / 4)}t out · ${elapsedMs}ms`;
1101
+ ? `${modelStr}${toolCount} tool(s) · ~${Math.round(tokens / 4)}t out · ${elapsedMs}ms`
1102
+ : `${modelStr}~${Math.round(tokens / 4)}t out · ${elapsedMs}ms`;
1048
1103
  console.log(` ${pc.dim(meta)}\n`);
1049
1104
  }
1050
1105
  function turnSeparator() {
@@ -1098,6 +1153,7 @@ async function chatLoop() {
1098
1153
  console.log(` ${pc.cyan('/paste')} Paste clipboard text/image as message`);
1099
1154
  console.log(` ${pc.cyan('/test')} Run tests and auto-fix failures`);
1100
1155
  console.log(` ${pc.cyan('/debug')} Run a command and autonomously fix failures`);
1156
+ console.log(` ${pc.cyan('/ensemble')} Run multi-model ensemble drafting pipeline`);
1101
1157
  console.log(` ${pc.cyan('/index')} Index codebase for symbol search`);
1102
1158
  console.log(` ${pc.cyan('/find')} Search indexed symbols`);
1103
1159
  console.log(` ${pc.cyan('/refs')} Find symbol references`);
@@ -1176,16 +1232,16 @@ async function chatLoop() {
1176
1232
  sessionManager.saveSessionState(messages, activeFiles, getSessionTodos(sessionId));
1177
1233
  }
1178
1234
  catch (error) {
1179
- console.error(pc.red(`\n[ERROR] Error: ${error.message}`));
1180
1235
  try {
1181
1236
  const filesContext = buildFileContext();
1182
1237
  const userContent = `${filesContext}User Prompt: ${message}`;
1183
- console.log(pc.yellow('\n[RETRY] Trying fallback mode...'));
1238
+ console.log(pc.yellow('\n [RETRY] Trying fallback mode...'));
1184
1239
  await callModelWithFallback(userContent, base64);
1185
1240
  sessionManager.saveSessionState(messages, activeFiles, getSessionTodos(sessionId));
1186
1241
  }
1187
1242
  catch (fallbackErr) {
1188
- console.error(pc.red(`\n[ERROR] Fallback also failed: ${fallbackErr.message}`));
1243
+ const firstLine = (fallbackErr.message || '').split('\n')[0];
1244
+ console.log(pc.red(`\n ${pc.bold('[ERROR]')} Fallback also failed: ${firstLine}`));
1189
1245
  }
1190
1246
  }
1191
1247
  turnSeparator();
@@ -1209,16 +1265,16 @@ async function chatLoop() {
1209
1265
  sessionManager.saveSessionState(messages, activeFiles, getSessionTodos(sessionId));
1210
1266
  }
1211
1267
  catch (error) {
1212
- console.error(pc.red(`\n[ERROR] Error: ${error.message}`));
1213
1268
  try {
1214
1269
  const filesContext = buildFileContext();
1215
1270
  const userContent = `${filesContext}User Prompt: ${message}`;
1216
- console.log(pc.yellow('\n[RETRY] Trying fallback mode...'));
1271
+ console.log(pc.yellow('\n [RETRY] Trying fallback mode...'));
1217
1272
  await callModelWithFallback(userContent, base64);
1218
1273
  sessionManager.saveSessionState(messages, activeFiles, getSessionTodos(sessionId));
1219
1274
  }
1220
1275
  catch (fallbackErr) {
1221
- console.error(pc.red(`\n[ERROR] Fallback also failed: ${fallbackErr.message}`));
1276
+ const firstLine = (fallbackErr.message || '').split('\n')[0];
1277
+ console.log(pc.red(`\n ${pc.bold('[ERROR]')} Fallback also failed: ${firstLine}`));
1222
1278
  }
1223
1279
  }
1224
1280
  turnSeparator();
@@ -1240,7 +1296,6 @@ async function chatLoop() {
1240
1296
  sessionManager.saveSessionState(messages, activeFiles, getSessionTodos(sessionId));
1241
1297
  }
1242
1298
  catch (error) {
1243
- console.error(pc.red(`\n[ERROR] Error: ${error.message}`));
1244
1299
  }
1245
1300
  turnSeparator();
1246
1301
  continue;
@@ -1730,6 +1785,23 @@ Once you have finished making changes, I will automatically re-run the command t
1730
1785
  turnSeparator();
1731
1786
  continue;
1732
1787
  }
1788
+ // Command: /ensemble <goal> — run multi-model ensemble drafting pipeline
1789
+ if (lowerInput.startsWith('/ensemble ') || lowerInput === '/ensemble') {
1790
+ const ensembleGoal = trimmedInput.substring(9).trim();
1791
+ if (!ensembleGoal) {
1792
+ console.log(pc.red(' Error: Please specify a goal for the ensemble draft. Example: /ensemble Implement feature X'));
1793
+ continue;
1794
+ }
1795
+ try {
1796
+ const { runEnsembleWorkflow } = await import('./agents/ensemble.js');
1797
+ await runEnsembleWorkflow(ensembleGoal, toolContext, config, router);
1798
+ }
1799
+ catch (err) {
1800
+ console.log(pc.red(`\n Error in ensemble drafting: ${err.message}`));
1801
+ }
1802
+ turnSeparator();
1803
+ continue;
1804
+ }
1733
1805
  // Command: /commit — stage and commit changes
1734
1806
  if (lowerInput === '/commit' || lowerInput.startsWith('/commit ')) {
1735
1807
  const forcedMsg = trimmedInput.startsWith('/commit ') ? trimmedInput.substring(8).trim() : '';
@@ -1939,11 +2011,10 @@ Once you have finished making changes, I will automatically re-run the command t
1939
2011
  await extractAndSave(router, sessionManager, messages);
1940
2012
  }
1941
2013
  catch (error) {
1942
- console.error(pc.red(`\n[ERROR] Error: ${error.message}`));
1943
2014
  try {
1944
2015
  const filesContext = buildFileContext();
1945
2016
  const userContent = `${filesContext}User Prompt: ${trimmedInput}`;
1946
- console.log(pc.yellow('\n[RETRY] Trying fallback mode...'));
2017
+ console.log(pc.yellow('\n [RETRY] Trying fallback mode...'));
1947
2018
  const fallbackResult = await callModelWithFallback(userContent);
1948
2019
  if (fallbackResult) {
1949
2020
  // Persist session after fallback too
@@ -1952,8 +2023,9 @@ Once you have finished making changes, I will automatically re-run the command t
1952
2023
  }
1953
2024
  }
1954
2025
  catch (fallbackErr) {
1955
- console.error(pc.red(`\n[ERROR] Fallback also failed: ${fallbackErr.message}`));
1956
- console.error(pc.gray('Check that at least one local server is running.'));
2026
+ const firstLine = (fallbackErr.message || '').split('\n')[0];
2027
+ console.log(pc.red(`\n ${pc.bold('[ERROR]')} Fallback also failed: ${firstLine}`));
2028
+ console.log(pc.dim(' Check that at least one local server is running or run /doctor to debug.'));
1957
2029
  }
1958
2030
  }
1959
2031
  turnSeparator();