feat(core): include session ID in instructions
This commit is contained in:
parent
c1d2d7aba3
commit
ce636daf04
3 changed files with 49 additions and 38 deletions
|
|
@ -3,10 +3,11 @@ export * as InstructionBuiltIns from "./builtins"
|
||||||
import { makeLocationNode } from "../effect/app-node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Context, DateTime, Effect, Layer, Schema } from "effect"
|
import { Context, DateTime, Effect, Layer, Schema } from "effect"
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
|
import { SessionSchema } from "../session/schema"
|
||||||
import { Instructions } from "./index"
|
import { Instructions } from "./index"
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly load: () => Effect.Effect<Instructions.Instructions>
|
readonly load: (sessionID: SessionSchema.ID) => Effect.Effect<Instructions.Instructions>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/InstructionBuiltIns") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/InstructionBuiltIns") {}
|
||||||
|
|
@ -15,38 +16,45 @@ const layer = Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
const instructions = Instructions.combine([
|
return Service.of({
|
||||||
Instructions.make({
|
load: (sessionID) =>
|
||||||
key: Instructions.Key.make("core/environment"),
|
Effect.succeed(
|
||||||
codec: Schema.toCodecJson(Schema.String),
|
Instructions.combine([
|
||||||
read: Effect.sync(() =>
|
Instructions.make({
|
||||||
[
|
key: Instructions.Key.make("core/environment"),
|
||||||
"<env>",
|
codec: Schema.toCodecJson(Schema.String),
|
||||||
` Working directory: ${location.directory}`,
|
read: Effect.sync(() =>
|
||||||
` Workspace root folder: ${location.project.directory}`,
|
[
|
||||||
` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`,
|
"<env>",
|
||||||
` Platform: ${process.platform}`,
|
` Session ID: ${sessionID}`,
|
||||||
"</env>",
|
` Working directory: ${location.directory}`,
|
||||||
].join("\n"),
|
` Workspace root folder: ${location.project.directory}`,
|
||||||
|
` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`,
|
||||||
|
` Platform: ${process.platform}`,
|
||||||
|
"</env>",
|
||||||
|
].join("\n"),
|
||||||
|
),
|
||||||
|
render: {
|
||||||
|
initial: (environment) =>
|
||||||
|
["Here is some useful information about the environment you are running in:", environment].join(
|
||||||
|
"\n",
|
||||||
|
),
|
||||||
|
changed: (_previous, environment) =>
|
||||||
|
["The environment you are running in is now:", environment].join("\n"),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Instructions.make({
|
||||||
|
key: Instructions.Key.make("core/date"),
|
||||||
|
codec: Schema.toCodecJson(Schema.String),
|
||||||
|
read: DateTime.nowAsDate.pipe(Effect.map((date) => date.toDateString())),
|
||||||
|
render: {
|
||||||
|
initial: (date) => `Today's date: ${date}`,
|
||||||
|
changed: (_previous, date) => `Today's date is now: ${date}`,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
render: {
|
})
|
||||||
initial: (environment) =>
|
|
||||||
["Here is some useful information about the environment you are running in:", environment].join("\n"),
|
|
||||||
changed: (_previous, environment) => ["The environment you are running in is now:", environment].join("\n"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Instructions.make({
|
|
||||||
key: Instructions.Key.make("core/date"),
|
|
||||||
codec: Schema.toCodecJson(Schema.String),
|
|
||||||
read: DateTime.nowAsDate.pipe(Effect.map((date) => date.toDateString())),
|
|
||||||
render: {
|
|
||||||
initial: (date) => `Today's date: ${date}`,
|
|
||||||
changed: (_previous, date) => `Today's date is now: ${date}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
|
|
||||||
return Service.of({ load: () => Effect.succeed(instructions) })
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ const layer = Layer.effect(
|
||||||
const loadInstructions = (agent: AgentV2.Selection, sessionID: SessionSchema.ID) =>
|
const loadInstructions = (agent: AgentV2.Selection, sessionID: SessionSchema.ID) =>
|
||||||
Effect.all(
|
Effect.all(
|
||||||
[
|
[
|
||||||
builtins.load(),
|
builtins.load(sessionID),
|
||||||
discovery.load(),
|
discovery.load(),
|
||||||
skillGuidance.load(agent),
|
skillGuidance.load(agent),
|
||||||
referenceGuidance.load(),
|
referenceGuidance.load(),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||||
import { InstructionBuiltIns } from "@opencode-ai/core/instructions/builtins"
|
import { InstructionBuiltIns } from "@opencode-ai/core/instructions/builtins"
|
||||||
|
import { SessionSchema } from "@opencode-ai/core/session/schema"
|
||||||
import { location } from "../fixture/location"
|
import { location } from "../fixture/location"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
import { readInitial, readUpdate } from "../lib/instructions"
|
import { readInitial, readUpdate } from "../lib/instructions"
|
||||||
|
|
@ -14,6 +15,7 @@ import { readInitial, readUpdate } from "../lib/instructions"
|
||||||
const directory = AbsolutePath.make(FSUtil.resolve("/repo/packages/core"))
|
const directory = AbsolutePath.make(FSUtil.resolve("/repo/packages/core"))
|
||||||
const projectDirectory = AbsolutePath.make(FSUtil.resolve("/repo"))
|
const projectDirectory = AbsolutePath.make(FSUtil.resolve("/repo"))
|
||||||
const timestamp = Date.parse("2026-06-03T12:00:00.000Z")
|
const timestamp = Date.parse("2026-06-03T12:00:00.000Z")
|
||||||
|
const sessionID = SessionSchema.ID.make("ses_builtin_test")
|
||||||
const localDate = (time: number) => new Date(time).toDateString()
|
const localDate = (time: number) => new Date(time).toDateString()
|
||||||
const locationLayer = Layer.succeed(
|
const locationLayer = Layer.succeed(
|
||||||
Location.Service,
|
Location.Service,
|
||||||
|
|
@ -36,12 +38,13 @@ describe("InstructionBuiltIns", () => {
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* TestClock.setTime(timestamp)
|
yield* TestClock.setTime(timestamp)
|
||||||
const context = yield* InstructionBuiltIns.Service
|
const context = yield* InstructionBuiltIns.Service
|
||||||
const initialized = yield* readInitial(yield* context.load())
|
const initialized = yield* readInitial(yield* context.load(sessionID))
|
||||||
|
|
||||||
expect(initialized.text).toBe(
|
expect(initialized.text).toBe(
|
||||||
[
|
[
|
||||||
"Here is some useful information about the environment you are running in:",
|
"Here is some useful information about the environment you are running in:",
|
||||||
"<env>",
|
"<env>",
|
||||||
|
` Session ID: ${sessionID}`,
|
||||||
` Working directory: ${directory}`,
|
` Working directory: ${directory}`,
|
||||||
` Workspace root folder: ${projectDirectory}`,
|
` Workspace root folder: ${projectDirectory}`,
|
||||||
" Is directory a git repo: yes",
|
" Is directory a git repo: yes",
|
||||||
|
|
@ -58,10 +61,10 @@ describe("InstructionBuiltIns", () => {
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* TestClock.setTime(timestamp)
|
yield* TestClock.setTime(timestamp)
|
||||||
const context = yield* InstructionBuiltIns.Service
|
const context = yield* InstructionBuiltIns.Service
|
||||||
const initialized = yield* readInitial(yield* context.load())
|
const initialized = yield* readInitial(yield* context.load(sessionID))
|
||||||
|
|
||||||
yield* TestClock.setTime(timestamp + 24 * 60 * 60 * 1000)
|
yield* TestClock.setTime(timestamp + 24 * 60 * 60 * 1000)
|
||||||
const refreshed = yield* readUpdate(yield* context.load(), initialized)
|
const refreshed = yield* readUpdate(yield* context.load(sessionID), initialized)
|
||||||
|
|
||||||
expect(refreshed.text).toBe(`Today's date is now: ${localDate(timestamp + 24 * 60 * 60 * 1000)}`)
|
expect(refreshed.text).toBe(`Today's date is now: ${localDate(timestamp + 24 * 60 * 60 * 1000)}`)
|
||||||
}),
|
}),
|
||||||
|
|
@ -71,10 +74,10 @@ describe("InstructionBuiltIns", () => {
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* TestClock.setTime(timestamp)
|
yield* TestClock.setTime(timestamp)
|
||||||
const context = yield* InstructionBuiltIns.Service
|
const context = yield* InstructionBuiltIns.Service
|
||||||
const initialized = yield* readInitial(yield* context.load())
|
const initialized = yield* readInitial(yield* context.load(sessionID))
|
||||||
|
|
||||||
yield* TestClock.setTime(timestamp + 60 * 60 * 1000)
|
yield* TestClock.setTime(timestamp + 60 * 60 * 1000)
|
||||||
expect((yield* readUpdate(yield* context.load(), initialized)).changed).toBe(false)
|
expect((yield* readUpdate(yield* context.load(sessionID), initialized)).changed).toBe(false)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue