@morphllm/morphsdk 0.2.82 → 0.2.83

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 (43) hide show
  1. package/dist/{chunk-EK5ZEOI3.js → chunk-HPR6BJA7.js} +5 -5
  2. package/dist/{chunk-FJKPMMNQ.js → chunk-HRK53IKL.js} +2 -2
  3. package/dist/{chunk-24EYSWME.js → chunk-LXG37353.js} +2 -2
  4. package/dist/{chunk-WIAYUEJK.js → chunk-QOYI77CN.js} +25 -5
  5. package/dist/chunk-QOYI77CN.js.map +1 -0
  6. package/dist/{chunk-ZLJAODDJ.js → chunk-RL4JBZ3T.js} +2 -2
  7. package/dist/{chunk-3ONNAQZU.js → chunk-S27A4NQM.js} +2 -2
  8. package/dist/client.cjs +24 -4
  9. package/dist/client.cjs.map +1 -1
  10. package/dist/client.js +6 -6
  11. package/dist/index.cjs +24 -4
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.js +6 -6
  14. package/dist/tools/warp_grep/agent/runner.cjs +24 -4
  15. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  16. package/dist/tools/warp_grep/agent/runner.js +1 -1
  17. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  18. package/dist/tools/warp_grep/agent/types.d.ts +14 -1
  19. package/dist/tools/warp_grep/anthropic.cjs +24 -4
  20. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  21. package/dist/tools/warp_grep/anthropic.js +3 -3
  22. package/dist/tools/warp_grep/client.cjs +24 -4
  23. package/dist/tools/warp_grep/client.cjs.map +1 -1
  24. package/dist/tools/warp_grep/client.js +2 -2
  25. package/dist/tools/warp_grep/gemini.cjs +24 -4
  26. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  27. package/dist/tools/warp_grep/gemini.js +2 -2
  28. package/dist/tools/warp_grep/index.cjs +24 -4
  29. package/dist/tools/warp_grep/index.cjs.map +1 -1
  30. package/dist/tools/warp_grep/index.js +2 -2
  31. package/dist/tools/warp_grep/openai.cjs +24 -4
  32. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  33. package/dist/tools/warp_grep/openai.js +3 -3
  34. package/dist/tools/warp_grep/vercel.cjs +24 -4
  35. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  36. package/dist/tools/warp_grep/vercel.js +3 -3
  37. package/package.json +1 -1
  38. package/dist/chunk-WIAYUEJK.js.map +0 -1
  39. /package/dist/{chunk-EK5ZEOI3.js.map → chunk-HPR6BJA7.js.map} +0 -0
  40. /package/dist/{chunk-FJKPMMNQ.js.map → chunk-HRK53IKL.js.map} +0 -0
  41. /package/dist/{chunk-24EYSWME.js.map → chunk-LXG37353.js.map} +0 -0
  42. /package/dist/{chunk-ZLJAODDJ.js.map → chunk-RL4JBZ3T.js.map} +0 -0
  43. /package/dist/{chunk-3ONNAQZU.js.map → chunk-S27A4NQM.js.map} +0 -0
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createWarpGrepTool as createWarpGrepTool2
3
- } from "./chunk-ZLJAODDJ.js";
3
+ } from "./chunk-RL4JBZ3T.js";
4
4
  import {
5
5
  createWarpGrepTool
6
- } from "./chunk-24EYSWME.js";
6
+ } from "./chunk-LXG37353.js";
7
7
  import {
8
8
  createWarpGrepTool as createWarpGrepTool3
9
- } from "./chunk-3ONNAQZU.js";
9
+ } from "./chunk-S27A4NQM.js";
10
10
  import {
11
11
  WarpGrepClient
12
- } from "./chunk-FJKPMMNQ.js";
12
+ } from "./chunk-HRK53IKL.js";
13
13
  import {
14
14
  createCodebaseSearchTool as createCodebaseSearchTool3
15
15
  } from "./chunk-UBX7QYBD.js";
@@ -280,4 +280,4 @@ export {
280
280
  VercelToolFactory,
281
281
  MorphClient
282
282
  };
283
- //# sourceMappingURL=chunk-EK5ZEOI3.js.map
283
+ //# sourceMappingURL=chunk-HPR6BJA7.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runWarpGrep
3
- } from "./chunk-WIAYUEJK.js";
3
+ } from "./chunk-QOYI77CN.js";
4
4
  import {
5
5
  RemoteCommandsProvider
6
6
  } from "./chunk-PUGSTXLO.js";
