codeply-cli 0.4.1 → 0.5.1

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/lib/agent.mjs CHANGED
@@ -338,6 +338,7 @@ const PARAMS = {
338
338
  plan_exit: ['path'],
339
339
  plan_enter: ['reason'],
340
340
  lsp: ['operation', 'path', 'line', 'character', 'symbol', 'query'],
341
+ ask_bot: ['bot', 'task'], // only offered when the host passes askBot (lib/bots.js)
341
342
  };
342
343
 
343
344
  // Names the model actually reaches for when it paraphrases the format.
@@ -1097,6 +1098,9 @@ export function buildSystemPrompt(mode, cwd, userMessage, opts = {}) {
1097
1098
  // reference, so it colors how every tool gets used.
1098
1099
  const role = opts.roleId ? rolesLib.getSubagent(opts.roleId) : null;
1099
1100
  if (role) parts.push('', ROLE_INTRO(role), role.persona);
1101
+ // A bot (lib/bots.js): identity, specialty, tone, approval boundary, memory, team.
1102
+ const botPrompt = typeof opts.botPrompt === 'function' ? opts.botPrompt(!!opts.native) : opts.botPrompt;
1103
+ if (botPrompt) parts.push('', botPrompt);
1100
1104
  if (opts.goal) {
1101
1105
  parts.push('', `GOAL MODE\nYou are working autonomously toward this goal until it is fully achieved:\n"${opts.goal}"\n` +
1102
1106
  'Keep going without asking the user questions - make sensible, conventional decisions yourself and note them in your summary. ' +
@@ -1424,7 +1428,7 @@ function withoutEmDashes(text) {
1424
1428
  * "claims an edit it didn't make this turn" check is skipped.
1425
1429
  * @yields {{type:string, ...}} text | reasoning | tool_start | tool_end | done | error | aborted
1426
1430
  */
1427
- export async function* runAgent({ userMessage, history, mode, cwd, approve, browser, images, signal, route, roleId, goal, maxSteps, verifyOnly }) {
1431
+ export async function* runAgent({ userMessage, history, mode, cwd, approve, browser, images, signal, route, roleId, goal, maxSteps, verifyOnly, botPrompt, askBot }) {
1428
1432
  let readOnly = READ_ONLY_MODES.has(mode);
1429
1433
  const stepBudget = Math.max(1, maxSteps || MAX_STEPS);
1430
1434
  // OpenAI-shaped content array only when there's actually an image to carry -
@@ -1451,6 +1455,7 @@ export async function* runAgent({ userMessage, history, mode, cwd, approve, brow
1451
1455
  const entries = Object.entries(PARAMS).filter(([n]) => {
1452
1456
  if (n === 'plan_exit') return m === 'Plan';
1453
1457
  if (n === 'plan_enter') return m === 'Build';
1458
+ if (n === 'ask_bot') return typeof askBot === 'function';
1454
1459
  if (ro && MUTATING_ACTIONS.has(n)) return m === 'Plan' && (n === 'write_file' || n === 'edit_file');
1455
1460
  return true;
1456
1461
  });
@@ -1458,13 +1463,13 @@ export async function* runAgent({ userMessage, history, mode, cwd, approve, brow
1458
1463
  };
1459
1464
  let toolSchemas = schemasFor(mode);
1460
1465
  const messages = [
1461
- { role: 'system', content: buildSystemPrompt(mode, cwd, userMessage, { roleId, goal, native, mcp: mcpList }) },
1466
+ { role: 'system', content: buildSystemPrompt(mode, cwd, userMessage, { roleId, goal, native, mcp: mcpList, botPrompt }) },
1462
1467
  ...history,
1463
1468
  { role: 'user', content: userContent },
1464
1469
  ];
1465
1470
 
1466
1471
  // fileState: path -> mtime when this turn last read/wrote it (see tools.mjs).
1467
- const ctx = { cwd, approve, browser, signal, mode, route, fileState: new Map(), ask: typeof approve?.ask === 'function' ? approve.ask : null };
1472
+ const ctx = { cwd, approve, browser, signal, mode, route, fileState: new Map(), ask: typeof approve?.ask === 'function' ? approve.ask : null, askBot: typeof askBot === 'function' ? askBot : null };
1468
1473
  const recentCallKeys = []; // executed calls, in order, for the stuck-loop guard
1469
1474
  const lastResultFor = new Map(); // call key -> its most recent result
1470
1475
  const transcript = [{ role: 'user', content: userMessage }];
@@ -1585,7 +1590,7 @@ export async function* runAgent({ userMessage, history, mode, cwd, approve, brow
1585
1590
  if (native && !attempt.result.success && !signal.aborted && TOOLS_UNSUPPORTED.test(String(attempt.result.error || ''))) {
1586
1591
  native = false;
1587
1592
  nativeUnsupported.add(nativeKey);
1588
- messages[0] = { role: 'system', content: buildSystemPrompt(mode, cwd, userMessage, { roleId, goal, native: false, mcp: mcpList }) };
1593
+ messages[0] = { role: 'system', content: buildSystemPrompt(mode, cwd, userMessage, { roleId, goal, native: false, mcp: mcpList, botPrompt }) };
1589
1594
  outgoing = [messages[0], ...outgoing.slice(1)];
1590
1595
  yield { type: 'notice', level: 'info', text: 'This model does not support native tool calls, so Codeply switched to text actions.' };
1591
1596
  attempt = await callModel(outgoing, userMessage, signal, route);
@@ -1905,6 +1910,9 @@ export async function* runAgent({ userMessage, history, mode, cwd, approve, brow
1905
1910
  ok: out.ok,
1906
1911
  meta: out.meta,
1907
1912
  summary: out.meta?.label,
1913
+ // The real reason a tool failed, so the card can show it even when
1914
+ // the model's own summary of it is vague.
1915
+ error: out.ok || out.meta?.rejected ? undefined : String(out.output || '').slice(0, 800),
1908
1916
  ms,
1909
1917
  needsApproval,
1910
1918
  };