@morphllm/morphsdk 0.2.116 → 0.2.118

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 (72) hide show
  1. package/dist/{chunk-3JVHMOYJ.js → chunk-3Q7KXILI.js} +2 -2
  2. package/dist/{chunk-SITZC3U6.js → chunk-5IVVJMMX.js} +2 -2
  3. package/dist/{chunk-5JARN2NG.js → chunk-A2LIILDJ.js} +2 -2
  4. package/dist/{chunk-QOEZARHG.js → chunk-EAT5W3SH.js} +2 -2
  5. package/dist/{chunk-SNGGSPYJ.js → chunk-GHGJAQSJ.js} +15 -1
  6. package/dist/chunk-GHGJAQSJ.js.map +1 -0
  7. package/dist/{chunk-25APYVON.js → chunk-PR44LEQQ.js} +2 -2
  8. package/dist/{chunk-62OVBE6G.js → chunk-QFEVCGR6.js} +6 -6
  9. package/dist/{chunk-RBOCP2MX.js → chunk-QL7MV3GT.js} +25 -2
  10. package/dist/chunk-QL7MV3GT.js.map +1 -0
  11. package/dist/{chunk-GENFEPHG.js → chunk-UR76P62F.js} +2 -2
  12. package/dist/{chunk-OVNPKTEG.js → chunk-YJXAMX3V.js} +2 -2
  13. package/dist/{chunk-Q6Y4R236.js → chunk-YTYCHRQ2.js} +7 -9
  14. package/dist/{chunk-Q6Y4R236.js.map → chunk-YTYCHRQ2.js.map} +1 -1
  15. package/dist/{chunk-4IOC2D5Y.js → chunk-ZYPLV3HP.js} +2 -2
  16. package/dist/client.cjs +43 -8
  17. package/dist/client.cjs.map +1 -1
  18. package/dist/client.js +9 -9
  19. package/dist/index.cjs +43 -8
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.js +9 -9
  22. package/dist/tools/browser/anthropic.js +3 -3
  23. package/dist/tools/browser/core.cjs +6 -8
  24. package/dist/tools/browser/core.cjs.map +1 -1
  25. package/dist/tools/browser/core.js +2 -2
  26. package/dist/tools/browser/index.cjs +6 -8
  27. package/dist/tools/browser/index.cjs.map +1 -1
  28. package/dist/tools/browser/index.js +5 -5
  29. package/dist/tools/browser/live.cjs +6 -8
  30. package/dist/tools/browser/live.cjs.map +1 -1
  31. package/dist/tools/browser/live.js +1 -1
  32. package/dist/tools/browser/openai.js +3 -3
  33. package/dist/tools/browser/vercel.js +3 -3
  34. package/dist/tools/warp_grep/agent/parser.cjs +14 -0
  35. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  36. package/dist/tools/warp_grep/agent/parser.js +1 -1
  37. package/dist/tools/warp_grep/agent/runner.cjs +37 -0
  38. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  39. package/dist/tools/warp_grep/agent/runner.js +2 -2
  40. package/dist/tools/warp_grep/anthropic.cjs +26 -0
  41. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  42. package/dist/tools/warp_grep/anthropic.js +4 -4
  43. package/dist/tools/warp_grep/client.cjs +37 -0
  44. package/dist/tools/warp_grep/client.cjs.map +1 -1
  45. package/dist/tools/warp_grep/client.js +3 -3
  46. package/dist/tools/warp_grep/gemini.cjs +26 -0
  47. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  48. package/dist/tools/warp_grep/gemini.js +3 -3
  49. package/dist/tools/warp_grep/harness.cjs +14 -0
  50. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  51. package/dist/tools/warp_grep/harness.js +1 -1
  52. package/dist/tools/warp_grep/index.cjs +37 -0
  53. package/dist/tools/warp_grep/index.cjs.map +1 -1
  54. package/dist/tools/warp_grep/index.js +3 -3
  55. package/dist/tools/warp_grep/openai.cjs +26 -0
  56. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  57. package/dist/tools/warp_grep/openai.js +4 -4
  58. package/dist/tools/warp_grep/vercel.cjs +37 -0
  59. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  60. package/dist/tools/warp_grep/vercel.js +4 -4
  61. package/package.json +1 -1
  62. package/dist/chunk-RBOCP2MX.js.map +0 -1
  63. package/dist/chunk-SNGGSPYJ.js.map +0 -1
  64. /package/dist/{chunk-3JVHMOYJ.js.map → chunk-3Q7KXILI.js.map} +0 -0
  65. /package/dist/{chunk-SITZC3U6.js.map → chunk-5IVVJMMX.js.map} +0 -0
  66. /package/dist/{chunk-5JARN2NG.js.map → chunk-A2LIILDJ.js.map} +0 -0
  67. /package/dist/{chunk-QOEZARHG.js.map → chunk-EAT5W3SH.js.map} +0 -0
  68. /package/dist/{chunk-25APYVON.js.map → chunk-PR44LEQQ.js.map} +0 -0
  69. /package/dist/{chunk-62OVBE6G.js.map → chunk-QFEVCGR6.js.map} +0 -0
  70. /package/dist/{chunk-GENFEPHG.js.map → chunk-UR76P62F.js.map} +0 -0
  71. /package/dist/{chunk-OVNPKTEG.js.map → chunk-YJXAMX3V.js.map} +0 -0
  72. /package/dist/{chunk-4IOC2D5Y.js.map → chunk-ZYPLV3HP.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  executeToolCall,
6
6
  executeToolCallStreaming
7
- } from "./chunk-OVNPKTEG.js";
7
+ } from "./chunk-YJXAMX3V.js";
8
8
 
