builtins.test.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Layer } from "effect"
  3. import * as TestClock from "effect/testing/TestClock"
  4. import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
  5. import { Location } from "@opencode-ai/core/location"
  6. import { FSUtil } from "@opencode-ai/util/fs-util"
  7. import { Global } from "@opencode-ai/util/global"
  8. import { AbsolutePath } from "@opencode-ai/core/schema"
  9. import { InstructionBuiltIns } from "@opencode-ai/core/instructions/builtins"
  10. import { SessionSchema } from "@opencode-ai/core/session/schema"
  11. import { location } from "../fixture/location"
  12. import { testEffect } from "../lib/effect"
  13. import { readInitial, readUpdate } from "../lib/instructions"
  14. const directory = AbsolutePath.make(FSUtil.resolve("/repo/packages/core"))
  15. const projectDirectory = AbsolutePath.make(FSUtil.resolve("/repo"))
  16. const timestamp = Date.parse("2026-06-03T12:00:00.000Z")
  17. const sessionID = SessionSchema.ID.make("ses_builtin_test")
  18. const localDate = (time: number) => new Date(time).toDateString()
  19. const locationLayer = Layer.succeed(
  20. Location.Service,
  21. Location.Service.of(
  22. location(
  23. { directory },
  24. { projectDirectory, vcs: { type: "git", store: AbsolutePath.make(FSUtil.resolve("/repo/.git")) } },
  25. ),
  26. ),
  27. )
  28. const it = testEffect(
  29. AppNodeBuilder.build(InstructionBuiltIns.node, [
  30. [Location.node, locationLayer],
  31. [Global.node, Global.layerWith({ config: "/global", tmp: "/temporary" })],
  32. ]),
  33. )
  34. describe("InstructionBuiltIns", () => {
  35. it.effect("loads location-scoped environment and host-local date instructions", () =>
  36. Effect.gen(function* () {
  37. yield* TestClock.setTime(timestamp)
  38. const context = yield* InstructionBuiltIns.Service
  39. const initialized = yield* readInitial(yield* context.load(sessionID))
  40. expect(initialized.text).toBe(
  41. [
  42. "Here is some useful information about the environment you are running in:",
  43. "<env>",
  44. ` Current conversation session ID: ${sessionID}`,
  45. ` Working directory: ${directory}`,
  46. ` Workspace root folder: ${projectDirectory}`,
  47. " Is directory a git repo: yes",
  48. ` Platform: ${process.platform}`,
  49. " Use /temporary for temporary work outside the workspace; it already exists and is pre-approved for external directory access.",
  50. "</env>",
  51. "",
  52. `Today's date: ${localDate(timestamp)}`,
  53. ].join("\n"),
  54. )
  55. }),
  56. )
  57. it.effect("updates the date without repeating unchanged environment instructions", () =>
  58. Effect.gen(function* () {
  59. yield* TestClock.setTime(timestamp)
  60. const context = yield* InstructionBuiltIns.Service
  61. const initialized = yield* readInitial(yield* context.load(sessionID))
  62. yield* TestClock.setTime(timestamp + 24 * 60 * 60 * 1000)
  63. const refreshed = yield* readUpdate(yield* context.load(sessionID), initialized)
  64. expect(refreshed.text).toBe(`Today's date is now: ${localDate(timestamp + 24 * 60 * 60 * 1000)}`)
  65. }),
  66. )
  67. it.effect("does not update again within the same local calendar day", () =>
  68. Effect.gen(function* () {
  69. yield* TestClock.setTime(timestamp)
  70. const context = yield* InstructionBuiltIns.Service
  71. const initialized = yield* readInitial(yield* context.load(sessionID))
  72. yield* TestClock.setTime(timestamp + 60 * 60 * 1000)
  73. expect((yield* readUpdate(yield* context.load(sessionID), initialized)).changed).toBe(false)
  74. }),
  75. )
  76. })