Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions bun.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/opencode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@hono/standard-validator": "0.1.5",
"@hono/zod-validator": "catalog:",
"@modelcontextprotocol/sdk": "1.15.1",
"@morphllm/morphsdk": "^0.2.71",
"@octokit/graphql": "9.0.2",
"@octokit/rest": "catalog:",
"@openauthjs/openauth": "catalog:",
Expand Down
4 changes: 3 additions & 1 deletion packages/opencode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { mergeDeep } from "remeda"
import PROMPT_GENERATE from "./generate.txt"
import PROMPT_COMPACTION from "./prompt/compaction.txt"
import PROMPT_EXPLORE from "./prompt/explore.txt"
import PROMPT_EXPLORE_WARPGREP from "./prompt/explore-warpgrep.txt"
import PROMPT_SUMMARY from "./prompt/summary.txt"
import PROMPT_TITLE from "./prompt/title.txt"
import { Env } from "../env"

export namespace Agent {
export const Info = z
Expand Down Expand Up @@ -149,7 +151,7 @@ export namespace Agent {
...defaultTools,
},
description: `Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.`,
prompt: PROMPT_EXPLORE,
prompt: Env.get("MORPH_API_KEY") ? PROMPT_EXPLORE_WARPGREP : PROMPT_EXPLORE,
options: {},
permission: agentPermission,
mode: "subagent",
Expand Down
20 changes: 20 additions & 0 deletions packages/opencode/src/agent/prompt/explore-warpgrep.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
You are a file search specialist. You excel at thoroughly navigating and exploring codebases.

Your strengths:
- Rapidly finding files using glob patterns
- Searching code and text with powerful regex patterns
- Reading and analyzing file contents

Guidelines:
- Use WarpGrep for broad searching at the beginning of a phase of exploration. It is used as a faster way to find relevant files/lines. Best practices is to start your search using WarpGrep.
- Use Grep for searching file contents with regex
- Use Read when you know the specific file path you need to read
- Use Bash for file operations like copying, moving, or listing directory contents
- Adapt your search approach based on the thoroughness level specified by the caller
- Return file paths as absolute paths in your final response
- For clear communication, avoid using emojis
- Do not create any files, or run bash commands that modify the user's system state in any way


Complete the user's search request efficiently and report your findings clearly.

2 changes: 1 addition & 1 deletion packages/opencode/src/agent/prompt/explore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ Guidelines:
- For clear communication, avoid using emojis
- Do not create any files, or run bash commands that modify the user's system state in any way

Complete the user's search request efficiently and report your findings clearly.
Complete the user's search request efficiently and report your findings clearly.
7 changes: 7 additions & 0 deletions packages/opencode/src/tool/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import z from "zod"
import { Plugin } from "../plugin"
import { WebSearchTool } from "./websearch"
import { CodeSearchTool } from "./codesearch"
import { WarpGrepTool } from "./warpgrep"
import { Flag } from "@/flag/flag"
import { Log } from "@/util/log"
import { Env } from "../env"

export namespace ToolRegistry {
const log = Log.create({ service: "tool.registry" })
Expand Down Expand Up @@ -102,6 +104,7 @@ export namespace ToolRegistry {
TodoReadTool,
WebSearchTool,
CodeSearchTool,
WarpGrepTool,
...(config.experimental?.batch_tool === true ? [BatchTool] : []),
...custom,
]
Expand All @@ -120,6 +123,10 @@ export namespace ToolRegistry {
if (t.id === "codesearch" || t.id === "websearch") {
return providerID === "opencode" || Flag.OPENCODE_ENABLE_EXA
}
// Enable warpgrep only when MORPH_API_KEY is set
if (t.id === "warpgrep") {
return !!Env.get("MORPH_API_KEY")
}
return true
})
.map(async (t) => {
Expand Down
58 changes: 58 additions & 0 deletions packages/opencode/src/tool/warpgrep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import z from "zod"
import { Tool } from "./tool"
import { Auth } from "../auth"
import { Env } from "../env"
import { Instance } from "../project/instance"
import { MorphClient } from "@morphllm/morphsdk"
import DESCRIPTION from "./warpgrep.txt"

export const WarpGrepTool = Tool.define("warpgrep", async () => {
return {
description: DESCRIPTION,
parameters: z.object({
query: z.string().describe("Natural language query about the codebase"),
path: z.string().optional().describe("Directory to scope the search (defaults to workspace root)"),
}),
async execute(args, ctx) {
const auth = await Auth.get("morph")
const apiKey = auth?.type === "api" ? auth.key : Env.get("MORPH_API_KEY")
if (!apiKey) {
throw new Error("Morph API key not configured. Set MORPH_API_KEY or run 'opencode auth login' and select 'Other' → 'morph'.")
}

const morph = new MorphClient({ apiKey })

const result = await morph.warpGrep.execute({
query: args.query,
repoRoot: args.path ?? Instance.directory,
})

if (!result.success) {
return {
title: args.query,
output: result.error ?? "Search failed",
metadata: { count: 0 },
}
}

if (!result.contexts || result.contexts.length === 0) {
return {
title: args.query,
output: "No relevant code found for the query.",
metadata: { count: 0 },
}
}

const output = result.contexts
.map((c) => `### ${c.file}\n\`\`\`\n${c.content}\n\`\`\``)
.join("\n\n")

return {
title: args.query,
output,
metadata: { count: result.contexts.length },
}
},
}
})

4 changes: 4 additions & 0 deletions packages/opencode/src/tool/warpgrep.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This is a subagent that takes in a search string and tries to find relevant files and lines.

- Best practice is to use it at the beginning of codebase explorations to fast track finding relevant files/lines.
- Do not use it to pin point keywords, but use it for broader semantic queries. "Find the XYZ flow", "How does XYZ work", "Where is XYZ handled?"