refactor(scout): resolve configured reference mentions (#26701)

This commit is contained in:
Shoubhit Dash
2026-05-11 12:57:26 +05:30
committed by GitHub
parent 5d6f2a1524
commit 7e997cfba4
9 changed files with 304 additions and 116 deletions

View File

@@ -56,7 +56,8 @@ import { EffectBridge } from "@/effect/bridge"
import { SyncEvent } from "@/sync"
import { SessionEvent } from "@/v2/session-event"
import { Modelv2 } from "@/v2/model"
import { AgentAttachment, FileAttachment, Source } from "@/v2/session-prompt"
import { AgentAttachment, FileAttachment, ReferenceAttachment, Source } from "@/v2/session-prompt"
import { Reference } from "@/reference/reference"
import * as DateTime from "effect/DateTime"
import { eq } from "@/storage/db"
import * as Database from "@/storage/db"
@@ -81,6 +82,45 @@ 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 },
}
}
export interface Interface {
readonly cancel: (sessionID: SessionID) => Effect.Effect<void>
readonly prompt: (input: PromptInput) => Effect.Effect<MessageV2.WithParts>
@@ -119,6 +159,7 @@ export const layer = Layer.effect(
const summary = yield* SessionSummary.Service
const sys = yield* SystemPrompt.Service
const llm = yield* LLM.Service
const references = yield* Reference.Service
const sync = yield* SyncEvent.Service
const runner = Effect.fn("SessionPrompt.runner")(function* () {
return yield* EffectBridge.make()
@@ -141,12 +182,116 @@ export const layer = Layer.effect(
const parts: Types.DeepMutable<PromptInput["parts"]> = [{ type: "text", text: template }]
const files = ConfigMarkdown.files(template)
const seen = new Set<string>()
const mentionSource = (match: RegExpMatchArray) => {
const start = match.index ?? 0
return { value: match[0], start, end: start + match[0].length }
}
const referenceTextPart = (input: {
reference: Reference.Resolved
source: ReturnType<typeof mentionSource>
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 },
}
}
yield* Effect.forEach(
files,
Effect.fnUntraced(function* (match) {
const name = match[1]
if (!name) return
if (seen.has(name)) return
seen.add(name)
const slash = name.indexOf("/")
const alias = slash === -1 ? name : name.slice(0, slash)
const reference = yield* references.get(alias)
if (reference) {
const source = mentionSource(match)
if (reference.kind === "invalid") {
parts.push(
referenceTextPart({ reference, source, target: slash === -1 ? undefined : name.slice(slash + 1) }),
)
return
}
yield* references.ensure(reference.path)
if (slash === -1) {
parts.push(referenceTextPart({ reference, source }))
return
}
const target = name.slice(slash + 1)
const targetPath = path.resolve(reference.path, target)
if (!AppFileSystem.contains(reference.path, targetPath)) {
parts.push(
referenceTextPart({
reference,
source,
target,
targetPath,
problem: `Path escapes configured reference @${alias}: ${target}`,
}),
)
return
}
const info = yield* fsys.stat(targetPath).pipe(Effect.option)
if (Option.isNone(info)) {
parts.push(
referenceTextPart({
reference,
source,
target,
targetPath,
problem: `Path does not exist inside configured reference @${alias}: ${target}`,
}),
)
return
}
parts.push({
type: "file",
url: pathToFileURL(targetPath).href,
filename: name,
mime: info.value.type === "Directory" ? "application/x-directory" : "text/plain",
})
return
}
const filepath = name.startsWith("~/")
? path.join(os.homedir(), name.slice(2))
: path.resolve(ctx.worktree, name)
@@ -1326,6 +1471,26 @@ NOTE: At any point in time through this workflow you should feel free to ask the
if (part.type === "text") {
if (part.synthetic) result.synthetic.push(part.text)
else result.text.push(part.text)
const reference = referencePromptMetadata(part.metadata?.reference)
if (reference) {
result.references.push(
new ReferenceAttachment({
name: reference.name,
kind: reference.kind,
uri: reference.path ? pathToFileURL(reference.path).href : undefined,
repository: reference.repository,
branch: reference.branch,
target: reference.target,
targetUri: reference.targetPath ? pathToFileURL(reference.targetPath).href : undefined,
problem: reference.problem,
source: new Source({
start: reference.source.start,
end: reference.source.end,
text: reference.source.value,
}),
}),
)
}
}
if (part.type === "file") {
result.files.push(
@@ -1363,6 +1528,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
text: [] as string[],
files: [] as FileAttachment[],
agents: [] as AgentAttachment[],
references: [] as ReferenceAttachment[],
synthetic: [] as string[],
},
)
@@ -1375,6 +1541,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
text: nextPrompt.text.join("\n"),
files: nextPrompt.files,
agents: nextPrompt.agents,
references: nextPrompt.references,
},
})
}
@@ -1817,6 +1984,7 @@ export const defaultLayer = Layer.suspend(() =>
Agent.defaultLayer,
SystemPrompt.defaultLayer,
LLM.defaultLayer,
Reference.defaultLayer,
Bus.layer,
CrossSpawnSpawner.defaultLayer,
SyncEvent.defaultLayer,