@morphllm/morphsdk 0.2.114 → 0.2.116

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.
Files changed (48) hide show
  1. package/dist/{chunk-HI35Y6EZ.js → chunk-3JVHMOYJ.js} +18 -5
  2. package/dist/chunk-3JVHMOYJ.js.map +1 -0
  3. package/dist/{chunk-ALTKGCG5.js → chunk-5JARN2NG.js} +2 -2
  4. package/dist/{chunk-3U7AWFBN.js → chunk-62OVBE6G.js} +5 -5
  5. package/dist/{chunk-FL4ZBHK2.js → chunk-GENFEPHG.js} +2 -2
  6. package/dist/{chunk-23R562QJ.js → chunk-OVNPKTEG.js} +9 -4
  7. package/dist/chunk-OVNPKTEG.js.map +1 -0
  8. package/dist/{chunk-YY7NZLAI.js → chunk-RBOCP2MX.js} +42 -20
  9. package/dist/chunk-RBOCP2MX.js.map +1 -0
  10. package/dist/{client-Bm_umdno.d.ts → client-D7iO2TbA.d.ts} +7 -0
  11. package/dist/client.cjs +61 -23
  12. package/dist/client.cjs.map +1 -1
  13. package/dist/client.d.ts +1 -1
  14. package/dist/client.js +6 -6
  15. package/dist/index.cjs +61 -23
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +6 -6
  19. package/dist/tools/warp_grep/agent/runner.cjs +41 -19
  20. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  21. package/dist/tools/warp_grep/agent/runner.js +1 -1
  22. package/dist/tools/warp_grep/anthropic.cjs +39 -19
  23. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  24. package/dist/tools/warp_grep/anthropic.js +3 -3
  25. package/dist/tools/warp_grep/client.cjs +49 -21
  26. package/dist/tools/warp_grep/client.cjs.map +1 -1
  27. package/dist/tools/warp_grep/client.d.ts +7 -1
  28. package/dist/tools/warp_grep/client.js +4 -2
  29. package/dist/tools/warp_grep/gemini.cjs +39 -19
  30. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  31. package/dist/tools/warp_grep/gemini.js +2 -2
  32. package/dist/tools/warp_grep/index.cjs +47 -21
  33. package/dist/tools/warp_grep/index.cjs.map +1 -1
  34. package/dist/tools/warp_grep/index.js +2 -2
  35. package/dist/tools/warp_grep/openai.cjs +39 -19
  36. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  37. package/dist/tools/warp_grep/openai.js +3 -3
  38. package/dist/tools/warp_grep/vercel.cjs +247 -21
  39. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  40. package/dist/tools/warp_grep/vercel.d.ts +7 -0
  41. package/dist/tools/warp_grep/vercel.js +3 -3
  42. package/package.json +6 -1
  43. package/dist/chunk-23R562QJ.js.map +0 -1
  44. package/dist/chunk-HI35Y6EZ.js.map +0 -1
  45. package/dist/chunk-YY7NZLAI.js.map +0 -1
  46. /package/dist/{chunk-ALTKGCG5.js.map → chunk-5JARN2NG.js.map} +0 -0
  47. /package/dist/{chunk-3U7AWFBN.js.map → chunk-62OVBE6G.js.map} +0 -0
  48. /package/dist/{chunk-FL4ZBHK2.js.map → chunk-GENFEPHG.js.map} +0 -0
@@ -3,12 +3,12 @@ import {
3
3
  execute,
4
4
  openai_default,
5
5
  warpGrepTool
6
- } from "../../chunk-FL4ZBHK2.js";
6
+ } from "../../chunk-GENFEPHG.js";
7
7
  import "../../chunk-KW7OEGZK.js";
8
8
  import {
9
9
  formatResult
10
- } from "../../chunk-23R562QJ.js";
11
- import "../../chunk-YY7NZLAI.js";
10
+ } from "../../chunk-OVNPKTEG.js";
11
+ import "../../chunk-RBOCP2MX.js";
12
12
  import "../../chunk-PUGSTXLO.js";
