import { expect, test } from "bun:test" import { Schema } from "effect" import { AgentV2 } from "@opencode-ai/core/agent" import { ModelV2 } from "@opencode-ai/core/model" import { SessionV2 } from "@opencode-ai/core/session" import { Agent } from "@opencode-ai/schema/agent" import { Location } from "@opencode-ai/schema/location" import { Model } from "@opencode-ai/schema/model" import { AgentAttachment, FileAttachment, Prompt, Source } from "@opencode-ai/schema/prompt" import { Provider } from "@opencode-ai/schema/provider" import { Project } from "@opencode-ai/schema/project" import { Session } from "@opencode-ai/schema/session" import { SessionInput } from "@opencode-ai/schema/session-input" import { SessionMessage } from "@opencode-ai/schema/session-message" import { Workspace } from "@opencode-ai/schema/workspace" import { Command } from "@opencode-ai/schema/command" import { Connection } from "@opencode-ai/schema/connection" import { Credential } from "@opencode-ai/schema/credential" import { FileSystem } from "@opencode-ai/schema/filesystem" import { Integration } from "@opencode-ai/schema/integration" import { LLM } from "@opencode-ai/schema/llm" import { ModelRequest } from "@opencode-ai/schema/model-request" import { Permission } from "@opencode-ai/schema/permission" import { Reference } from "@opencode-ai/schema/reference" import { Skill } from "@opencode-ai/schema/skill" import { AbsolutePath, DateTimeUtcFromMillis } from "@opencode-ai/schema/schema" import { ProviderV2 } from "@opencode-ai/core/provider" test("Core reuses the canonical shared schemas", async () => { const [ coreCommand, coreConnection, coreCredential, coreFileSystem, coreIntegration, coreLocation, coreLLM, coreModelRequest, corePermission, coreProject, coreReference, coreSessionInput, coreSessionMessage, corePrompt, coreSkill, coreV2Schema, coreWorkspace, ] = await Promise.all([ import("@opencode-ai/core/command"), import("@opencode-ai/core/integration/connection"), import("@opencode-ai/core/credential"), import("@opencode-ai/core/filesystem"), import("@opencode-ai/core/integration"), import("@opencode-ai/core/location"), import("@opencode-ai/llm"), import("@opencode-ai/core/model-request"), import("@opencode-ai/core/permission"), import("@opencode-ai/core/project/schema"), import("@opencode-ai/core/reference"), import("@opencode-ai/core/session/input"), import("@opencode-ai/core/session/message"), import("@opencode-ai/core/session/prompt"), import("@opencode-ai/core/skill"), import("@opencode-ai/core/v2-schema"), import("@opencode-ai/core/workspace"), ]) const schemas = [ [AgentV2.ID, Agent.ID], [AgentV2.Color, Agent.Color], [AgentV2.Info, Agent.Info], [coreCommand.Info, Command.Info], [coreConnection.CredentialInfo, Connection.CredentialInfo], [coreConnection.EnvInfo, Connection.EnvInfo], [coreConnection.Info, Connection.Info], [coreCredential.ID, Credential.ID], [coreCredential.OAuth, Credential.OAuth], [coreCredential.Key, Credential.Key], [coreCredential.Value, Credential.Value], [coreFileSystem.Entry, FileSystem.Entry], [coreFileSystem.Submatch, FileSystem.Submatch], [coreFileSystem.Match, FileSystem.Match], [coreIntegration.ID, Integration.ID], [coreIntegration.MethodID, Integration.MethodID], [coreIntegration.When, Integration.When], [coreIntegration.TextPrompt, Integration.TextPrompt], [coreIntegration.SelectPrompt, Integration.SelectPrompt], [coreIntegration.Prompt, Integration.Prompt], [coreIntegration.OAuthMethod, Integration.OAuthMethod], [coreIntegration.KeyMethod, Integration.KeyMethod], [coreIntegration.EnvMethod, Integration.EnvMethod], [coreIntegration.Method, Integration.Method], [coreIntegration.Inputs, Integration.Inputs], [coreIntegration.Ref, Integration.Ref], [coreLocation.Ref, Location.Ref], [coreLLM.ProviderMetadata, LLM.ProviderMetadata], [coreLLM.ToolTextContent, LLM.ToolTextContent], [coreLLM.ToolFileContent, LLM.ToolFileContent], [coreLLM.ToolContent, LLM.ToolContent], [ModelV2.ID, Model.ID], [ModelV2.VariantID, Model.VariantID], [ModelV2.Ref, Model.Ref], [ModelV2.Family, Model.Family], [ModelV2.Capabilities, Model.Capabilities], [ModelV2.Cost, Model.Cost], [ModelV2.Api, Model.Api], [ModelV2.Info, Model.Info], [ProviderV2.ID, Provider.ID], [ProviderV2.AISDK, Provider.AISDK], [ProviderV2.Native, Provider.Native], [ProviderV2.Api, Provider.Api], [ProviderV2.Request, Provider.Request], [ProviderV2.Info, Provider.Info], [coreModelRequest.Generation, ModelRequest.Generation], [coreModelRequest.Request, ModelRequest.Request], [corePermission.Effect, Permission.Effect], [corePermission.Rule, Permission.Rule], [corePermission.Ruleset, Permission.Ruleset], [coreProject.ID, Project.ID], [coreReference.LocalSource, Reference.LocalSource], [coreReference.GitSource, Reference.GitSource], [coreReference.Source, Reference.Source], [SessionV2.ID, Session.ID], [SessionV2.Info, Session.Info], [SessionV2.ListAnchor, Session.ListAnchor], [coreSessionInput.Delivery, SessionInput.Delivery], [coreSessionInput.Admitted, SessionInput.Admitted], [coreSessionMessage.ID, SessionMessage.ID], [coreSessionMessage.UnknownError, SessionMessage.UnknownError], [coreSessionMessage.AgentSwitched, SessionMessage.AgentSwitched], [coreSessionMessage.ModelSwitched, SessionMessage.ModelSwitched], [coreSessionMessage.User, SessionMessage.User], [coreSessionMessage.Synthetic, SessionMessage.Synthetic], [coreSessionMessage.System, SessionMessage.System], [coreSessionMessage.Shell, SessionMessage.Shell], [coreSessionMessage.ToolStatePending, SessionMessage.ToolStatePending], [coreSessionMessage.ToolStateRunning, SessionMessage.ToolStateRunning], [coreSessionMessage.ToolStateCompleted, SessionMessage.ToolStateCompleted], [coreSessionMessage.ToolStateError, SessionMessage.ToolStateError], [coreSessionMessage.ToolState, SessionMessage.ToolState], [coreSessionMessage.AssistantTool, SessionMessage.AssistantTool], [coreSessionMessage.AssistantText, SessionMessage.AssistantText], [coreSessionMessage.AssistantReasoning, SessionMessage.AssistantReasoning], [coreSessionMessage.AssistantContent, SessionMessage.AssistantContent], [coreSessionMessage.Assistant, SessionMessage.Assistant], [coreSessionMessage.Compaction, SessionMessage.Compaction], [coreSessionMessage.Message, SessionMessage.Message], [corePrompt.Source, Source], [corePrompt.FileAttachment, FileAttachment], [corePrompt.AgentAttachment, AgentAttachment], [corePrompt.Prompt, Prompt], [coreSkill.DirectorySource, Skill.DirectorySource], [coreSkill.UrlSource, Skill.UrlSource], [coreSkill.EmbeddedSource, Skill.EmbeddedSource], [coreSkill.Source, Skill.Source], [coreSkill.Info, Skill.Info], [coreV2Schema.DateTimeUtcFromMillis, DateTimeUtcFromMillis], [coreWorkspace.ID, Workspace.ID], ] for (const [core, shared] of schemas) expect(core).toBe(shared) expect(Agent.Info.empty(Agent.ID.make("test"))).toEqual(AgentV2.Info.empty(AgentV2.ID.make("test"))) expect(Model.Info.empty(Provider.ID.make("test"), Model.ID.make("model"))).toEqual( ModelV2.Info.empty(ProviderV2.ID.make("test"), ModelV2.ID.make("model")), ) expect(Provider.Info.empty(Provider.ID.make("test"))).toEqual(ProviderV2.Info.empty(ProviderV2.ID.make("test"))) expect(Skill.Source.key(Skill.DirectorySource.make({ type: "directory", path: AbsolutePath.make("/tmp") }))).toBe( "directory:/tmp", ) }) test("shared record schemas construct and decode plain objects", () => { const made = Prompt.make({ text: "hello" }) const decoded = Schema.decodeUnknownSync(Prompt)({ text: "hello" }) const content = Schema.decodeUnknownSync(SessionMessage.AssistantText)({ type: "text", id: "part_1", text: "hi" }) expect(Object.getPrototypeOf(made)).toBe(Object.prototype) expect(Object.getPrototypeOf(decoded)).toBe(Object.prototype) expect(Object.getPrototypeOf(content)).toBe(Object.prototype) expect(Prompt.ast.annotations?.identifier).toBe("Prompt") expect(SessionMessage.AssistantText.ast.annotations?.identifier).toBe("Session.Message.Assistant.Text") expect(Prompt.equivalence(Prompt.make({ text: "hello" }), decoded)).toBe(true) expect(Prompt.fromUserMessage({ text: "hello" })).toEqual(made) expect(Workspace.ID.ascending("")).toStartWith("wrk_") })