mirror of
https://github.com/anomalyco/opencode.git
synced 2026-04-29 09:16:36 +00:00
refactor(instruction): migrate to Effect service pattern (#20542)
This commit is contained in:
@@ -1,11 +1,53 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
||||
import path from "path"
|
||||
import { InstructionPrompt } from "../../src/session/instruction"
|
||||
import { ModelID, ProviderID } from "../../src/provider/schema"
|
||||
import { Instruction } from "../../src/session/instruction"
|
||||
import type { MessageV2 } from "../../src/session/message-v2"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
import { MessageID, PartID, SessionID } from "../../src/session/schema"
|
||||
import { Global } from "../../src/global"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
|
||||
describe("InstructionPrompt.resolve", () => {
|
||||
function loaded(filepath: string): MessageV2.WithParts[] {
|
||||
const sessionID = SessionID.make("session-loaded-1")
|
||||
const messageID = MessageID.make("message-loaded-1")
|
||||
|
||||
return [
|
||||
{
|
||||
info: {
|
||||
id: messageID,
|
||||
sessionID,
|
||||
role: "user",
|
||||
time: { created: 0 },
|
||||
agent: "build",
|
||||
model: {
|
||||
providerID: ProviderID.make("anthropic"),
|
||||
modelID: ModelID.make("claude-sonnet-4-20250514"),
|
||||
},
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: PartID.make("part-loaded-1"),
|
||||
messageID,
|
||||
sessionID,
|
||||
type: "tool",
|
||||
callID: "call-loaded-1",
|
||||
tool: "read",
|
||||
state: {
|
||||
status: "completed",
|
||||
input: {},
|
||||
output: "done",
|
||||
title: "Read",
|
||||
metadata: { loaded: [filepath] },
|
||||
time: { start: 0, end: 1 },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
describe("Instruction.resolve", () => {
|
||||
test("returns empty when AGENTS.md is at project root (already in systemPaths)", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
@@ -16,10 +58,14 @@ describe("InstructionPrompt.resolve", () => {
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const system = await InstructionPrompt.systemPaths()
|
||||
const system = await Instruction.systemPaths()
|
||||
expect(system.has(path.join(tmp.path, "AGENTS.md"))).toBe(true)
|
||||
|
||||
const results = await InstructionPrompt.resolve([], path.join(tmp.path, "src", "file.ts"), "test-message-1")
|
||||
const results = await Instruction.resolve(
|
||||
[],
|
||||
path.join(tmp.path, "src", "file.ts"),
|
||||
MessageID.make("message-test-1"),
|
||||
)
|
||||
expect(results).toEqual([])
|
||||
},
|
||||
})
|
||||
@@ -35,13 +81,13 @@ describe("InstructionPrompt.resolve", () => {
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const system = await InstructionPrompt.systemPaths()
|
||||
const system = await Instruction.systemPaths()
|
||||
expect(system.has(path.join(tmp.path, "subdir", "AGENTS.md"))).toBe(false)
|
||||
|
||||
const results = await InstructionPrompt.resolve(
|
||||
const results = await Instruction.resolve(
|
||||
[],
|
||||
path.join(tmp.path, "subdir", "nested", "file.ts"),
|
||||
"test-message-2",
|
||||
MessageID.make("message-test-2"),
|
||||
)
|
||||
expect(results.length).toBe(1)
|
||||
expect(results[0].filepath).toBe(path.join(tmp.path, "subdir", "AGENTS.md"))
|
||||
@@ -60,17 +106,87 @@ describe("InstructionPrompt.resolve", () => {
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const filepath = path.join(tmp.path, "subdir", "AGENTS.md")
|
||||
const system = await InstructionPrompt.systemPaths()
|
||||
const system = await Instruction.systemPaths()
|
||||
expect(system.has(filepath)).toBe(false)
|
||||
|
||||
const results = await InstructionPrompt.resolve([], filepath, "test-message-2")
|
||||
const results = await Instruction.resolve([], filepath, MessageID.make("message-test-3"))
|
||||
expect(results).toEqual([])
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("does not reattach the same nearby instructions twice for one message", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "subdir", "AGENTS.md"), "# Subdir Instructions")
|
||||
await Bun.write(path.join(dir, "subdir", "nested", "file.ts"), "const x = 1")
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const filepath = path.join(tmp.path, "subdir", "nested", "file.ts")
|
||||
const id = MessageID.make("message-claim-1")
|
||||
|
||||
const first = await Instruction.resolve([], filepath, id)
|
||||
const second = await Instruction.resolve([], filepath, id)
|
||||
|
||||
expect(first).toHaveLength(1)
|
||||
expect(first[0].filepath).toBe(path.join(tmp.path, "subdir", "AGENTS.md"))
|
||||
expect(second).toEqual([])
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("clear allows nearby instructions to be attached again for the same message", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "subdir", "AGENTS.md"), "# Subdir Instructions")
|
||||
await Bun.write(path.join(dir, "subdir", "nested", "file.ts"), "const x = 1")
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const filepath = path.join(tmp.path, "subdir", "nested", "file.ts")
|
||||
const id = MessageID.make("message-claim-2")
|
||||
|
||||
const first = await Instruction.resolve([], filepath, id)
|
||||
await Instruction.clear(id)
|
||||
const second = await Instruction.resolve([], filepath, id)
|
||||
|
||||
expect(first).toHaveLength(1)
|
||||
expect(second).toHaveLength(1)
|
||||
expect(second[0].filepath).toBe(path.join(tmp.path, "subdir", "AGENTS.md"))
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("skips instructions already reported by prior read metadata", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "subdir", "AGENTS.md"), "# Subdir Instructions")
|
||||
await Bun.write(path.join(dir, "subdir", "nested", "file.ts"), "const x = 1")
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const agents = path.join(tmp.path, "subdir", "AGENTS.md")
|
||||
const filepath = path.join(tmp.path, "subdir", "nested", "file.ts")
|
||||
const id = MessageID.make("message-claim-3")
|
||||
|
||||
const results = await Instruction.resolve(loaded(agents), filepath, id)
|
||||
|
||||
expect(results).toEqual([])
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test.todo("fetches remote instructions from config URLs via HttpClient", () => {})
|
||||
})
|
||||
|
||||
describe("InstructionPrompt.systemPaths OPENCODE_CONFIG_DIR", () => {
|
||||
describe("Instruction.systemPaths OPENCODE_CONFIG_DIR", () => {
|
||||
let originalConfigDir: string | undefined
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -106,7 +222,7 @@ describe("InstructionPrompt.systemPaths OPENCODE_CONFIG_DIR", () => {
|
||||
await Instance.provide({
|
||||
directory: projectTmp.path,
|
||||
fn: async () => {
|
||||
const paths = await InstructionPrompt.systemPaths()
|
||||
const paths = await Instruction.systemPaths()
|
||||
expect(paths.has(path.join(profileTmp.path, "AGENTS.md"))).toBe(true)
|
||||
expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(false)
|
||||
},
|
||||
@@ -133,7 +249,7 @@ describe("InstructionPrompt.systemPaths OPENCODE_CONFIG_DIR", () => {
|
||||
await Instance.provide({
|
||||
directory: projectTmp.path,
|
||||
fn: async () => {
|
||||
const paths = await InstructionPrompt.systemPaths()
|
||||
const paths = await Instruction.systemPaths()
|
||||
expect(paths.has(path.join(profileTmp.path, "AGENTS.md"))).toBe(false)
|
||||
expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(true)
|
||||
},
|
||||
@@ -159,7 +275,7 @@ describe("InstructionPrompt.systemPaths OPENCODE_CONFIG_DIR", () => {
|
||||
await Instance.provide({
|
||||
directory: projectTmp.path,
|
||||
fn: async () => {
|
||||
const paths = await InstructionPrompt.systemPaths()
|
||||
const paths = await Instruction.systemPaths()
|
||||
expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(true)
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user