Просмотр исходного кода

refactor(session): extract reference prompt helpers (#28197)

Shoubhit Dash 3 месяцев назад
Родитель
Сommit
dc0297f4ac

+ 0 - 5
packages/opencode/src/reference/repository-cache.ts

@@ -311,9 +311,4 @@ export const defaultLayer: Layer.Layer<Service> = layer.pipe(
   Layer.provide(Git.defaultLayer),
 )
 
-export const ensure = Effect.fn("RepositoryCache.ensure")(function* (input: EnsureInput) {
-  const cache = yield* Service
-  return yield* cache.ensure(input)
-})
-
 export * as RepositoryCache from "./repository-cache"

+ 1 - 82
packages/opencode/src/session/prompt.ts

@@ -61,6 +61,7 @@ import * as DateTime from "effect/DateTime"
 import { eq } from "@/storage/db"
 import * as Database from "@/storage/db"
 import { SessionTable } from "./session.sql"
+import { referencePromptMetadata, referenceTextPart } from "./prompt/reference"
 import { SessionReminders } from "./reminders"
 
 // @ts-ignore
@@ -82,88 +83,6 @@ const STRUCTURED_OUTPUT_SYSTEM_PROMPT = `IMPORTANT: The user has requested struc
 const log = Log.create({ service: "session.prompt" })
 const elog = EffectLogger.create({ service: "session.prompt" })
 
-type ReferencePromptMetadata = {
-  name: string
-  kind: "local" | "git" | "invalid"
-  path?: string
-  repository?: string
-  branch?: string
-  target?: string
-  targetPath?: string
-  problem?: string
-  source: { value: string; start: number; end: number }
-}
-
-function stringField(record: Record<string, unknown>, key: string) {
-  return typeof record[key] === "string" ? record[key] : undefined
-}
-
-function referencePromptMetadata(input: unknown): ReferencePromptMetadata | undefined {
-  if (!input || typeof input !== "object" || Array.isArray(input)) return
-  const record = input as Record<string, unknown>
-  const name = stringField(record, "name")
-  const kind = stringField(record, "kind")
-  if (!name || (kind !== "local" && kind !== "git" && kind !== "invalid")) return
-  if (!record.source || typeof record.source !== "object" || Array.isArray(record.source)) return
-  const source = record.source as Record<string, unknown>
-  const value = stringField(source, "value")
-  if (!value || typeof source.start !== "number" || typeof source.end !== "number") return
-  return {
-    name,
-    kind,
-    path: stringField(record, "path"),
-    repository: stringField(record, "repository"),
-    branch: stringField(record, "branch"),
-    target: stringField(record, "target"),
-    targetPath: stringField(record, "targetPath"),
-    problem: stringField(record, "problem"),
-    source: { value, start: source.start, end: source.end },
-  }
-}
-
-function referenceTextPart(input: {
-  reference: Reference.Resolved
-  source: ReferencePromptMetadata["source"]
-  target?: string
-  targetPath?: string
-  problem?: string
-}): MessageV2.TextPartInput {
-  const metadata: ReferencePromptMetadata = {
-    name: input.reference.name,
-    kind: input.reference.kind,
-    ...(input.reference.kind === "invalid"
-      ? { repository: input.reference.repository }
-      : { path: input.reference.path }),
-    ...(input.reference.kind === "git"
-      ? { repository: input.reference.repository, branch: input.reference.branch }
-      : {}),
-    ...(input.target === undefined ? {} : { target: input.target }),
-    ...(input.targetPath ? { targetPath: input.targetPath } : {}),
-    problem: input.problem ?? (input.reference.kind === "invalid" ? input.reference.message : undefined),
-    source: input.source,
-  }
-  const label = metadata.target === undefined ? `@${metadata.name}` : `@${metadata.name}/${metadata.target}`
-  return {
-    type: "text",
-    synthetic: true,
-    text: [
-      `Referenced configured reference ${label}.`,
-      ...(metadata.kind === "local" ? ["Kind: local directory"] : []),
-      ...(metadata.kind === "git" ? ["Kind: git repository"] : []),
-      ...(metadata.repository ? [`Repository: ${metadata.repository}`] : []),
-      ...(metadata.branch ? [`Branch/ref: ${metadata.branch}`] : []),
-      ...(metadata.path ? [`Reference root: ${metadata.path}`] : []),
-      ...(metadata.targetPath ? [`Resolved path: ${metadata.targetPath}`] : []),
-      ...(metadata.problem
-        ? [`Problem: ${metadata.problem}`]
-        : [
-            "For targeted context, inspect the reference path directly with Read, Glob, and Grep. For broader research, call the task tool with subagent scout and include this reference path.",
-          ]),
-    ].join("\n"),
-    metadata: { reference: metadata },
-  }
-}
-
 export interface Interface {
   readonly cancel: (sessionID: SessionID) => Effect.Effect<void>
   readonly prompt: (input: PromptInput) => Effect.Effect<MessageV2.WithParts, Image.Error>

+ 69 - 0
packages/opencode/src/session/prompt/reference.ts

@@ -0,0 +1,69 @@
+import { Option, Schema } from "effect"
+import { MessageV2 } from "../message-v2"
+import { Reference } from "@/reference/reference"
+
+const Source = Schema.Struct({
+  value: Schema.String,
+  start: Schema.Number,
+  end: Schema.Number,
+})
+
+export const ReferencePromptMetadata = Schema.Struct({
+  name: Schema.String,
+  kind: Schema.Literals(["local", "git", "invalid"]),
+  path: Schema.optional(Schema.String),
+  repository: Schema.optional(Schema.String),
+  branch: Schema.optional(Schema.String),
+  target: Schema.optional(Schema.String),
+  targetPath: Schema.optional(Schema.String),
+  problem: Schema.optional(Schema.String),
+  source: Source,
+})
+export type ReferencePromptMetadata = typeof ReferencePromptMetadata.Type
+
+const decodeReferencePromptMetadata = Schema.decodeUnknownOption(ReferencePromptMetadata)
+
+export function referencePromptMetadata(input: unknown) {
+  return Option.getOrUndefined(decodeReferencePromptMetadata(input))
+}
+
+export function referenceTextPart(input: {
+  reference: Reference.Resolved
+  source: ReferencePromptMetadata["source"]
+  target?: string
+  targetPath?: string
+  problem?: string
+}): MessageV2.TextPartInput {
+  const metadata: ReferencePromptMetadata = {
+    name: input.reference.name,
+    kind: input.reference.kind,
+    ...(input.reference.kind === "invalid" ? { repository: input.reference.repository } : { path: input.reference.path }),
+    ...(input.reference.kind === "git" ? { repository: input.reference.repository, branch: input.reference.branch } : {}),
+    ...(input.target === undefined ? {} : { target: input.target }),
+    ...(input.targetPath ? { targetPath: input.targetPath } : {}),
+    problem: input.problem ?? (input.reference.kind === "invalid" ? input.reference.message : undefined),
+    source: input.source,
+  }
+  const label = metadata.target === undefined ? `@${metadata.name}` : `@${metadata.name}/${metadata.target}`
+  return {
+    type: "text",
+    synthetic: true,
+    text: [
+      `Referenced configured reference ${label}.`,
+      ...(metadata.kind === "local" ? ["Kind: local directory"] : []),
+      ...(metadata.kind === "git" ? ["Kind: git repository"] : []),
+      ...(metadata.repository ? [`Repository: ${metadata.repository}`] : []),
+      ...(metadata.branch ? [`Branch/ref: ${metadata.branch}`] : []),
+      ...(metadata.path ? [`Reference root: ${metadata.path}`] : []),
+      ...(metadata.targetPath ? [`Resolved path: ${metadata.targetPath}`] : []),
+      ...(metadata.problem
+        ? [`Problem: ${metadata.problem}`]
+        : [
+            "For targeted context, inspect the reference path directly with Read, Glob, and Grep. For broader research, call the task tool with subagent scout and include this reference path.",
+          ]),
+    ].join("\n"),
+    metadata: { reference: metadata },
+  }
+}
+
+export * as ReferencePrompt from "./reference"