@@ -117,4 +117,4 @@ export {
117
117
  executeToolCall,
118
118
  formatResult
119
119
  };
120
- //# sourceMappingURL=chunk-FJKPMMNQ.js.map
120
+ //# sourceMappingURL=chunk-HRK53IKL.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  executeToolCall,
7
7
  formatResult
8
- } from "./chunk-FJKPMMNQ.js";
8
+ } from "./chunk-HRK53IKL.js";
9
9
  import {
10
10
  getSystemPrompt
11
11
  } from "./chunk-FMLHRJDF.js";
@@ -58,4 +58,4 @@ export {
58
58
  createWarpGrepTool,
59
59
  openai_default
60
60
  };
61
- //# sourceMappingURL=chunk-24EYSWME.js.map
61
+ //# sourceMappingURL=chunk-LXG37353.js.map
@@ -69,10 +69,15 @@ async function callModel(messages, model, options = {}) {
69
69
  return content;
70
70
  }
71
71
  async function runWarpGrep(config) {
72
+ const totalStart = Date.now();
73
+ const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
74
+ const timings = { turns: [], timeout_ms: timeoutMs };
72
75
  const repoRoot = path.resolve(config.repoRoot || process.cwd());
73
76
  const messages = [];
74
77
  messages.push({ role: "system", content: getSystemPrompt() });
78
+ const initialStateStart = Date.now();
75
79
  const initialState = await buildInitialState(repoRoot, config.query, config.provider);
80
+ timings.initial_state_ms = Date.now() - initialStateStart;
76
81
  messages.push({ role: "user", content: initialState });
77
82
  const maxTurns = AGENT_CONFIG.MAX_TURNS;
78
83
  const model = config.model || DEFAULT_MODEL;
@@ -81,22 +86,29 @@ async function runWarpGrep(config) {
81
86
  let finishMeta;
82
87
  let terminationReason = "terminated";
83
88
  for (let turn = 1; turn <= maxTurns; turn += 1) {
89
+ const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
84
90
  enforceContextLimit(messages);
91
+ const modelCallStart = Date.now();
85
92
  const assistantContent = await callModel(messages, model, {
86
93
  morphApiKey: config.morphApiKey,
87
94
  morphApiUrl: config.morphApiUrl,
88
95
  retryConfig: config.retryConfig,
89
- timeout: config.timeout
96
+ timeout: timeoutMs
90
97
  }).catch((e) => {
91
98
  errors.push({ message: e instanceof Error ? e.message : String(e) });
92
99
  return "";
93
100
  });
94
- if (!assistantContent) break;
101
+ turnMetrics.morph_api_ms = Date.now() - modelCallStart;
102
+ if (!assistantContent) {
103
+ timings.turns.push(turnMetrics);
104
+ break;
105
+ }
95
106
  messages.push({ role: "assistant", content: assistantContent });
96
107
  const toolCalls = parser.parse(assistantContent);
97
108
  if (toolCalls.length === 0) {
98
109
  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" });
99
110
  terminationReason = "terminated";
111
+ timings.turns.push(turnMetrics);
100
112
  break;
101
113
  }
102
114
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
@@ -137,7 +149,9 @@ async function runWarpGrep(config) {
137
149
  )
138
150
  );
139
151
  }
152
+ const toolExecStart = Date.now();
140
153
  const allResults = await Promise.all(allPromises);
154
+ turnMetrics.local_tools_ms = Date.now() - toolExecStart;
141
155
  for (const result of allResults) {
142
156
  formatted.push(result);
143
157
  }
@@ -146,6 +160,7 @@ async function runWarpGrep(config) {
146
160
  const contextBudget = calculateContextBudget(messages);
147
161
  messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
148
162
  }
163
+ timings.turns.push(turnMetrics);
149
164
  if (finishCalls.length) {
150
165
  const fc = finishCalls[0];
151
166
  const files = fc.arguments?.files ?? [];
@@ -155,7 +170,8 @@ async function runWarpGrep(config) {
155
170
  }
156
171
  }
157
172
  if (terminationReason !== "completed" || !finishMeta) {
158
- return { terminationReason, messages, errors };
173
+ timings.total_ms = Date.now() - totalStart;
174
+ return { terminationReason, messages, errors, timings };
159
175
  }
160
176
  const parts = ["Relevant context found:"];
161
177
  for (const f of finishMeta.files) {
@@ -163,6 +179,7 @@ async function runWarpGrep(config) {
163
179
  parts.push(`- ${f.path}: ${ranges}`);
164
180
  }
165
181
  const payload = parts.join("\n");
182
+ const finishResolutionStart = Date.now();
166
183
  const fileReadErrors = [];
167
184
  const resolved = await readFinishFiles(
168
185
  repoRoot,
@@ -182,17 +199,20 @@ async function runWarpGrep(config) {
182
199
  }
183
200
  }
184
201
  );
202
+ timings.finish_resolution_ms = Date.now() - finishResolutionStart;
185
203
  if (fileReadErrors.length > 0) {
186
204
  errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
187
205
  }
206
+ timings.total_ms = Date.now() - totalStart;
188
207
  return {
189
208
  terminationReason: "completed",
190
209
  messages,
191
- finish: { payload, metadata: finishMeta, resolved }
210
+ finish: { payload, metadata: finishMeta, resolved },
211
+ timings
192
212
  };
193
213
  }