9
9
  // tools/warp_grep/vercel.ts
10
10
  import { tool } from "ai";
@@ -63,4 +63,4 @@ export {
63
63
  createWarpGrepTool,
64
64
  vercel_default
65
65
  };
66
- //# sourceMappingURL=chunk-3JVHMOYJ.js.map
66
+ //# sourceMappingURL=chunk-3Q7KXILI.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-2HMEZZKK.js";
5
5
  import {
6
6
  executeBrowserTask
7
- } from "./chunk-4IOC2D5Y.js";
7
+ } from "./chunk-ZYPLV3HP.js";
8
8
  import {
9
9
  __export
10
10
  } from "./chunk-PZ5AY32C.js";
@@ -93,4 +93,4 @@ export {
93
93
  createBrowserTool,
94
94
  openai_exports
95
95
  };
96
- //# sourceMappingURL=chunk-SITZC3U6.js.map
96
+ //# sourceMappingURL=chunk-5IVVJMMX.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  executeToolCall,
7
7
  formatResult
8
- } from "./chunk-OVNPKTEG.js";
8
+ } from "./chunk-YJXAMX3V.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-5JARN2NG.js.map
53
+ //# sourceMappingURL=chunk-A2LIILDJ.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-2HMEZZKK.js";
5
5
  import {
6
6
  executeBrowserTask
7
- } from "./chunk-4IOC2D5Y.js";
7
+ } from "./chunk-ZYPLV3HP.js";
8
8
  import {
9
9
  __export
10
10
  } from "./chunk-PZ5AY32C.js";
@@ -77,4 +77,4 @@ export {
77
77
  createBrowserTool,
78
78
  anthropic_exports
79
79
  };
80
- //# sourceMappingURL=chunk-QOEZARHG.js.map
80
+ //# sourceMappingURL=chunk-EAT5W3SH.js.map
@@ -92,9 +92,23 @@ function parseNestedXmlTools(text) {
92
92
  }
93
93
  if (files.length > 0) {
94
94
  tools.push({ name: "finish", arguments: { files } });
95
+ } else {
96
+ const raw = content.replace(/<[^>]*>/g, "").trim();
97
+ const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
98
+ tools.push({ name: "finish", arguments: { files: [], textResult } });
95
99
  }
96
100
  }
97
101
  }
102
+ if (tools.length === 0) {
103
+ const fnFinishMatch = text.match(/<function=finish>([\s\S]*?)<\/function>/i);
104
+ if (fnFinishMatch) {
105
+ const inner = fnFinishMatch[1];
106
+ const paramMatch = inner.match(/<parameter=result>([\s\S]*?)<\/parameter>/i);
107
+ const raw = (paramMatch ? paramMatch[1] : inner).trim();
108
+ const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
109
+ tools.push({ name: "finish", arguments: { files: [], textResult } });
110
+ }
111
+ }
98
112
  return tools;
99
113
  }