13
13
  import "../../chunk-3MLWXJTJ.js";
14
14
  import "../../chunk-SNGGSPYJ.js";
@@ -1370,27 +1370,41 @@ async function callModel(messages, model, options = {}) {
1370
1370
  maxRetries: options.retryConfig?.maxRetries,
1371
1371
  timeout: timeoutMs
1372
1372
  });
1373
- let data;
1374
- try {
1375
- data = await client.chat.completions.create({
1376
- model,
1377
- temperature: 0,
1378
- max_tokens: 1024,
1379
- messages
1380
- });
1381
- } catch (error) {
1382
- if (error instanceof import_openai.default.APIError && error.status === 404) {
1373
+ const MAX_EMPTY_RETRIES = 1;
1374
+ for (let attempt = 0; attempt <= MAX_EMPTY_RETRIES; attempt++) {
1375
+ let data;
1376
+ try {
1377
+ data = await client.chat.completions.create({
1378
+ model,
1379
+ temperature: 0,
1380
+ max_tokens: 1024,
1381
+ messages
1382
+ });
1383
+ } catch (error) {
1384
+ if (error instanceof import_openai.default.APIError && error.status === 404) {
1385
+ throw new Error(
1386
+ "The endpoint you are trying to call is likely deprecated. Please update with: npm cache clean --force && npx -y @morphllm/morphmcp@latest or visit: https://morphllm.com/mcp"
1387
+ );
1388
+ }
1389
+ throw error;
1390
+ }
1391
+ const choice = data?.choices?.[0];
1392
+ const content = choice?.message?.content;
1393
+ if (content && typeof content === "string") {
1394
+ return content;
1395
+ }
1396
+ if (attempt === MAX_EMPTY_RETRIES) {
1397
+ const finishReason = choice?.finish_reason ?? "unknown";
1398
+ const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;
1399
+ const choicesLen = data?.choices?.length ?? 0;
1400
+ const contentType = content === null ? "null" : content === void 0 ? "undefined" : typeof content;
1383
1401
  throw new Error(
1384
- "The endpoint you are trying to call is likely deprecated. Please update with: npm cache clean --force && npx -y @morphllm/morphmcp@latest or visit: https://morphllm.com/mcp"
1402
+ `Invalid response from model: content=${contentType}, finish_reason=${finishReason}, has_tool_calls=${hasToolCalls}, choices_length=${choicesLen}`
1385
1403
  );
1386
1404
  }
1387
- throw error;
1388
- }
1389
- const content = data?.choices?.[0]?.message?.content;
1390
- if (!content || typeof content !== "string") {
1391
- throw new Error("Invalid response from model");
1405
+ await new Promise((resolve) => setTimeout(resolve, 200));
1392
1406
  }
1393
- return content;
1407
+ throw new Error("Invalid response from model");
1394
1408
  }
1395
1409
  async function runWarpGrep(config) {
1396
1410
  const totalStart = Date.now();
@@ -1419,22 +1433,180 @@ async function runWarpGrep(config) {
1419
1433
  retryConfig: config.retryConfig,
1420
1434
  timeout: timeoutMs
1421
1435
  }).catch((e) => {
1422
- errors.push({ message: e instanceof Error ? e.message : String(e) });
1436
+ const errMsg = e instanceof Error ? e.message : String(e);
1437
+ console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
1438
+ errors.push({ message: errMsg });
1439
+ return "";
1440
+ });
1441
+ turnMetrics.morph_api_ms = Date.now() - modelCallStart;
1442
+ if (!assistantContent) {
1443
+ console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
1444
+ timings.turns.push(turnMetrics);
1445
+ break;
1446
+ }
1447
+ messages.push({ role: "assistant", content: assistantContent });
1448
+ const toolCalls = parser.parse(assistantContent);
1449
+ if (toolCalls.length === 0) {
1450
+ console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
1451
+ errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: rm -rf ~/.npm/_npx && npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
1452
+ terminationReason = "terminated";
1453
+ timings.turns.push(turnMetrics);
1454
+ break;
1455
+ }
1456
+ const finishCalls = toolCalls.filter((c) => c.name === "finish");
1457
+ const grepCalls = toolCalls.filter((c) => c.name === "grep");
1458
+ const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
1459
+ const readCalls = toolCalls.filter((c) => c.name === "read");
1460
+ const skipCalls = toolCalls.filter((c) => c.name === "_skip");
1461
+ const formatted = [];
1462
+ for (const c of skipCalls) {
1463
+ const msg = c.arguments?.message || "Command skipped due to parsing error";
1464
+ formatted.push(msg);
1465
+ }
1466
+ const allPromises = [];
1467
+ for (const c of grepCalls) {
1468
+ const args = c.arguments ?? {};
1469
+ allPromises.push(
1470
+ toolGrep(provider, args).then(
1471
+ ({ output }) => formatAgentToolOutput("grep", args, output, { isError: false }),
1472
+ (err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
1473
+ )
1474
+ );
1475
+ }
1476
+ for (const c of listDirCalls) {
1477
+ const args = c.arguments ?? {};
1478
+ allPromises.push(
1479
+ toolListDirectory(provider, args).then(
1480
+ (p) => formatAgentToolOutput("list_directory", args, p, { isError: false }),
1481
+ (err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
1482
+ )
1483
+ );
1484
+ }
1485
+ for (const c of readCalls) {
1486
+ const args = c.arguments ?? {};
1487
+ allPromises.push(
1488
+ toolRead(provider, args).then(
1489
+ (p) => formatAgentToolOutput("read", args, p, { isError: false }),
1490
+ (err) => formatAgentToolOutput("read", args, String(err), { isError: true })
1491
+ )
1492
+ );
1493
+ }
1494
+ const toolExecStart = Date.now();
1495
+ const allResults = await Promise.all(allPromises);
1496
+ turnMetrics.local_tools_ms = Date.now() - toolExecStart;
1497
+ for (const result of allResults) {
1498
+ formatted.push(result);
1499
+ }
1500
+ if (formatted.length > 0) {
1501
+ const turnMessage = formatTurnMessage(turn, maxTurns);
1502
+ const contextBudget = calculateContextBudget(messages);
1503
+ messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
1504
+ }
1505
+ timings.turns.push(turnMetrics);
1506
+ if (finishCalls.length) {
1507
+ const fc = finishCalls[0];
1508
+ const files = fc.arguments?.files ?? [];
1509
+ finishMeta = { files };
1510
+ terminationReason = "completed";
1511
+ break;
1512
+ }
1513
+ }
1514
+ if (terminationReason !== "completed" || !finishMeta) {
1515
+ timings.total_ms = Date.now() - totalStart;
1516
+ return { terminationReason, messages, errors, timings };
1517
+ }
1518
+ const parts = ["Relevant context found:"];
1519
+ for (const f of finishMeta.files) {
1520
+ const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
1521
+ parts.push(`- ${f.path}: ${ranges}`);
1522
+ }
1523
+ const payload = parts.join("\n");
1524
+ const finishResolutionStart = Date.now();
1525
+ const fileReadErrors = [];
1526
+ const resolved = await readFinishFiles(
1527
+ repoRoot,
1528
+ finishMeta.files,
1529
+ async (p, s, e) => {
1530
+ try {
1531
+ const rr = await provider.read({ path: p, start: s, end: e });
1532
+ return rr.lines.map((l) => {
1533
+ const idx = l.indexOf("|");
1534
+ return idx >= 0 ? l.slice(idx + 1) : l;
1535
+ });
1536
+ } catch (err) {
1537
+ const errorMsg = err instanceof Error ? err.message : String(err);
1538
+ fileReadErrors.push({ path: p, error: errorMsg });
1539
+ console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
1540
+ return [`[couldn't find: ${p}]`];
1541
+ }
1542
+ }
1543
+ );
1544
+ timings.finish_resolution_ms = Date.now() - finishResolutionStart;
1545
+ if (fileReadErrors.length > 0) {
1546
+ errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
1547
+ }
1548
+ timings.total_ms = Date.now() - totalStart;
1549
+ return {
1550
+ terminationReason: "completed",
1551
+ messages,
1552
+ finish: { payload, metadata: finishMeta, resolved },
1553
+ timings
1554
+ };
1555
+ }
1556
+ async function* runWarpGrepStreaming(config) {
1557
+ const totalStart = Date.now();
1558
+ const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
1559
+ const timings = { turns: [], timeout_ms: timeoutMs };
1560
+ const repoRoot = import_path2.default.resolve(config.repoRoot || process.cwd());
1561
+ const messages = [];
1562
+ messages.push({ role: "system", content: getSystemPrompt() });
1563
+ const initialStateStart = Date.now();
1564
+ const initialState = await buildInitialState(repoRoot, config.query, config.provider);
1565
+ timings.initial_state_ms = Date.now() - initialStateStart;
1566
+ messages.push({ role: "user", content: initialState });
1567
+ const maxTurns = AGENT_CONFIG.MAX_TURNS;
1568
+ const model = config.model || DEFAULT_MODEL;
1569
+ const provider = config.provider;
1570
+ const errors = [];
1571
+ let finishMeta;
1572
+ let terminationReason = "terminated";
1573
+ for (let turn = 1; turn <= maxTurns; turn += 1) {
1574
+ const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
1575
+ enforceContextLimit(messages);
1576
+ const modelCallStart = Date.now();
1577
+ const assistantContent = await callModel(messages, model, {
1578
+ morphApiKey: config.morphApiKey,
1579
+ morphApiUrl: config.morphApiUrl,
1580
+ retryConfig: config.retryConfig,
1581
+ timeout: timeoutMs
1582
+ }).catch((e) => {
1583
+ const errMsg = e instanceof Error ? e.message : String(e);
1584
+ console.error(`[warp_grep:stream] Morph API call failed on turn ${turn}:`, errMsg);
1585
+ errors.push({ message: errMsg });
1423
1586
  return "";
1424
1587
  });
1425
1588
  turnMetrics.morph_api_ms = Date.now() - modelCallStart;
1426
1589
  if (!assistantContent) {
1590
+ console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
1427
1591
  timings.turns.push(turnMetrics);
1428
1592
  break;
1429
1593
  }
1430
1594
  messages.push({ role: "assistant", content: assistantContent });
1431
1595
  const toolCalls = parser.parse(assistantContent);
1432
1596
  if (toolCalls.length === 0) {
1597
+ console.error(`[warp_grep:stream] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
1433
1598
  errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: rm -rf ~/.npm/_npx && npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
1434
1599
  terminationReason = "terminated";
1435
1600
  timings.turns.push(turnMetrics);
1436
1601
  break;
1437
1602
  }
1603
+ yield {
1604
+ turn,
1605
+ toolCalls: toolCalls.map((c) => ({
1606
+ name: c.name,
1607
+ arguments: c.arguments ?? {}
1608
+ }))
1609
+ };
1438
1610
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
1439
1611
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
1440
1612
  const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
@@ -1739,7 +1911,9 @@ async function executeToolCall(input, config) {
1739
1911
  });
1740
1912
  const finish = result.finish;
1741
1913
  if (result.terminationReason !== "completed" || !finish?.metadata) {
1742
- return { success: false, error: "Search did not complete" };
1914
+ const errorDetails = result.errors?.map((e) => e.message).join("; ") || "unknown reason";
1915
+ console.error(`[warp_grep] executeToolCall failed. Reason: ${result.terminationReason}. Errors: ${errorDetails}. Turns: ${result.timings?.turns?.length ?? 0}`);
1916
+ return { success: false, error: `Search did not complete: ${errorDetails}` };
1743
1917
  }
1744
1918
  const contexts = (finish.resolved ?? []).map((r) => ({
1745
1919
  file: r.path,
@@ -1748,6 +1922,46 @@ async function executeToolCall(input, config) {
1748
1922
  }));
1749
1923
  return { success: true, contexts, summary: finish.payload };
1750
1924
  }
1925
+ function processAgentResult(result) {
1926
+ const finish = result.finish;
1927
+ if (result.terminationReason !== "completed" || !finish?.metadata) {
1928
+ const errorDetails = result.errors?.map((e) => e.message).join("; ") || "unknown reason";
1929
+ console.error(`[warp_grep] processAgentResult failed. Reason: ${result.terminationReason}. Errors: ${errorDetails}. Turns: ${result.timings?.turns?.length ?? 0}`);
1930
+ return { success: false, error: `Search did not complete: ${errorDetails}` };
1931
+ }
1932
+ const contexts = (finish.resolved ?? []).map((r) => ({
1933
+ file: r.path,
1934
+ content: r.content,
1935
+ lines: r.ranges
1936
+ }));
1937
+ return { success: true, contexts, summary: finish.payload };
1938
+ }
1939
+ async function* executeToolCallStreaming(input, config) {
1940
+ const parsed = typeof input === "string" ? JSON.parse(input) : input;
1941
+ const provider = config.remoteCommands ? new RemoteCommandsProvider(config.repoRoot, config.remoteCommands) : config.provider ?? await getLocalProvider(config.repoRoot, config.excludes);
1942
+ const generator = runWarpGrepStreaming({
1943
+ query: parsed.query,
1944
+ repoRoot: config.repoRoot,
1945
+ provider,
1946
+ excludes: config.excludes,
1947
+ includes: config.includes,
1948
+ debug: config.debug ?? false,
1949
+ morphApiKey: config.morphApiKey,
1950
+ morphApiUrl: config.morphApiUrl,
1951
+ retryConfig: config.retryConfig,
1952
+ timeout: config.timeout
1953
+ });
1954
+ let agentResult;
1955
+ for (; ; ) {
1956
+ const { value, done } = await generator.next();
1957
+ if (done) {
1958
+ agentResult = value;
1959
+ break;
1960
+ }
1961
+ yield value;
1962
+ }
1963
+ return processAgentResult(agentResult);
1964
+ }
1751
1965
  function formatResult(result) {
1752
1966
  if (!result.success) {
1753
1967
  return `Search failed: ${result.error}`;
@@ -1799,14 +2013,26 @@ function createWarpGrepTool(config) {
1799
2013
  description: config.description ?? WARP_GREP_DESCRIPTION,
1800
2014
  inputSchema: schema,
1801
2015
  execute: async (params) => {
1802
- const result = await executeToolCall(params, config);
2016
+ const steps = [];
2017
+ const generator = executeToolCallStreaming(params, config);
2018
+ let result;
2019
+ for (; ; ) {
2020
+ const { value, done } = await generator.next();
2021
+ if (done) {
2022
+ result = value;
2023
+ break;
2024
+ }
2025
+ steps.push(value);
2026
+ }
1803
2027
  if (!result.success) {
1804
2028
  throw new Error(`Failed to search codebase: ${result.error}`);
1805
2029
  }
2030
+ const allToolCalls = steps.flatMap((s) => s.toolCalls);
1806
2031
  return {
1807
2032
  success: true,
1808
2033
  contexts: result.contexts,
1809
- summary: result.summary
2034
+ summary: result.summary,
2035
+ progress: allToolCalls.length > 0 ? { turn: steps.length, toolCalls: allToolCalls } : void 0
1810
2036
  };
1811
2037
  }
1812
2038
  });