system.test.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Layer } from "effect"
  3. import type { Agent } from "../../src/agent/agent"
  4. import { NamedError } from "@opencode-ai/core/util/error"
  5. import { Skill } from "../../src/skill"
  6. import { Permission } from "../../src/permission"
  7. import { SystemPrompt } from "../../src/session/system"
  8. import { testEffect } from "../lib/effect"
  9. const skills: Skill.Info[] = [
  10. {
  11. name: "zeta-skill",
  12. description: "Zeta skill.",
  13. location: "/tmp/zeta-skill/SKILL.md",
  14. content: "# zeta-skill",
  15. },
  16. {
  17. name: "alpha-skill",
  18. description: "Alpha skill.",
  19. location: "/tmp/alpha-skill/SKILL.md",
  20. content: "# alpha-skill",
  21. },
  22. {
  23. name: "middle-skill",
  24. description: "Middle skill.",
  25. location: "/tmp/middle-skill/SKILL.md",
  26. content: "# middle-skill",
  27. },
  28. {
  29. name: "manual-skill",
  30. location: "/tmp/manual-skill/SKILL.md",
  31. content: "# manual-skill",
  32. },
  33. ]
  34. const build: Agent.Info = {
  35. name: "build",
  36. mode: "primary",
  37. permission: Permission.fromConfig({ "*": "allow" }),
  38. options: {},
  39. }
  40. const it = testEffect(
  41. SystemPrompt.layer.pipe(
  42. Layer.provide(
  43. Layer.succeed(
  44. Skill.Service,
  45. Skill.Service.of({
  46. get: (name) => Effect.succeed(skills.find((skill) => skill.name === name)),
  47. require: (name) => {
  48. const info = skills.find((skill) => skill.name === name)
  49. if (info) return Effect.succeed(info)
  50. return Effect.fail(new Skill.NotFoundError({ name, available: skills.map((skill) => skill.name) }))
  51. },
  52. all: () => Effect.succeed(skills),
  53. dirs: () => Effect.succeed([]),
  54. available: () => Effect.succeed(skills),
  55. }),
  56. ),
  57. ),
  58. ),
  59. )
  60. describe("session.system", () => {
  61. it.effect("skills output is sorted by name and stable across calls", () =>
  62. Effect.gen(function* () {
  63. const prompt = yield* SystemPrompt.Service
  64. const first = yield* prompt.skills(build)
  65. const second = yield* prompt.skills(build)
  66. const output = first ?? (yield* Effect.fail(new NamedError.Unknown({ message: "missing skills output" })))
  67. expect(first).toBe(second)
  68. const alpha = output.indexOf("<name>alpha-skill</name>")
  69. const middle = output.indexOf("<name>middle-skill</name>")
  70. const zeta = output.indexOf("<name>zeta-skill</name>")
  71. expect(alpha).toBeGreaterThan(-1)
  72. expect(middle).toBeGreaterThan(alpha)
  73. expect(zeta).toBeGreaterThan(middle)
  74. expect(output).not.toContain("manual-skill")
  75. }),
  76. )
  77. })