100
114
  function preprocessText(text) {
@@ -265,4 +279,4 @@ var LLMResponseParser = class {
265
279
  export {
266
280
  LLMResponseParser
267
281
  };
268
- //# sourceMappingURL=chunk-SNGGSPYJ.js.map
282
+ //# sourceMappingURL=chunk-GHGJAQSJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/agent/parser.ts"],"sourcesContent":["// Parses assistant lines into structured tool calls\nimport type { ToolCall } from './types.js';\n\nconst VALID_COMMANDS = ['list_directory', 'grep', 'read', 'finish'] as const;\ntype ValidCommand = typeof VALID_COMMANDS[number];\n\nfunction isValidCommand(name: string): name is ValidCommand {\n return VALID_COMMANDS.includes(name as ValidCommand);\n}\n\nfunction getXmlElementText(xml: string, tagName: string): string | null {\n const regex = new RegExp(`<${tagName}>([\\\\s\\\\S]*?)</${tagName}>`, 'i');\n const match = xml.match(regex);\n return match ? match[1].trim() : null;\n}\n\nfunction parseNestedXmlTools(text: string): ToolCall[] {\n const tools: ToolCall[] = [];\n \n // Match any XML tool tags. Unknown tools are silently ignored for forward-compatibility:\n // if we add new tools (e.g. <search>) to the model, old clients won't break.\n const toolRegex = /<([a-z_][a-z0-9_]*)>([\\s\\S]*?)<\\/\\1>/gi;\n let match;\n \n while ((match = toolRegex.exec(text)) !== null) {\n const rawToolName = match[1].toLowerCase();\n const content = match[2];\n \n // Skip unknown tools silently - enables forward compatibility\n if (!isValidCommand(rawToolName)) continue;\n \n const toolName = rawToolName;\n \n if (toolName === 'list_directory') {\n const path = getXmlElementText(content, 'path');\n const pattern = getXmlElementText(content, 'pattern');\n if (path) {\n tools.push({ name: 'list_directory', arguments: { path, pattern } });\n }\n } else if (toolName === 'grep') {\n const pattern = getXmlElementText(content, 'pattern');\n const subDir = getXmlElementText(content, 'sub_dir');\n const glob = getXmlElementText(content, 'glob');\n if (pattern) {\n tools.push({ \n name: 'grep', \n arguments: { \n pattern, \n path: subDir || '.', \n ...(glob && { glob }) \n } \n });\n }\n } else if (toolName === 'read') {\n const path = getXmlElementText(content, 'path');\n const linesStr = getXmlElementText(content, 'lines');\n if (path) {\n const args: Record<string, unknown> = { path };\n if (linesStr) {\n const ranges: Array<[number, number]> = [];\n for (const rangeStr of linesStr.split(',')) {\n const trimmed = rangeStr.trim();\n if (!trimmed) continue;\n const [s, e] = trimmed.split('-').map(v => parseInt(v.trim(), 10));\n if (Number.isFinite(s) && Number.isFinite(e)) {\n ranges.push([s, e]);\n } else if (Number.isFinite(s)) {\n // Single line like \"100\"\n ranges.push([s, s]);\n }\n }\n if (ranges.length === 1) {\n args.start = ranges[0][0];\n args.end = ranges[0][1];\n } else if (ranges.length > 1) {\n args.lines = ranges;\n }\n }\n tools.push({ name: 'read', arguments: args });\n }\n } else if (toolName === 'finish') {\n // Parse nested <file> elements\n const fileRegex = /<file>([\\s\\S]*?)<\\/file>/gi;\n const files: Array<{ path: string; lines: '*' | Array<[number, number]> }> = [];\n let fileMatch;\n \n while ((fileMatch = fileRegex.exec(content)) !== null) {\n const fileContent = fileMatch[1];\n const filePath = getXmlElementText(fileContent, 'path');\n const linesStr = getXmlElementText(fileContent, 'lines');\n \n if (filePath) {\n if (!linesStr || linesStr.trim() === '*') {\n // No lines specified or explicit '*' - read entire file\n files.push({ path: filePath, lines: '*' });\n } else {\n const ranges: Array<[number, number]> = [];\n for (const rangeStr of linesStr.split(',')) {\n const [s, e] = rangeStr.split('-').map(v => parseInt(v.trim(), 10));\n if (Number.isFinite(s) && Number.isFinite(e)) {\n ranges.push([s, e]);\n }\n }\n if (ranges.length > 0) {\n files.push({ path: filePath, lines: ranges });\n } else {\n // Invalid ranges provided, fall back to entire file\n files.push({ path: filePath, lines: '*' });\n }\n }\n }\n }\n \n if (files.length > 0) {\n tools.push({ name: 'finish', arguments: { files } });\n } else {\n // No valid <file> elements — treat as text-only finish\n const raw = content.replace(/<[^>]*>/g, '').trim();\n const textResult = (!raw || raw === '*') ? 'No relevant code found.' : raw;\n tools.push({ name: 'finish', arguments: { files: [], textResult } });\n }\n }\n }\n\n // Detect non-standard finish format: <function=finish><parameter=result>...</parameter></function>\n // Some models emit this instead of <finish>...</finish>. Rather than hard-erroring,\n // extract the text and treat it as a text-only finish (no files, just the model's response).\n if (tools.length === 0) {\n const fnFinishMatch = text.match(/<function=finish>([\\s\\S]*?)<\\/function>/i);\n if (fnFinishMatch) {\n const inner = fnFinishMatch[1];\n // Try to extract <parameter=result>...</parameter> content first\n const paramMatch = inner.match(/<parameter=result>([\\s\\S]*?)<\\/parameter>/i);\n const raw = (paramMatch ? paramMatch[1] : inner).trim();\n const textResult = (!raw || raw === '*') ? 'No relevant code found.' : raw;\n tools.push({ name: 'finish', arguments: { files: [], textResult } });\n }\n }\n\n return tools;\n}\n\nfunction preprocessText(text: string): { lines: string[]; nestedTools: ToolCall[] } {\n // Strip <think> blocks (reasoning) and <tool_call> wrappers (model hallucination).\n // NOTE: Only strip exact <tool_call> tags - NOT <tool> or <tool_xyz> which could be valid future tools.\n const processed = text\n .replace(/<think>[\\s\\S]*?<\\/think>/gi, '')\n .replace(/<\\/?tool_call>/gi, '');\n const nestedTools = parseNestedXmlTools(processed);\n \n // Extract raw line-based tool calls (legacy format: `grep 'pattern' path`)\n const toolCallLines: string[] = [];\n const allLines = processed.split(/\\r?\\n/).map(l => l.trim());\n for (const line of allLines) {\n if (!line) continue;\n if (line.startsWith('<')) continue;\n \n const firstWord = line.split(/\\s/)[0];\n if (VALID_COMMANDS.includes(firstWord as ValidCommand)) {\n if (!toolCallLines.includes(line)) {\n toolCallLines.push(line);\n }\n }\n }\n \n return { lines: toolCallLines, nestedTools };\n}\n\nexport class LLMResponseParser {\n private readonly finishSpecSplitRe = /,(?=[^,\\s]+:)/;\n\n parse(text: string): ToolCall[] {\n if (typeof text !== 'string') {\n throw new TypeError('Command text must be a string.');\n }\n \n // Preprocess to handle XML tags\n const { lines, nestedTools } = preprocessText(text);\n \n // Start with nested XML tools (new format)\n const commands: ToolCall[] = [...nestedTools];\n let finishAccumulator: Map<string, number[][]> | null = null;\n\n lines.forEach((line) => {\n if (!line || line.startsWith('#')) return;\n const parts = this.splitLine(line);\n if (parts.length === 0) return;\n const cmd = parts[0];\n \n switch (cmd) {\n case 'list_directory':\n this.handleListDirectory(parts, line, commands);\n break;\n case 'grep':\n this.handleGrep(parts, line, commands);\n break;\n case 'read':\n this.handleRead(parts, line, commands);\n break;\n case 'finish':\n finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);\n break;\n default:\n // Silently ignore unknown commands\n break;\n }\n });\n\n if (finishAccumulator) {\n const map = finishAccumulator as Map<string, number[][]>;\n const entries = [...map.entries()];\n const filesPayload = entries.map(([path, ranges]) => ({\n path,\n lines: [...ranges].sort((a, b) => a[0] - b[0]) as Array<[number, number]>,\n }));\n commands.push({ name: 'finish', arguments: { files: filesPayload } });\n }\n return commands;\n }\n\n private splitLine(line: string): string[] {\n // Split by whitespace but keep quoted blocks as one\n const parts: string[] = [];\n let current = '';\n let inSingle = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === \"'\" && line[i - 1] !== '\\\\') {\n inSingle = !inSingle;\n current += ch;\n } else if (!inSingle && /\\s/.test(ch)) {\n if (current) {\n parts.push(current);\n current = '';\n }\n } else {\n current += ch;\n }\n }\n if (current) parts.push(current);\n return parts;\n }\n\n /** Helper to create a _skip tool call with an error message */\n private skip(message: string): ToolCall {\n return { name: '_skip', arguments: { message } };\n }\n\n private handleListDirectory(parts: string[], rawLine: string, commands: ToolCall[]) {\n // list_directory <path> [pattern]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: list_directory <path> [pattern]. Example: list_directory src/`\n ));\n return;\n }\n const path = parts[1];\n const pattern = parts[2]?.replace(/^\"|\"$/g, '') ?? null;\n commands.push({ name: 'list_directory', arguments: { path, pattern } });\n }\n\n private handleGrep(parts: string[], rawLine: string, commands: ToolCall[]) {\n // grep '<pattern>' <path>\n if (parts.length < 3) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing arguments. ` +\n `Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`\n ));\n return;\n }\n let pat = parts[1];\n // Be lenient: accept unquoted patterns by treating the first arg as the pattern\n if (pat.startsWith(\"'\") && pat.endsWith(\"'\")) {\n pat = pat.slice(1, -1);\n }\n // If pattern is empty after processing, skip\n if (!pat) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" has an empty pattern. ` +\n `Provide a non-empty search pattern. Example: grep 'function' src/`\n ));\n return;\n }\n commands.push({ name: 'grep', arguments: { pattern: pat, path: parts[2] } });\n }\n\n private handleRead(parts: string[], rawLine: string, commands: ToolCall[]) {\n // read <path>[:start-end]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`\n ));\n return;\n }\n const spec = parts[1];\n const rangeIdx = spec.indexOf(':');\n if (rangeIdx === -1) {\n commands.push({ name: 'read', arguments: { path: spec } });\n return;\n }\n const filePath = spec.slice(0, rangeIdx);\n const range = spec.slice(rangeIdx + 1);\n const [s, e] = range.split('-').map(v => parseInt(v, 10));\n // If range is invalid, fallback to reading the whole file\n if (!Number.isFinite(s) || !Number.isFinite(e)) {\n commands.push({ name: 'read', arguments: { path: filePath } });\n return;\n }\n commands.push({ name: 'read', arguments: { path: filePath, start: s, end: e } });\n }\n\n private handleFinish(parts: string[], rawLine: string, commands: ToolCall[], acc: Map<string, number[][]> | null) {\n // finish file1:1-10,20-30 file2:5-7\n const map = acc ?? new Map<string, number[][]>();\n const args = parts.slice(1);\n for (const token of args) {\n const [filePath, rangesText] = token.split(':', 2);\n if (!filePath || !rangesText) {\n // Skip this malformed token, continue processing others\n commands.push(this.skip(\n `[SKIPPED] Invalid finish token \"${token}\". ` +\n `Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`\n ));\n continue;\n }\n const rangeSpecs = rangesText.split(',').filter(Boolean);\n for (const spec of rangeSpecs) {\n const [s, e] = spec.split('-').map(v => parseInt(v, 10));\n if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {\n // Skip this invalid range, continue with others\n commands.push(this.skip(\n `[SKIPPED] Invalid range \"${spec}\" in \"${token}\". ` +\n `Ranges must be <start>-<end> where start <= end. Example: 1-50`\n ));\n continue;\n }\n const arr = map.get(filePath) ?? [];\n arr.push([s, e]);\n map.set(filePath, arr);\n }\n }\n return map;\n }\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2HMEZZKK.js";
4
4
  import {
5
5
  executeBrowserTask
6
- } from "./chunk-4IOC2D5Y.js";
6
+ } from "./chunk-ZYPLV3HP.js";
7
7
  import {
8
8
  __export
9
9
  } from "./chunk-PZ5AY32C.js";
@@ -54,4 +54,4 @@ export {
54
54
  browserTool,
55
55
  vercel_exports
56
56
  };
57
- //# sourceMappingURL=chunk-25APYVON.js.map
57
+ //# sourceMappingURL=chunk-PR44LEQQ.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createWarpGrepTool
3
- } from "./chunk-GENFEPHG.js";
3
+ } from "./chunk-UR76P62F.js";
4
4
  import {
5
5
  createWarpGrepTool as createWarpGrepTool3
6
- } from "./chunk-3JVHMOYJ.js";
6
+ } from "./chunk-3Q7KXILI.js";
7
7
  import {
8
8
  createWarpGrepTool as createWarpGrepTool2
9
- } from "./chunk-5JARN2NG.js";
9
+ } from "./chunk-A2LIILDJ.js";
10
10
  import {
11
11
  WarpGrepClient
12
- } from "./chunk-OVNPKTEG.js";
12
+ } from "./chunk-YJXAMX3V.js";
13
13
  import {
14
14
  createCodebaseSearchTool as createCodebaseSearchTool3
15
15
  } from "./chunk-O5DA5V5S.js";
