agent.test.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Exit, Scope } from "effect"
  3. import { AgentV2 } from "@opencode-ai/core/agent"
  4. import { testEffect } from "./lib/effect"
  5. const it = testEffect(AgentV2.locationLayer)
  6. describe("AgentV2", () => {
  7. it.effect("starts without agents", () =>
  8. Effect.gen(function* () {
  9. const agent = yield* AgentV2.Service
  10. expect(yield* agent.all()).toEqual([])
  11. expect(yield* agent.get(AgentV2.ID.make("build"))).toBeUndefined()
  12. }),
  13. )
  14. it.effect("materializes replayable agent transforms", () =>
  15. Effect.gen(function* () {
  16. const agent = yield* AgentV2.Service
  17. const id = AgentV2.ID.make("reviewer")
  18. const transform = yield* agent.transform()
  19. yield* transform((editor) =>
  20. editor.update(id, (info) => {
  21. info.description = "Reviews code"
  22. info.mode = "subagent"
  23. }),
  24. )
  25. expect(yield* agent.get(id)).toMatchObject({ id, description: "Reviews code", mode: "subagent" })
  26. expect((yield* agent.all()).map((info) => info.id)).toEqual([id])
  27. }),
  28. )
  29. it.effect("rebuilds state when a transform is replaced", () =>
  30. Effect.gen(function* () {
  31. const agent = yield* AgentV2.Service
  32. const id = AgentV2.ID.make("reviewer")
  33. const transform = yield* agent.transform()
  34. yield* transform((editor) =>
  35. editor.update(id, (info) => {
  36. info.description = "Old description"
  37. info.hidden = true
  38. }),
  39. )
  40. yield* transform((editor) =>
  41. editor.update(id, (info) => {
  42. info.description = "New description"
  43. }),
  44. )
  45. expect(yield* agent.get(id)).toMatchObject({ description: "New description", hidden: false })
  46. }),
  47. )
  48. it.effect("removes a transform contribution when its scope closes", () =>
  49. Effect.gen(function* () {
  50. const agent = yield* AgentV2.Service
  51. const id = AgentV2.ID.make("scoped")
  52. const scope = yield* Scope.make()
  53. const transform = yield* agent.transform().pipe(Scope.provide(scope))
  54. yield* transform((editor) => editor.update(id, () => {}))
  55. expect(yield* agent.get(id)).toBeDefined()
  56. yield* Scope.close(scope, Exit.void)
  57. expect(yield* agent.get(id)).toBeUndefined()
  58. }),
  59. )
  60. it.effect("applies direct agent updates", () =>
  61. Effect.gen(function* () {
  62. const agent = yield* AgentV2.Service
  63. const id = AgentV2.ID.make("build")
  64. yield* agent.update((editor) =>
  65. editor.update(id, (info) => {
  66. info.mode = "primary"
  67. info.hidden = true
  68. }),
  69. )
  70. expect(yield* agent.get(id)).toMatchObject({ id, mode: "primary", hidden: true })
  71. }),
  72. )
  73. it.effect("creates agents with runtime defaults and supports direct removal", () =>
  74. Effect.gen(function* () {
  75. const agent = yield* AgentV2.Service
  76. const id = AgentV2.ID.make("custom")
  77. yield* agent.update((editor) => editor.update(id, () => {}))
  78. expect(yield* agent.get(id)).toEqual(AgentV2.Info.empty(id))
  79. yield* agent.update((editor) => editor.remove(id))
  80. expect(yield* agent.get(id)).toBeUndefined()
  81. }),
  82. )
  83. })