diff --git a/packages/core/src/instructions/builtins.ts b/packages/core/src/instructions/builtins.ts index b116971834b..f8ce9b55358 100644 --- a/packages/core/src/instructions/builtins.ts +++ b/packages/core/src/instructions/builtins.ts @@ -3,10 +3,11 @@ export * as InstructionBuiltIns from "./builtins" import { makeLocationNode } from "../effect/app-node" import { Context, DateTime, Effect, Layer, Schema } from "effect" import { Location } from "../location" +import { SessionSchema } from "../session/schema" import { Instructions } from "./index" export interface Interface { - readonly load: () => Effect.Effect + readonly load: (sessionID: SessionSchema.ID) => Effect.Effect } export class Service extends Context.Service()("@opencode/v2/InstructionBuiltIns") {} @@ -15,38 +16,45 @@ const layer = Layer.effect( Service, Effect.gen(function* () { const location = yield* Location.Service - const instructions = Instructions.combine([ - Instructions.make({ - key: Instructions.Key.make("core/environment"), - codec: Schema.toCodecJson(Schema.String), - read: Effect.sync(() => - [ - "", - ` Working directory: ${location.directory}`, - ` Workspace root folder: ${location.project.directory}`, - ` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`, - ` Platform: ${process.platform}`, - "", - ].join("\n"), + return Service.of({ + load: (sessionID) => + Effect.succeed( + Instructions.combine([ + Instructions.make({ + key: Instructions.Key.make("core/environment"), + codec: Schema.toCodecJson(Schema.String), + read: Effect.sync(() => + [ + "", + ` Session ID: ${sessionID}`, + ` Working directory: ${location.directory}`, + ` Workspace root folder: ${location.project.directory}`, + ` Is directory a git repo: ${location.vcs?.type === "git" ? "yes" : "no"}`, + ` Platform: ${process.platform}`, + "", + ].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) }) + }) }), ) diff --git a/packages/core/src/session/runner/llm.ts b/packages/core/src/session/runner/llm.ts index 13d3f530ee0..9c8cf4d8d48 100644 --- a/packages/core/src/session/runner/llm.ts +++ b/packages/core/src/session/runner/llm.ts @@ -145,7 +145,7 @@ const layer = Layer.effect( const loadInstructions = (agent: AgentV2.Selection, sessionID: SessionSchema.ID) => Effect.all( [ - builtins.load(), + builtins.load(sessionID), discovery.load(), skillGuidance.load(agent), referenceGuidance.load(), diff --git a/packages/core/test/instructions/builtins.test.ts b/packages/core/test/instructions/builtins.test.ts index 43f2c92aee2..079c443392f 100644 --- a/packages/core/test/instructions/builtins.test.ts +++ b/packages/core/test/instructions/builtins.test.ts @@ -7,6 +7,7 @@ import { FSUtil } from "@opencode-ai/core/fs-util" import { Global } from "@opencode-ai/core/global" import { AbsolutePath } from "@opencode-ai/core/schema" import { InstructionBuiltIns } from "@opencode-ai/core/instructions/builtins" +import { SessionSchema } from "@opencode-ai/core/session/schema" import { location } from "../fixture/location" import { testEffect } from "../lib/effect" 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 projectDirectory = AbsolutePath.make(FSUtil.resolve("/repo")) 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 locationLayer = Layer.succeed( Location.Service, @@ -36,12 +38,13 @@ describe("InstructionBuiltIns", () => { Effect.gen(function* () { yield* TestClock.setTime(timestamp) const context = yield* InstructionBuiltIns.Service - const initialized = yield* readInitial(yield* context.load()) + const initialized = yield* readInitial(yield* context.load(sessionID)) expect(initialized.text).toBe( [ "Here is some useful information about the environment you are running in:", "", + ` Session ID: ${sessionID}`, ` Working directory: ${directory}`, ` Workspace root folder: ${projectDirectory}`, " Is directory a git repo: yes", @@ -58,10 +61,10 @@ describe("InstructionBuiltIns", () => { Effect.gen(function* () { yield* TestClock.setTime(timestamp) 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) - 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)}`) }), @@ -71,10 +74,10 @@ describe("InstructionBuiltIns", () => { Effect.gen(function* () { yield* TestClock.setTime(timestamp) 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) - expect((yield* readUpdate(yield* context.load(), initialized)).changed).toBe(false) + expect((yield* readUpdate(yield* context.load(sessionID), initialized)).changed).toBe(false) }), ) })