@@ -36,7 +36,7 @@ import {
36
36
  } from "./chunk-M5DR2WOZ.js";
37
37
  import {
38
38
  BrowserClient
39
- } from "./chunk-4IOC2D5Y.js";
39
+ } from "./chunk-ZYPLV3HP.js";
40
40
  import {
41
41
  MorphGit
42
42
  } from "./chunk-LE66XCOI.js";
@@ -643,4 +643,4 @@ export {
643
643
  VercelToolFactory,
644
644
  MorphClient
645
645
  };
646
- //# sourceMappingURL=chunk-62OVBE6G.js.map
646
+ //# sourceMappingURL=chunk-QFEVCGR6.js.map
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-3MLWXJTJ.js";
11
11
  import {
12
12
  LLMResponseParser
13
- } from "./chunk-SNGGSPYJ.js";
13
+ } from "./chunk-GHGJAQSJ.js";
14
14
  import {
15
15
  getSystemPrompt
16
16
  } from "./chunk-FMLHRJDF.js";
@@ -173,8 +173,20 @@ async function runWarpGrep(config) {
173
173
  if (finishCalls.length) {
174
174
  const fc = finishCalls[0];
175
175
  const files = fc.arguments?.files ?? [];
176
+ const textResult = fc.arguments?.textResult;
176
177
  finishMeta = { files };
177
178
  terminationReason = "completed";
179
+ if (files.length === 0) {
180
+ const payload2 = textResult || "No relevant code found.";
181
+ timings.turns.push(turnMetrics);
182
+ timings.total_ms = Date.now() - totalStart;
183
+ return {
184
+ terminationReason: "completed",
185
+ messages,
186
+ finish: { payload: payload2, metadata: finishMeta },
187
+ timings
188
+ };
189
+ }
178
190
  break;
179
191
  }
180
192
  }