194
214
 
195
215
  export {
196
216
  runWarpGrep
197
217
  };
198
- //# sourceMappingURL=chunk-WIAYUEJK.js.map
218
+ //# sourceMappingURL=chunk-QOYI77CN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/agent/runner.ts"],"sourcesContent":["import { AGENT_CONFIG, DEFAULT_MODEL } from './config.js';\nimport { getSystemPrompt } from './prompt.js';\nimport type { AgentRunResult, ChatMessage, SessionConfig, AgentFinish, WarpGrepExecutionMetrics, WarpGrepTurnMetrics } from './types.js';\nimport { LLMResponseParser } from './parser.js';\nimport type { WarpGrepProvider } from '../providers/types.js';\nimport { toolGrep } from './tools/grep.js';\nimport { toolRead } from './tools/read.js';\nimport { toolListDirectory } from './tools/list_directory.js';\nimport { readFinishFiles } from './tools/finish.js';\nimport { fetchWithRetry, withTimeout, type RetryConfig } from '../../utils/resilience.js';\nimport { formatAgentToolOutput } from './formatter.js';\nimport { formatTurnMessage, calculateContextBudget, buildInitialState, enforceContextLimit } from './helpers.js';\nimport path from 'path';\n\ntype EventName =\n | 'initial_state'\n | 'round_start'\n | 'round_end'\n | 'finish'\n | 'error';\n\nexport type EventCallback = (name: EventName, payload: Record<string, unknown>) => void;\n\nconst parser = new LLMResponseParser();\n\nconst DEFAULT_API_URL = 'https://api.morphllm.com';\n\ninterface CallModelOptions {\n morphApiKey?: string;\n morphApiUrl?: string;\n retryConfig?: RetryConfig;\n timeout?: number;\n}\n\nasync function callModel(\n messages: ChatMessage[],\n model: string,\n options: CallModelOptions = {}\n): Promise<string> {\n const baseUrl = options.morphApiUrl || DEFAULT_API_URL;\n const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || '';\n \n const fetchPromise = fetchWithRetry(\n `${baseUrl}/v1/chat/completions`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n temperature: 0.0,\n max_tokens: 1024,\n messages,\n }),\n },\n options.retryConfig\n );\n const timeoutMs = options.timeout ?? AGENT_CONFIG.TIMEOUT_MS;\n const resp = await withTimeout(fetchPromise, timeoutMs, 'morph-warp-grep request timed out');\n if (!resp.ok) {\n if (resp.status === 404) {\n throw new Error(\n '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'\n );\n }\n // keeping these cases are real throws, if this happens retry will likely not help, so best we just throw here, notice the error and fix\n const t = await resp.text();\n throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);\n }\n const data = await resp.json();\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== 'string') {\n throw new Error('Invalid response from model');\n }\n return content;\n}\n\nexport async function runWarpGrep(config: SessionConfig & { provider: WarpGrepProvider }): Promise<AgentRunResult> {\n const totalStart = Date.now();\n const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;\n const timings: Partial<WarpGrepExecutionMetrics> = { turns: [], timeout_ms: timeoutMs };\n \n const repoRoot = path.resolve(config.repoRoot || process.cwd());\n const messages: ChatMessage[] = [];\n\n messages.push({ role: 'system' as const, content: getSystemPrompt() });\n \n const initialStateStart = Date.now();\n const initialState = await buildInitialState(repoRoot, config.query, config.provider);\n timings.initial_state_ms = Date.now() - initialStateStart;\n \n messages.push({ role: 'user', content: initialState });\n\n const maxTurns = AGENT_CONFIG.MAX_TURNS;\n const model = config.model || DEFAULT_MODEL;\n const provider = config.provider;\n const errors: Array<{ message: string }> = [];\n\n let finishMeta: AgentFinish | undefined;\n let terminationReason: AgentRunResult['terminationReason'] = 'terminated';\n\n for (let turn = 1; turn <= maxTurns; turn += 1) {\n const turnMetrics: WarpGrepTurnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };\n \n // Enforce hard context limit before calling model\n enforceContextLimit(messages);\n \n // call model\n const modelCallStart = Date.now();\n const assistantContent = await callModel(messages, model, {\n morphApiKey: config.morphApiKey,\n morphApiUrl: config.morphApiUrl,\n retryConfig: config.retryConfig,\n timeout: timeoutMs,\n }).catch((e: unknown) => {\n errors.push({ message: e instanceof Error ? e.message : String(e) });\n return '';\n });\n turnMetrics.morph_api_ms = Date.now() - modelCallStart;\n \n if (!assistantContent) {\n timings.turns!.push(turnMetrics);\n break;\n }\n messages.push({ role: 'assistant', content: assistantContent });\n\n // parse tool calls (no longer throws - returns _skip calls for malformed commands)\n const toolCalls = parser.parse(assistantContent);\n if (toolCalls.length === 0) {\n 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' });\n terminationReason = 'terminated';\n timings.turns!.push(turnMetrics);\n break;\n }\n\n const finishCalls = toolCalls.filter(c => c.name === 'finish');\n const grepCalls = toolCalls.filter(c => c.name === 'grep');\n const listDirCalls = toolCalls.filter(c => c.name === 'list_directory');\n const readCalls = toolCalls.filter(c => c.name === 'read');\n const skipCalls = toolCalls.filter(c => c.name === '_skip');\n\n const formatted: string[] = [];\n\n // Surface any skipped commands as feedback to the LLM\n for (const c of skipCalls) {\n const msg = (c.arguments as { message?: string })?.message || 'Command skipped due to parsing error';\n formatted.push(msg);\n }\n\n const allPromises: Array<Promise<string>> = [];\n \n for (const c of grepCalls) {\n const args = (c.arguments ?? {}) as { pattern: string; path: string; glob?: string };\n allPromises.push(\n toolGrep(provider, args).then(\n ({ output }) => formatAgentToolOutput('grep', args, output, { isError: false }),\n err => formatAgentToolOutput('grep', args, String(err), { isError: true })\n )\n );\n }\n \n for (const c of listDirCalls) {\n const args = (c.arguments ?? {}) as { path: string; pattern?: string | null };\n allPromises.push(\n toolListDirectory(provider, args).then(\n p => formatAgentToolOutput('list_directory', args, p, { isError: false }),\n err => formatAgentToolOutput('list_directory', args, String(err), { isError: true })\n )\n );\n }\n \n for (const c of readCalls) {\n const args = (c.arguments ?? {}) as { path: string; start?: number; end?: number; lines?: Array<[number, number]> };\n allPromises.push(\n toolRead(provider, args).then(\n p => formatAgentToolOutput('read', args, p, { isError: false }),\n err => formatAgentToolOutput('read', args, String(err), { isError: true })\n )\n );\n }\n \n const toolExecStart = Date.now();\n const allResults = await Promise.all(allPromises);\n turnMetrics.local_tools_ms = Date.now() - toolExecStart;\n \n for (const result of allResults) {\n formatted.push(result);\n }\n\n if (formatted.length > 0) {\n const turnMessage = formatTurnMessage(turn, maxTurns);\n const contextBudget = calculateContextBudget(messages);\n messages.push({ role: 'user', content: formatted.join('\\n') + turnMessage + '\\n' + contextBudget });\n }\n\n timings.turns!.push(turnMetrics);\n\n if (finishCalls.length) {\n const fc = finishCalls[0];\n const files = ((fc.arguments as any)?.files ?? []) as AgentFinish['files'];\n finishMeta = { files };\n terminationReason = 'completed';\n break;\n }\n }\n\n if (terminationReason !== 'completed' || !finishMeta) {\n timings.total_ms = Date.now() - totalStart;\n return { terminationReason, messages, errors, timings: timings as WarpGrepExecutionMetrics };\n }\n\n // Build finish payload\n const parts: string[] = ['Relevant context found:'];\n for (const f of finishMeta.files) {\n const ranges = f.lines === '*' ? '*' \n : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(', ') \n : '*';\n parts.push(`- ${f.path}: ${ranges}`);\n }\n const payload = parts.join('\\n');\n\n // Resolve file contents for returned ranges\n // Wrap reader in try-catch to handle non-existent or unreadable files gracefully\n // Track files that couldn't be read for error reporting\n const finishResolutionStart = Date.now();\n const fileReadErrors: Array<{ path: string; error: string }> = [];\n const resolved = await readFinishFiles(\n repoRoot,\n finishMeta.files,\n async (p: string, s?: number, e?: number) => {\n try {\n const rr = await provider.read({ path: p, start: s, end: e });\n // rr.lines are \"line|content\" → strip the \"line|\" prefix\n return rr.lines.map(l => {\n const idx = l.indexOf('|');\n return idx >= 0 ? l.slice(idx + 1) : l;\n });\n } catch (err) {\n // File doesn't exist or can't be read - log error but don't throw\n // This handles cases where the agent hallucinated a path or the file was deleted\n const errorMsg = err instanceof Error ? err.message : String(err);\n fileReadErrors.push({ path: p, error: errorMsg });\n console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);\n return [`[couldn't find: ${p}]`];\n }\n }\n );\n\n timings.finish_resolution_ms = Date.now() - finishResolutionStart;\n\n // Add file read errors to the result so MCP can report them\n if (fileReadErrors.length > 0) {\n errors.push(...fileReadErrors.map(e => ({ message: `File read error: ${e.path} - ${e.error}` })));\n }\n\n timings.total_ms = Date.now() - totalStart;\n return {\n terminationReason: 'completed',\n messages,\n finish: { payload, metadata: finishMeta, resolved },\n timings: timings as WarpGrepExecutionMetrics,\n };\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  executeToolCall,
7
7
  formatResult
