shared-schema.test.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { expect, test } from "bun:test"
  2. import { Schema } from "effect"
  3. import { AgentV2 } from "@opencode-ai/core/agent"
  4. import { ModelV2 } from "@opencode-ai/core/model"
  5. import { SessionV2 } from "@opencode-ai/core/session"
  6. import { Agent } from "@opencode-ai/schema/agent"
  7. import { Location } from "@opencode-ai/schema/location"
  8. import { Model } from "@opencode-ai/schema/model"
  9. import { AgentAttachment, FileAttachment, Prompt, Source } from "@opencode-ai/schema/prompt"
  10. import { Provider } from "@opencode-ai/schema/provider"
  11. import { Project } from "@opencode-ai/schema/project"
  12. import { ProjectDirectories } from "@opencode-ai/schema/project-directories"
  13. import { PermissionV1 } from "@opencode-ai/schema/permission-v1"
  14. import { Session } from "@opencode-ai/schema/session"
  15. import { SessionInput } from "@opencode-ai/schema/session-input"
  16. import { SessionMessage } from "@opencode-ai/schema/session-message"
  17. import { Workspace } from "@opencode-ai/schema/workspace"
  18. import { Command } from "@opencode-ai/schema/command"
  19. import { Connection } from "@opencode-ai/schema/connection"
  20. import { Credential } from "@opencode-ai/schema/credential"
  21. import { FileSystem } from "@opencode-ai/schema/filesystem"
  22. import { Integration } from "@opencode-ai/schema/integration"
  23. import { LLM } from "@opencode-ai/schema/llm"
  24. import { Permission } from "@opencode-ai/schema/permission"
  25. import { Plugin } from "@opencode-ai/schema/plugin"
  26. import { Pty } from "@opencode-ai/schema/pty"
  27. import { Reference } from "@opencode-ai/schema/reference"
  28. import { SessionTodo } from "@opencode-ai/schema/session-todo"
  29. import { Skill } from "@opencode-ai/schema/skill"
  30. import { AbsolutePath, DateTimeUtcFromMillis, optional, statics } from "@opencode-ai/schema/schema"
  31. import { ProviderV2 } from "@opencode-ai/core/provider"
  32. import { PluginV2 } from "@opencode-ai/core/plugin"
  33. test("Core reuses the canonical shared schemas", async () => {
  34. const [
  35. coreCommand,
  36. coreConnection,
  37. coreCredential,
  38. coreFileSystem,
  39. coreIntegration,
  40. coreLocation,
  41. coreLLM,
  42. corePermission,
  43. corePermissionV1,
  44. coreProjectCopy,
  45. corePty,
  46. coreProject,
  47. coreReference,
  48. coreSessionInput,
  49. coreSessionMessage,
  50. coreSessionTodo,
  51. corePrompt,
  52. coreSkill,
  53. coreV2Schema,
  54. coreSchema,
  55. coreWorkspace,
  56. ] = await Promise.all([
  57. import("@opencode-ai/core/command"),
  58. import("@opencode-ai/core/integration/connection"),
  59. import("@opencode-ai/core/credential"),
  60. import("@opencode-ai/core/filesystem"),
  61. import("@opencode-ai/core/integration"),
  62. import("@opencode-ai/core/location"),
  63. import("@opencode-ai/llm"),
  64. import("@opencode-ai/core/permission"),
  65. import("@opencode-ai/core/v1/permission"),
  66. import("@opencode-ai/core/project/copy"),
  67. import("@opencode-ai/core/pty"),
  68. import("@opencode-ai/core/project/schema"),
  69. import("@opencode-ai/core/reference"),
  70. import("@opencode-ai/core/session/input"),
  71. import("@opencode-ai/core/session/message"),
  72. import("@opencode-ai/core/session/todo"),
  73. import("@opencode-ai/core/session/prompt"),
  74. import("@opencode-ai/core/skill"),
  75. import("@opencode-ai/core/v2-schema"),
  76. import("@opencode-ai/core/schema"),
  77. import("@opencode-ai/core/workspace"),
  78. ])
  79. const schemas = [
  80. [AgentV2.ID, Agent.ID],
  81. [AgentV2.Color, Agent.Color],
  82. [AgentV2.Info, Agent.Info],
  83. [coreCommand.Info, Command.Info],
  84. [coreConnection.CredentialInfo, Connection.CredentialInfo],
  85. [coreConnection.EnvInfo, Connection.EnvInfo],
  86. [coreConnection.Info, Connection.Info],
  87. [coreCredential.ID, Credential.ID],
  88. [coreCredential.OAuth, Credential.OAuth],
  89. [coreCredential.Key, Credential.Key],
  90. [coreCredential.Value, Credential.Value],
  91. [coreFileSystem.Entry, FileSystem.Entry],
  92. [coreFileSystem.Submatch, FileSystem.Submatch],
  93. [coreFileSystem.Match, FileSystem.Match],
  94. [coreIntegration.ID, Integration.ID],
  95. [coreIntegration.MethodID, Integration.MethodID],
  96. [coreIntegration.When, Integration.When],
  97. [coreIntegration.TextPrompt, Integration.TextPrompt],
  98. [coreIntegration.SelectPrompt, Integration.SelectPrompt],
  99. [coreIntegration.Prompt, Integration.Prompt],
  100. [coreIntegration.OAuthMethod, Integration.OAuthMethod],
  101. [coreIntegration.KeyMethod, Integration.KeyMethod],
  102. [coreIntegration.EnvMethod, Integration.EnvMethod],
  103. [coreIntegration.Method, Integration.Method],
  104. [coreIntegration.Inputs, Integration.Inputs],
  105. [coreIntegration.Ref, Integration.Ref],
  106. [coreLocation.Ref, Location.Ref],
  107. [coreLLM.ProviderMetadata, LLM.ProviderMetadata],
  108. [coreLLM.ToolTextContent, LLM.ToolTextContent],
  109. [coreLLM.ToolFileContent, LLM.ToolFileContent],
  110. [coreLLM.ToolContent, LLM.ToolContent],
  111. [ModelV2.ID, Model.ID],
  112. [ModelV2.VariantID, Model.VariantID],
  113. [ModelV2.Ref, Model.Ref],
  114. [ModelV2.Family, Model.Family],
  115. [ModelV2.Capabilities, Model.Capabilities],
  116. [ModelV2.Cost, Model.Cost],
  117. [ModelV2.Api, Model.Api],
  118. [ModelV2.Info, Model.Info],
  119. [ProviderV2.ID, Provider.ID],
  120. [ProviderV2.AISDK, Provider.AISDK],
  121. [ProviderV2.Native, Provider.Native],
  122. [ProviderV2.Api, Provider.Api],
  123. [ProviderV2.Request, Provider.Request],
  124. [ProviderV2.Info, Provider.Info],
  125. [corePermission.Effect, Permission.Effect],
  126. [corePermission.Rule, Permission.Rule],
  127. [corePermission.Ruleset, Permission.Ruleset],
  128. [corePermissionV1.Event, PermissionV1.Event],
  129. [coreProjectCopy.Event, ProjectDirectories.Event],
  130. [PluginV2.ID, Plugin.ID],
  131. [PluginV2.Event, Plugin.Event],
  132. [corePty.Info, Pty.Info],
  133. [corePty.Event, Pty.Event],
  134. [coreProject.ID, Project.ID],
  135. [coreReference.LocalSource, Reference.LocalSource],
  136. [coreReference.GitSource, Reference.GitSource],
  137. [coreReference.Source, Reference.Source],
  138. [SessionV2.ID, Session.ID],
  139. [SessionV2.Info, Session.Info],
  140. [SessionV2.ListAnchor, Session.ListAnchor],
  141. [coreSessionInput.Delivery, SessionInput.Delivery],
  142. [coreSessionInput.Admitted, SessionInput.Admitted],
  143. [coreSessionMessage.ID, SessionMessage.ID],
  144. [coreSessionMessage.UnknownError, SessionMessage.UnknownError],
  145. [coreSessionMessage.AgentSwitched, SessionMessage.AgentSwitched],
  146. [coreSessionMessage.ModelSwitched, SessionMessage.ModelSwitched],
  147. [coreSessionMessage.User, SessionMessage.User],
  148. [coreSessionMessage.Synthetic, SessionMessage.Synthetic],
  149. [coreSessionMessage.System, SessionMessage.System],
  150. [coreSessionMessage.Shell, SessionMessage.Shell],
  151. [coreSessionMessage.ToolStatePending, SessionMessage.ToolStatePending],
  152. [coreSessionMessage.ToolStateRunning, SessionMessage.ToolStateRunning],
  153. [coreSessionMessage.ToolStateCompleted, SessionMessage.ToolStateCompleted],
  154. [coreSessionMessage.ToolStateError, SessionMessage.ToolStateError],
  155. [coreSessionMessage.ToolState, SessionMessage.ToolState],
  156. [coreSessionMessage.AssistantTool, SessionMessage.AssistantTool],
  157. [coreSessionMessage.AssistantText, SessionMessage.AssistantText],
  158. [coreSessionMessage.AssistantReasoning, SessionMessage.AssistantReasoning],
  159. [coreSessionMessage.AssistantContent, SessionMessage.AssistantContent],
  160. [coreSessionMessage.Assistant, SessionMessage.Assistant],
  161. [coreSessionMessage.Compaction, SessionMessage.Compaction],
  162. [coreSessionMessage.Message, SessionMessage.Message],
  163. [coreSessionTodo.Info, SessionTodo.Info],
  164. [coreSessionTodo.Event, SessionTodo.Event],
  165. [corePrompt.Source, Source],
  166. [corePrompt.FileAttachment, FileAttachment],
  167. [corePrompt.AgentAttachment, AgentAttachment],
  168. [corePrompt.Prompt, Prompt],
  169. [coreSkill.DirectorySource, Skill.DirectorySource],
  170. [coreSkill.UrlSource, Skill.UrlSource],
  171. [coreSkill.EmbeddedSource, Skill.EmbeddedSource],
  172. [coreSkill.Source, Skill.Source],
  173. [coreSkill.Info, Skill.Info],
  174. [coreV2Schema.DateTimeUtcFromMillis, DateTimeUtcFromMillis],
  175. [coreSchema.optional, optional],
  176. [coreSchema.statics, statics],
  177. [coreWorkspace.ID, Workspace.ID],
  178. ]
  179. for (const [core, shared] of schemas) expect(core).toBe(shared)
  180. expect(Agent.Info.empty(Agent.ID.make("test"))).toEqual(AgentV2.Info.empty(AgentV2.ID.make("test")))
  181. expect(Model.Info.empty(Provider.ID.make("test"), Model.ID.make("model"))).toEqual(
  182. ModelV2.Info.empty(ProviderV2.ID.make("test"), ModelV2.ID.make("model")),
  183. )
  184. expect(Provider.Info.empty(Provider.ID.make("test"))).toEqual(ProviderV2.Info.empty(ProviderV2.ID.make("test")))
  185. expect(Skill.Source.key(Skill.DirectorySource.make({ type: "directory", path: AbsolutePath.make("/tmp") }))).toBe(
  186. "directory:/tmp",
  187. )
  188. })
  189. test("shared record schemas construct and decode plain objects", () => {
  190. const made = Prompt.make({ text: "hello" })
  191. const decoded = Schema.decodeUnknownSync(Prompt)({ text: "hello" })
  192. const content = Schema.decodeUnknownSync(SessionMessage.AssistantText)({ type: "text", id: "part_1", text: "hi" })
  193. expect(Object.getPrototypeOf(made)).toBe(Object.prototype)
  194. expect(Object.getPrototypeOf(decoded)).toBe(Object.prototype)
  195. expect(Object.getPrototypeOf(content)).toBe(Object.prototype)
  196. expect(Prompt.ast.annotations?.identifier).toBe("Prompt")
  197. expect(SessionMessage.AssistantText.ast.annotations?.identifier).toBe("Session.Message.Assistant.Text")
  198. expect(Prompt.equivalence(Prompt.make({ text: "hello" }), decoded)).toBe(true)
  199. expect(Prompt.fromUserMessage({ text: "hello" })).toEqual(made)
  200. expect(Workspace.ID.ascending("")).toStartWith("wrk_")
  201. })