@@ -327,8 +339,19 @@ async function* runWarpGrepStreaming(config) {
327
339
  if (finishCalls.length) {
328
340
  const fc = finishCalls[0];
329
341
  const files = fc.arguments?.files ?? [];
342
+ const textResult = fc.arguments?.textResult;
330
343
  finishMeta = { files };
331
344
  terminationReason = "completed";
345
+ if (files.length === 0) {
346
+ const payload2 = textResult || "No relevant code found.";
347
+ timings.total_ms = Date.now() - totalStart;
348
+ return {
349
+ terminationReason: "completed",
350
+ messages,
351
+ finish: { payload: payload2, metadata: finishMeta },
352
+ timings
353
+ };
354
+ }
332
355
  break;
333
356
  }
334
357
  }
@@ -379,4 +402,4 @@ export {
379
402
  runWarpGrep,
380
403
  runWarpGrepStreaming
381
404
  };
382
- //# sourceMappingURL=chunk-RBOCP2MX.js.map
405
+ //# sourceMappingURL=chunk-QL7MV3GT.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, WarpGrepStep } 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 type { RetryConfig } from '../../utils/resilience.js';\nimport { formatAgentToolOutput } from './formatter.js';\nimport { formatTurnMessage, calculateContextBudget, buildInitialState, enforceContextLimit } from './helpers.js';\nimport OpenAI from 'openai';\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 const timeoutMs = options.timeout ?? AGENT_CONFIG.TIMEOUT_MS;\n\n const client = new OpenAI({\n apiKey,\n baseURL: `${baseUrl}/v1`,\n maxRetries: options.retryConfig?.maxRetries,\n timeout: timeoutMs,\n });\n\n const MAX_EMPTY_RETRIES = 1;\n\n for (let attempt = 0; attempt <= MAX_EMPTY_RETRIES; attempt++) {\n let data;\n try {\n data = await client.chat.completions.create({\n model,\n temperature: 0.0,\n max_tokens: 1024,\n messages,\n });\n } catch (error) {\n if (error instanceof OpenAI.APIError && error.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 throw error;\n }\n\n const choice = data?.choices?.[0];\n const content = choice?.message?.content;\n\n if (content && typeof content === 'string') {\n return content;\n }\n\n // Last attempt — throw with diagnostics\n if (attempt === MAX_EMPTY_RETRIES) {\n const finishReason = choice?.finish_reason ?? 'unknown';\n const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;\n const choicesLen = data?.choices?.length ?? 0;\n const contentType = content === null ? 'null' : content === undefined ? 'undefined' : typeof content;\n\n throw new Error(\n `Invalid response from model: content=${contentType}, finish_reason=${finishReason}, ` +\n `has_tool_calls=${hasToolCalls}, choices_length=${choicesLen}`\n );\n }\n\n // Retry — brief pause before next attempt\n await new Promise(resolve => setTimeout(resolve, 200));\n }\n\n // Unreachable, but satisfies TypeScript\n throw new Error('Invalid response from model');\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 const errMsg = e instanceof Error ? e.message : String(e);\n console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);\n errors.push({ message: errMsg });\n return '';\n });\n turnMetrics.morph_api_ms = Date.now() - modelCallStart;\n\n if (!assistantContent) {\n console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);\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 console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));\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 const textResult = (fc.arguments as any)?.textResult as string | undefined;\n finishMeta = { files };\n terminationReason = 'completed';\n\n // Text-only finish: model returned a text response instead of file references\n // (e.g. \"No relevant code found\"). Surface the text to the parent LLM.\n if (files.length === 0) {\n const payload = textResult || 'No relevant code found.';\n timings.turns!.push(turnMetrics);\n timings.total_ms = Date.now() - totalStart;\n return {\n terminationReason: 'completed',\n messages,\n finish: { payload, metadata: finishMeta },\n timings: timings as WarpGrepExecutionMetrics,\n };\n }\n\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\n/**\n * Streaming version of runWarpGrep that yields step information after each turn.\n * Yields WarpGrepStep with tool calls for each turn, then returns the final AgentRunResult.\n */\nexport async function* runWarpGrepStreaming(\n config: SessionConfig & { provider: WarpGrepProvider }\n): AsyncGenerator<WarpGrepStep, AgentRunResult, undefined> {\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 const errMsg = e instanceof Error ? e.message : String(e);\n console.error(`[warp_grep:stream] Morph API call failed on turn ${turn}:`, errMsg);\n errors.push({ message: errMsg });\n return '';\n });\n turnMetrics.morph_api_ms = Date.now() - modelCallStart;\n\n if (!assistantContent) {\n console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);\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 console.error(`[warp_grep:stream] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));\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 // Yield step with tool calls (before execution)\n yield {\n turn,\n toolCalls: toolCalls.map(c => ({\n name: c.name,\n arguments: c.arguments ?? {}\n }))\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 const textResult = (fc.arguments as any)?.textResult as string | undefined;\n finishMeta = { files };\n terminationReason = 'completed';\n\n // Text-only finish: model returned a text response instead of file references\n if (files.length === 0) {\n const payload = textResult || 'No relevant code found.';\n timings.total_ms = Date.now() - totalStart;\n return {\n terminationReason: 'completed',\n messages,\n finish: { payload, metadata: finishMeta },\n timings: timings as WarpGrepExecutionMetrics,\n };\n }\n\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 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 return rr.lines.map(l => {\n const idx = l.indexOf('|');\n return idx >= 0 ? l.slice(idx + 1) : l;\n });\n } catch (err) {\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 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":["payload"]}
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  executeToolCall,
7
7
  formatResult