8
- } from "./chunk-FJKPMMNQ.js";
8
+ } from "./chunk-HRK53IKL.js";
9
9
  import {
10
10
  getSystemPrompt
11
11
  } from "./chunk-FMLHRJDF.js";
@@ -50,4 +50,4 @@ export {
50
50
  execute,
51
51
  createWarpGrepTool
52
52
  };
53
- //# sourceMappingURL=chunk-ZLJAODDJ.js.map
53
+ //# sourceMappingURL=chunk-RL4JBZ3T.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-KW7OEGZK.js";
4
4
  import {
5
5
  executeToolCall
6
- } from "./chunk-FJKPMMNQ.js";
6
+ } from "./chunk-HRK53IKL.js";
7
7
 
8
8
  // tools/warp_grep/vercel.ts
9
9
  import { tool } from "ai";
@@ -38,4 +38,4 @@ export {
38
38
  createWarpGrepTool,
39
39
  vercel_default
40
40
  };
41
- //# sourceMappingURL=chunk-3ONNAQZU.js.map
41
+ //# sourceMappingURL=chunk-S27A4NQM.js.map
package/dist/client.cjs CHANGED
@@ -1882,10 +1882,15 @@ async function callModel(messages, model, options = {}) {
1882
1882
  return content;
1883
1883
  }
