feat(core): include session ID in instructions

This commit is contained in:
Dax Raad
2026-07-15 00:47:10 -04:00
parent c1d2d7aba3
commit ce636daf04
3 changed files with 49 additions and 38 deletions
+15 -7
View File
@@ -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,13 +16,17 @@ 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({
load: (sessionID) =>
Effect.succeed(
Instructions.combine([
Instructions.make({ Instructions.make({
key: Instructions.Key.make("core/environment"), key: Instructions.Key.make("core/environment"),
codec: Schema.toCodecJson(Schema.String), codec: Schema.toCodecJson(Schema.String),
read: Effect.sync(() => read: Effect.sync(() =>
[ [
"<env>", "<env>",
` Session ID: ${sessionID}`,
` Working directory: ${location.directory}`, ` Working directory: ${location.directory}`,
` Workspace root folder: ${location.project.directory}`, ` Workspace root folder: ${location.project.directory}`,
` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`, ` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`,
@@ -31,8 +36,11 @@ const layer = Layer.effect(
), ),
render: { render: {
initial: (environment) => initial: (environment) =>
["Here is some useful information about the environment you are running in:", environment].join("\n"), ["Here is some useful information about the environment you are running in:", environment].join(
changed: (_previous, environment) => ["The environment you are running in is now:", environment].join("\n"), "\n",
),
changed: (_previous, environment) =>
["The environment you are running in is now:", environment].join("\n"),
}, },
}), }),
Instructions.make({ Instructions.make({
@@ -44,9 +52,9 @@ const layer = Layer.effect(
changed: (_previous, date) => `Today's date is now: ${date}`, changed: (_previous, date) => `Today's date is now: ${date}`,
}, },
}), }),
]) ]),
),
return Service.of({ load: () => Effect.succeed(instructions) }) })
}), }),
) )
+1 -1
View File
@@ -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)
}), }),
) )
}) })