8
- } from "./chunk-OVNPKTEG.js";
8
+ } from "./chunk-YJXAMX3V.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-GENFEPHG.js.map
61
+ //# sourceMappingURL=chunk-UR76P62F.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  runWarpGrep,
3
3
  runWarpGrepStreaming
4
- } from "./chunk-RBOCP2MX.js";
4
+ } from "./chunk-QL7MV3GT.js";
5
5
  import {
6
6
  RemoteCommandsProvider
7
7
  } from "./chunk-PUGSTXLO.js";
@@ -148,4 +148,4 @@ export {
148
148
  executeToolCallStreaming,
149
149
  formatResult
150
150
  };
151
- //# sourceMappingURL=chunk-OVNPKTEG.js.map
151
+ //# sourceMappingURL=chunk-YJXAMX3V.js.map
@@ -32,13 +32,14 @@ function buildLiveUrl(debugUrl, options = {}) {
32
32
  }
33
33
  return url.toString();
34
34
  }
35
+ function cdpToHttps(wsUrl) {
36
+ return wsUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://");
37
+ }
35
38
  function normalizeLiveUrl(debugUrl) {
36
39
  const trimmed = debugUrl.trim();
37
- if (!trimmed) {
38
- return trimmed;
39
- }
40
+ if (!trimmed) return trimmed;
40
41
  if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
41
- return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
42
+ return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;
42
43
  }