1884
1884
  async function runWarpGrep(config) {
1885
+ const totalStart = Date.now();
1886
+ const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
1887
+ const timings = { turns: [], timeout_ms: timeoutMs };
1885
1888
  const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
1886
1889
  const messages = [];
1887
1890
  messages.push({ role: "system", content: getSystemPrompt() });
1891
+ const initialStateStart = Date.now();
1888
1892
  const initialState = await buildInitialState(repoRoot, config.query, config.provider);
1893
+ timings.initial_state_ms = Date.now() - initialStateStart;
1889
1894
  messages.push({ role: "user", content: initialState });
1890
1895
  const maxTurns = AGENT_CONFIG.MAX_TURNS;
1891
1896
  const model = config.model || DEFAULT_MODEL;
@@ -1894,22 +1899,29 @@ async function runWarpGrep(config) {
1894
1899
  let finishMeta;
1895
1900
  let terminationReason = "terminated";
1896
1901
  for (let turn = 1; turn <= maxTurns; turn += 1) {
1902
+ const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
1897
1903
  enforceContextLimit(messages);
1904
+ const modelCallStart = Date.now();
1898
1905
  const assistantContent = await callModel(messages, model, {
1899
1906
  morphApiKey: config.morphApiKey,
1900
1907
  morphApiUrl: config.morphApiUrl,
1901
1908
  retryConfig: config.retryConfig,
1902
- timeout: config.timeout
1909
+ timeout: timeoutMs
1903
1910
  }).catch((e) => {
1904
1911
  errors.push({ message: e instanceof Error ? e.message : String(e) });
1905
1912
  return "";
1906
1913
  });
1907
- if (!assistantContent) break;
1914
+ turnMetrics.morph_api_ms = Date.now() - modelCallStart;
1915
+ if (!assistantContent) {
1916
+ timings.turns.push(turnMetrics);
1917
+ break;
1918
+ }
1908
1919
  messages.push({ role: "assistant", content: assistantContent });
1909
1920
  const toolCalls = parser.parse(assistantContent);
1910
1921
  if (toolCalls.length === 0) {
1911
1922
  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" });
1912
1923
  terminationReason = "terminated";
1924
+ timings.turns.push(turnMetrics);
1913
1925
  break;
1914
1926
  }
1915
1927
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
@@ -1950,7 +1962,9 @@ async function runWarpGrep(config) {
1950
1962
  )
1951
1963
  );
1952
1964
  }
1965
+ const toolExecStart = Date.now();
1953
1966
  const allResults = await Promise.all(allPromises);
1967
+ turnMetrics.local_tools_ms = Date.now() - toolExecStart;
1954
1968
  for (const result of allResults) {
1955
1969
  formatted.push(result);
1956
1970
  }
@@ -1959,6 +1973,7 @@ async function runWarpGrep(config) {
1959
1973
  const contextBudget = calculateContextBudget(messages);
1960
1974
  messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
1961
1975
  }
1976
+ timings.turns.push(turnMetrics);
1962
1977
  if (finishCalls.length) {
1963
1978
  const fc = finishCalls[0];
1964
1979
  const files = fc.arguments?.files ?? [];
@@ -1968,7 +1983,8 @@ async function runWarpGrep(config) {
1968
1983
  }
1969
1984
  }
1970
1985
  if (terminationReason !== "completed" || !finishMeta) {
1971
- return { terminationReason, messages, errors };
1986
+ timings.total_ms = Date.now() - totalStart;
1987
+ return { terminationReason, messages, errors, timings };
1972
1988
  }
1973
1989
  const parts = ["Relevant context found:"];
1974
1990
  for (const f of finishMeta.files) {
@@ -1976,6 +1992,7 @@ async function runWarpGrep(config) {
1976
1992
  parts.push(`- ${f.path}: ${ranges}`);
1977
1993
  }
1978
1994
  const payload = parts.join("\n");
1995
+ const finishResolutionStart = Date.now();
1979
1996
  const fileReadErrors = [];
1980
1997
  const resolved = await readFinishFiles(
1981
1998
  repoRoot,
@@ -1995,13 +2012,16 @@ async function runWarpGrep(config) {
1995
2012
  }
1996
2013
  }
1997
2014
  );
2015
+ timings.finish_resolution_ms = Date.now() - finishResolutionStart;
1998
2016
  if (fileReadErrors.length > 0) {
1999
2017
  errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
2000
2018
  }
2019
+ timings.total_ms = Date.now() - totalStart;
2001
2020
  return {
2002
2021
  terminationReason: "completed",
2003
2022
  messages,
2004
- finish: { payload, metadata: finishMeta, resolved }
2023
+ finish: { payload, metadata: finishMeta, resolved },
2024
+ timings
2005
2025
  };
2006
2026
  }
2007
2027