Kaynağa Gözat

first pass making system prompt less fast

Dax Raad 8 ay önce
ebeveyn
işleme
7d174767b0

+ 7 - 3
packages/opencode/src/external/fzf.ts

@@ -116,11 +116,15 @@ export namespace Fzf {
     return filepath
   }
 
-  export async function search(cwd: string, query: string) {
-    const results = await $`${await filepath()} --filter ${query}`
+  export async function search(input: {
+    cwd: string
+    query: string
+    limit?: number
+  }) {
+    const results = await $`${await filepath()} --filter=${input.query}`
       .quiet()
       .throws(false)
-      .cwd(cwd)
+      .cwd(input.cwd)
       .text()
     const split = results
       .trim()

+ 9 - 0
packages/opencode/src/external/ripgrep.ts

@@ -5,6 +5,7 @@ import fs from "fs/promises"
 import { z } from "zod"
 import { NamedError } from "../util/error"
 import { lazy } from "../util/lazy"
+import { $ } from "bun"
 
 export namespace Ripgrep {
   const PLATFORM = {
@@ -111,4 +112,12 @@ export namespace Ripgrep {
     const { filepath } = await state()
     return filepath
   }
+
+  export async function files(cwd: string) {
+    const result =
+      await $`${await filepath()} --files --hidden --glob '!.git/*'`
+        .cwd(cwd)
+        .text()
+    return result.split("\n").filter(Boolean)
+  }
 }

+ 5 - 1
packages/opencode/src/server/server.ts

@@ -457,7 +457,11 @@ export namespace Server {
         async (c) => {
           const body = c.req.valid("json")
           const app = App.info()
-          const result = await Fzf.search(app.path.cwd, body.query)
+          const result = await Fzf.search({
+            cwd: app.path.cwd,
+            query: body.query,
+            limit: 10,
+          })
           return c.json(result)
         },
       )

+ 49 - 2
packages/opencode/src/session/system.ts

@@ -1,4 +1,6 @@
 import { App } from "../app/app"
+import { Fzf } from "../external/fzf"
+import { Ripgrep } from "../external/ripgrep"
 import { ListTool } from "../tool/ls"
 import { Filesystem } from "../util/filesystem"
 
@@ -22,8 +24,53 @@ export namespace SystemPrompt {
     return result
   }
 
-  export async function environment(sessionID: string) {
+  export async function environment() {
     const app = App.info()
+
+    const tree = async () => {
+      const files = await Ripgrep.files(app.path.cwd)
+      type Node = {
+        children: Record<string, Node>
+      }
+      const root: Node = {
+        children: {},
+      }
+      for (const file of files) {
+        const parts = file.split("/")
+        let node = root
+        for (const part of parts) {
+          const existing = node.children[part]
+          if (existing) {
+            node = existing
+            continue
+          }
+          node.children[part] = {
+            children: {},
+          }
+          node = node.children[part]
+        }
+      }
+
+      function render(path: string[], node: Node): string {
+        const lines: string[] = []
+        const entries = Object.entries(node.children).sort(([a], [b]) =>
+          a.localeCompare(b),
+        )
+
+        for (const [name, child] of entries) {
+          const currentPath = [...path, name]
+          const indent = "\t".repeat(path.length)
+          const hasChildren = Object.keys(child.children).length > 0
+          lines.push(`${indent}${name}` + (hasChildren ? "/" : ""))
+
+          if (hasChildren) lines.push(render(currentPath, child))
+        }
+
+        return lines.join("\n")
+      }
+      return render([], root)
+    }
+
     return [
       [
         `Here is some useful information about the environment you are running in:`,
@@ -34,7 +81,7 @@ export namespace SystemPrompt {
         `  Today's date: ${new Date().toDateString()}`,
         `</env>`,
         `<project>`,
-        `  ${app.git ? await ListTool.execute({ path: app.path.cwd, ignore: [] }, { sessionID: sessionID, messageID: "", abort: AbortSignal.any([]) }).then((x) => x.output) : ""}`,
+        `  ${app.git ? await tree() : ""}`,
         `</project>`,
       ].join("\n"),
     ]

+ 5 - 3
packages/opencode/src/tool/ls.ts

@@ -4,7 +4,7 @@ import { App } from "../app/app"
 import * as path from "path"
 import DESCRIPTION from "./ls.txt"
 
-const IGNORE_PATTERNS = [
+export const IGNORE_PATTERNS = [
   "node_modules/",
   "__pycache__/",
   ".git/",
@@ -18,6 +18,8 @@ const IGNORE_PATTERNS = [
   ".vscode/",
 ]
 
+const LIMIT = 100
+
 export const ListTool = Tool.define({
   id: "opencode.list",
   description: DESCRIPTION,
@@ -45,7 +47,7 @@ export const ListTool = Tool.define({
       if (params.ignore?.some((pattern) => new Bun.Glob(pattern).match(file)))
         continue
       files.push(file)
-      if (files.length >= 1000) break
+      if (files.length >= LIMIT) break
     }
 
     // Build directory structure
@@ -99,7 +101,7 @@ export const ListTool = Tool.define({
     return {
       metadata: {
         count: files.length,
-        truncated: files.length >= 1000,
+        truncated: files.length >= LIMIT,
         title: path.relative(app.path.root, searchPath),
       },
       output,