43
44
  let url;
44
45
  try {
@@ -46,12 +47,9 @@ function normalizeLiveUrl(debugUrl) {
46
47
  } catch {
47
48
  return trimmed;
48
49
  }
49
- if (url.protocol === "wss:" || url.protocol === "ws:") {
50
- return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
51
- }
52
50
  const wssParam = url.searchParams.get("wss");
53
51
  if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
54
- url.searchParams.set("wss", wssParam);
52
+ url.searchParams.set("wss", cdpToHttps(wssParam));
55
53
  }
56
54
  return url.toString();
57
55
  }
@@ -105,4 +103,4 @@ export {
105
103
  buildEmbedCode,
106
104
  resolvePreset
107
105
  };
108
- //# sourceMappingURL=chunk-Q6Y4R236.js.map
106
+ //# sourceMappingURL=chunk-YTYCHRQ2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../tools/browser/live.ts"],"sourcesContent":["/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n }\n\n const normalized = normalizeLiveUrl(debugUrl);\n const url = new URL(normalized);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\nfunction normalizeLiveUrl(debugUrl: string): string {\n const trimmed = debugUrl.trim();\n if (!trimmed) {\n return trimmed;\n }\n\n if (trimmed.startsWith('wss://') || trimmed.startsWith('ws://')) {\n return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;\n }\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n return trimmed;\n }\n\n if (url.protocol === 'wss:' || url.protocol === 'ws:') {\n return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;\n }\n\n const wssParam = url.searchParams.get('wss');\n if (wssParam && (wssParam.startsWith('wss://') || wssParam.startsWith('ws://'))) {\n url.searchParams.set('wss', wssParam);\n }\n\n return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n * interactive: true,\n * width: '100%',\n * height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const {\n width = '100%',\n height = '600px',\n style = '',\n className = '',\n ...sessionOptions\n } = options;\n\n const src = buildLiveUrl(debugUrl, sessionOptions);\n \n // Convert numeric dimensions to pixels\n const widthStr = typeof width === 'number' ? `${width}px` : width;\n const heightStr = typeof height === 'number' ? `${height}px` : height;\n \n // Build style attribute\n const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n \n // Build iframe attributes\n const attributes = [\n `src=\"${src}\"`,\n `style=\"${fullStyle}\"`,\n ];\n \n if (className) {\n attributes.push(`class=\"${className}\"`);\n }\n \n return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const iframe = buildLiveIframe(debugUrl, options);\n return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n if (!optionsOrPreset) {\n return {};\n }\n \n if (typeof optionsOrPreset === 'string') {\n const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n if (!preset) {\n throw new Error(\n `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n );\n }\n return preset;\n }\n \n return optionsOrPreset;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../tools/browser/live.ts"],"sourcesContent":["/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n }\n\n const normalized = normalizeLiveUrl(debugUrl);\n const url = new URL(normalized);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\n/**\n * Convert a CDP WebSocket scheme to HTTPS.\n *\n * Browser-use's live viewer expects `wss=https://UUID.cdpN.browser-use.com`\n * but CDP URLs use `wss://`. This swaps the scheme.\n */\nfunction cdpToHttps(wsUrl: string): string {\n return wsUrl.replace(/^wss:\\/\\//, 'https://').replace(/^ws:\\/\\//, 'http://');\n}\n\n/**\n * Normalize any debug URL into a valid browser-use live viewer URL.\n *\n * Handles three input formats:\n * 1. Already-correct `https://live.browser-use.com?wss=https://...` — pass through\n * 2. Already-correct but with wrong scheme `...?wss=wss://...` — fix the wss param\n * 3. Raw CDP URL `wss://UUID.cdpN.browser-use.com` — wrap into live viewer URL\n */\nfunction normalizeLiveUrl(debugUrl: string): string {\n const trimmed = debugUrl.trim();\n if (!trimmed) return trimmed;\n\n // Case 3: raw CDP WebSocket URL → wrap into live viewer\n if (trimmed.startsWith('wss://') || trimmed.startsWith('ws://')) {\n return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;\n }\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n return trimmed;\n }\n\n // Case 2: live viewer URL with wrong scheme in wss param → fix it\n const wssParam = url.searchParams.get('wss');\n if (wssParam && (wssParam.startsWith('wss://') || wssParam.startsWith('ws://'))) {\n url.searchParams.set('wss', cdpToHttps(wssParam));\n }\n\n return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n * interactive: true,\n * width: '100%',\n * height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const {\n width = '100%',\n height = '600px',\n style = '',\n className = '',\n ...sessionOptions\n } = options;\n\n const src = buildLiveUrl(debugUrl, sessionOptions);\n \n // Convert numeric dimensions to pixels\n const widthStr = typeof width === 'number' ? `${width}px` : width;\n const heightStr = typeof height === 'number' ? `${height}px` : height;\n \n // Build style attribute\n const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n \n // Build iframe attributes\n const attributes = [\n `src=\"${src}\"`,\n `style=\"${fullStyle}\"`,\n ];\n \n if (className) {\n attributes.push(`class=\"${className}\"`);\n }\n \n return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const iframe = buildLiveIframe(debugUrl, options);\n return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n if (!optionsOrPreset) {\n return {};\n }\n \n if (typeof optionsOrPreset === 'string') {\n const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n if (!preset) {\n throw new Error(\n `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n );\n }\n return preset;\n }\n \n return optionsOrPreset;\n}\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  buildLiveIframe,
7
7
  buildLiveUrl,
8
8
  resolvePreset
9
- } from "./chunk-Q6Y4R236.js";
9
+ } from "./chunk-YTYCHRQ2.js";
10
10
  import {
11
11
  fetchWithRetry,
12
12
  withTimeout
@@ -609,4 +609,4 @@ export {
609
609
  getWebp,
610
610
  checkHealth
611
611
  };
612
- //# sourceMappingURL=chunk-4IOC2D5Y.js.map
612
+ //# sourceMappingURL=chunk-ZYPLV3HP.js.map
package/dist/client.cjs CHANGED
@@ -1005,13 +1005,14 @@ function buildLiveUrl(debugUrl, options = {}) {
1005
1005
  }
1006
1006
  return url.toString();
1007
1007
  }
1008
+ function cdpToHttps(wsUrl) {
1009
+ return wsUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://");
1010
+ }
1008
1011
  function normalizeLiveUrl(debugUrl) {
1009
1012
  const trimmed = debugUrl.trim();
1010
- if (!trimmed) {
1011
- return trimmed;
1012
- }
1013
+ if (!trimmed) return trimmed;
1013
1014
  if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
1014
- return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
1015
+ return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;
1015
1016
  }
1016
1017
  let url;
1017
1018
  try {
@@ -1019,12 +1020,9 @@ function normalizeLiveUrl(debugUrl) {
1019
1020
  } catch {
1020
1021
  return trimmed;
1021
1022
  }
1022
- if (url.protocol === "wss:" || url.protocol === "ws:") {
1023
- return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
1024
- }
1025
1023
  const wssParam = url.searchParams.get("wss");
1026
1024
  if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
1027
- url.searchParams.set("wss", wssParam);
1025
+ url.searchParams.set("wss", cdpToHttps(wssParam));
1028
1026
  }
1029
1027
  return url.toString();
1030
1028
  }
@@ -2521,9 +2519,23 @@ function parseNestedXmlTools(text) {
2521
2519
  }
2522
2520
  if (files.length > 0) {
2523
2521
  tools.push({ name: "finish", arguments: { files } });
2522
+ } else {
2523
+ const raw = content.replace(/<[^>]*>/g, "").trim();
2524
+ const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
2525
+ tools.push({ name: "finish", arguments: { files: [], textResult } });
2524
2526
  }
2525
2527
  }
2526
2528
  }
2529
+ if (tools.length === 0) {
2530
+ const fnFinishMatch = text.match(/<function=finish>([\s\S]*?)<\/function>/i);
2531
+ if (fnFinishMatch) {
2532
+ const inner = fnFinishMatch[1];
2533
+ const paramMatch = inner.match(/<parameter=result>([\s\S]*?)<\/parameter>/i);
2534
+ const raw = (paramMatch ? paramMatch[1] : inner).trim();
2535
+ const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
2536
+ tools.push({ name: "finish", arguments: { files: [], textResult } });
2537
+ }
2538
+ }
2527
2539
  return tools;
2528
2540
  }
2529
2541
  function preprocessText(text) {
@@ -3150,8 +3162,20 @@ async function runWarpGrep(config) {
3150
3162
  if (finishCalls.length) {
3151
3163
  const fc = finishCalls[0];
3152
3164
  const files = fc.arguments?.files ?? [];
3165
+ const textResult = fc.arguments?.textResult;
3153
3166
  finishMeta = { files };
3154
3167
  terminationReason = "completed";
3168
+ if (files.length === 0) {
3169
+ const payload2 = textResult || "No relevant code found.";
3170
+ timings.turns.push(turnMetrics);
3171
+ timings.total_ms = Date.now() - totalStart;
3172
+ return {
3173
+ terminationReason: "completed",
3174
+ messages,
3175
+ finish: { payload: payload2, metadata: finishMeta },
3176
+ timings
3177
+ };
3178
+ }
3155
3179
  break;
3156
3180
  }
3157
3181
  }
@@ -3304,8 +3328,19 @@ async function* runWarpGrepStreaming(config) {
3304
3328
  if (finishCalls.length) {
3305
3329
  const fc = finishCalls[0];
3306
3330
  const files = fc.arguments?.files ?? [];
3331
+ const textResult = fc.arguments?.textResult;
3307
3332
  finishMeta = { files };
3308
3333
  terminationReason = "completed";
3334
+ if (files.length === 0) {
3335
+ const payload2 = textResult || "No relevant code found.";
3336
+ timings.total_ms = Date.now() - totalStart;
3337
+ return {
3338
+ terminationReason: "completed",
3339
+ messages,
3340
+ finish: { payload: payload2, metadata: finishMeta },
3341
+ timings
3342
+ };
3343
+ }
3309
3344
  break;
3310
3345
  }
3311
3346
  }