codex-sdk

    MoonBit SDK for embedding the Codex agent in workflows and applications

    openai
    codex
    sdk
    moonbit
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    3 months ago
    Downloads
    246

    #Codex SDK for MoonBit

    Embed the Codex agent in MoonBit workflows and applications.

    This package is a direct MoonBit port of the official @openai/codex-sdk. It wraps the codex CLI and exchanges JSONL events over stdin and stdout.

    The immutable upstream reference for this port is commit f201c30c52a35f819262865a53df94b6f4ea7a50. Every ported source process and test carries a comment linking to its corresponding file or line at that commit.

    #Workspace usage

    import {
    "totto2727/codex-sdk" @codex_sdk,
    }

    The native codex executable must be available on PATH, or supplied with codex_path_override.

    #Quickstart

    async fn main {
    let codex = @codex_sdk.Codex::Codex()
    let thread = codex.start_thread()
    let turn = thread.run(
    @codex_sdk.Input::Prompt("Diagnose the test failure and propose a fix"),
    )
    println(turn.final_response)
    }

    Call run repeatedly on the same Thread value to continue that conversation.

    #Streaming responses

    MoonBit uses an asynchronous callback in place of TypeScript's AsyncGenerator. The callback receives the same structured event variants and remains inside the task that owns the Codex subprocess.

    thread.run_streamed(
    @codex_sdk.Input::Prompt("Diagnose the test failure"),
    async event => {
    match event {
    ItemCompleted(completed) => println("\{completed.item}")
    TurnCompleted(completed) => println("\{completed.usage}")
    _ => ()
    }
    },
    )

    Cancelling the MoonBit task that runs run or run_streamed cancels the Codex subprocess, which is the native equivalent of passing an AbortSignal.

    #Structured output

    Pass a JSON object as the per-turn output schema. The SDK writes it to a temporary file and forwards the path through --output-schema.

    let schema = Json::object({
    "type": "object",
    "properties": {
    "summary": Json::object({ "type": "string" }),
    },
    "required": ["summary"],
    "additionalProperties": false,
    })
    let turn = thread.run(
    Prompt("Summarize repository status"),
    turn_options=@codex_sdk.TurnOptions::TurnOptions(output_schema=schema),
    )

    #TypeScript parity

    The public event, item, option, thread, and turn models follow the official TypeScript SDK. MoonBit paths use moonbitlang/x/path.Path, task cancellation replaces AbortSignal, and streaming uses an async callback because the pinned MoonBit async runtime does not expose an async-generator type. Node's optional-package binary lookup is replaced by PATH lookup because a MoonBit package has no Node module-resolution context.

    The source layout follows the upstream files using MoonBit snake-case filenames:

    Upstream TypeScriptMoonBit
    codex.tscodex.mbt
    codexOptions.tscodex_options.mbt
    events.tsevents.mbt
    exec.tsexec.mbt
    index.tsindex.mbt
    items.tsitems.mbt
    outputSchemaFile.tsoutput_schema_file.mbt
    thread.tsthread.mbt
    threadOptions.tsthread_options.mbt
    turnOptions.tsturn_options.mbt

    Files prefixed with moonbit_internal_ have no direct upstream module and exist only for MoonBit language or test-runtime requirements. Each such file documents the corresponding upstream process and the reason the independent implementation is required.

    #Tests

    Run the native package suite from the repository root:

    moon test --target native mbt/package/codex-sdk/src

    The 37 upstream abort, exec, run, and runStreamed cases are ported one-for-one against a native fake Codex executable that records arguments, environment variables, stdin, schemas, JSONL events, process exits, and cancellation. Another 26 moonbit_internal_ cases cover the explicit MoonBit item and event decoders, including every discriminated union branch, malformed payloads, unknown variants, and invalid JSONL. The Node-only optional-package layout cases are represented by documented MoonBit-runtime substitutions for an explicit executable override, PATH executable fallback, exact caller-provided PATH, and preservation of the Windows Path key.

    CodexConfigObject

    type CodexConfigObject = Map[String, CodexConfigValue]

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/codexOptions.ts#L3

    RunStreamedResult

    type RunStreamedResult = Unit

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/thread.ts#L24-L25

    StreamedTurn

    type StreamedTurn = Unit

    Async type difference: MoonBit has no AsyncGenerator, so streamed events are consumed by the callback and the result is Unit.

    CodexSdkError

    pub(all) suberror CodexSdkError {
    InvalidConfig(path~ : String, message~ : String)
    InvalidOutputSchema(message~ : String)
    InvalidEvent(message~ : String)
    TurnFailed(message~ : String)
    ExecFailed(code~ : Int, stderr~ : String)
    } derive(Eq,
    Debug
    )

    Type difference: named variants retain upstream failure boundaries while satisfying MoonBit's typed error system.

    AgentMessageItem

    pub(all) struct AgentMessageItem {
    id : String
    text : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L74-L80

    ApprovalMode

    pub(all) enum ApprovalMode {
    Never
    OnRequest
    OnFailure
    Untrusted
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    ApprovalMode::to_string

    fn ApprovalMode::to_string(self : ApprovalMode) -> String

    Type difference: the explicit conversion is required for the MoonBit enum.

    Codex

    pub struct Codex {
    // private fields
    }

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/codex.ts#L6-L13

    Codex::Codex

    fn Codex::Codex(options? : CodexOptions) -> Codex

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/codex.ts#L15-L19

    Codex::resume_thread

    fn Codex::resume_thread(self : Codex, id : String, options? : ThreadOptions) -> Thread

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/codex.ts#L29-L38

    Codex::start_thread

    fn Codex::start_thread(self : Codex, options? : ThreadOptions) -> Thread

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/codex.ts#L21-L27

    CodexConfigValue

    pub(all) enum CodexConfigValue {
    ConfigString(String)
    ConfigInt(Int)
    ConfigDouble(Double)
    ConfigBool(Bool)
    ConfigArray(Array[CodexConfigValue])
    ConfigObject(Map[String, CodexConfigValue])
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit requires an explicit recursive enum in place of the TypeScript union.

    CodexExec

    type CodexExec

    Upstream path type and bundled-directory resolution: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/exec.ts#L58-L65 and https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/exec.ts#L412-L430

    CodexOptions

    pub(all) struct CodexOptions {
    codex_path_override :
    Path
    ?
    base_url : String?
    api_key : String?
    config : Map[String, CodexConfigValue]?
    env : Map[String, String]?
    } derive(Eq)

    Type difference: filesystem strings are represented by Path.

    CodexOptions::CodexOptions

    fn CodexOptions::CodexOptions(codex_path_override? :
    Path
    , base_url? : String, api_key? : String, config? : Map[String, CodexConfigValue], env? : Map[String, String]) -> CodexOptions

    Type difference: MoonBit structs require a constructor to provide the upstream empty-object defaults.

    CommandExecutionItem

    pub(all) struct CommandExecutionItem {
    id : String
    command : String
    aggregated_output : String
    exit_code : Int?
    status : CommandExecutionStatus
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L8-L20

    CommandExecutionStatus

    pub(all) enum CommandExecutionStatus {
    InProgress
    Completed
    Failed
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    ErrorItem

    pub(all) struct ErrorItem {
    id : String
    message : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L96-L101

    FileChangeItem

    pub(all) struct FileChangeItem {
    id : String
    changes : ReadOnlyArray[FileUpdateChange]
    status : PatchApplyStatus
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L34-L42

    FileUpdateChange

    pub(all) struct FileUpdateChange {
    path :
    Path

    kind : PatchChangeKind
    } derive(Eq)

    Type difference: filesystem strings are represented by Path.

    Input

    pub(all) enum Input {
    Prompt(String)
    UserInputs(Array[UserInput])
    } derive(Eq)

    Type difference: MoonBit uses an enum instead of the TypeScript string-or-array union.

    ItemCompletedEvent

    pub(all) struct ItemCompletedEvent {
    item : ThreadItem
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L58-L62

    ItemStartedEvent

    pub(all) struct ItemStartedEvent {
    item : ThreadItem
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L46-L50

    ItemUpdatedEvent

    pub(all) struct ItemUpdatedEvent {
    item : ThreadItem
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L52-L56

    McpToolCallError

    pub(all) struct McpToolCallError {
    message : String
    } derive(Eq,
    Debug
    )

    Type difference: explicit structs replace inline TypeScript object types.

    McpToolCallItem

    pub(all) struct McpToolCallItem {
    id : String
    server : String
    tool : String
    arguments : Json
    result : McpToolCallResult?
    error : McpToolCallError?
    status : McpToolCallStatus
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L47-L72

    McpToolCallResult

    pub(all) struct McpToolCallResult {
    content : ReadOnlyArray[Json]
    meta : Json?
    structured_content : Json
    } derive(Eq,
    Debug
    )

    Type difference: explicit structs replace inline TypeScript object types.

    McpToolCallStatus

    pub(all) enum McpToolCallStatus {
    McpInProgress
    McpCompleted
    McpFailed
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    ModelReasoningEffort

    pub(all) enum ModelReasoningEffort {
    Minimal
    Low
    Medium
    High
    XHigh
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    ModelReasoningEffort::to_string

    fn ModelReasoningEffort::to_string(self : ModelReasoningEffort) -> String

    Type difference: the explicit conversion is required for the MoonBit enum.

    PatchApplyStatus

    pub(all) enum PatchApplyStatus {
    PatchCompleted
    PatchFailed
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    PatchChangeKind

    pub(all) enum PatchChangeKind {
    Add
    Delete
    Update
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    ReasoningItem

    pub(all) struct ReasoningItem {
    id : String
    text : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L82-L87

    SandboxMode

    pub(all) enum SandboxMode {
    ReadOnly
    WorkspaceWrite
    DangerFullAccess
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    SandboxMode::to_string

    fn SandboxMode::to_string(self : SandboxMode) -> String

    Type difference: the explicit conversion is required for the MoonBit enum.

    Thread

    pub struct Thread {
    // private fields
    }

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/thread.ts#L40-L45

    Thread::id

    fn Thread::id(self : Thread) -> String?

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/thread.ts#L47-L50

    Thread::run

    async fn Thread::run(self : Thread, input : Input, turn_options? : TurnOptions) -> Turn

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/thread.ts#L116-L140

    Thread::run_streamed

    async fn Thread::run_streamed(self : Thread, input : Input, on_event : async (ThreadEvent) -> Unit, turn_options? : TurnOptions) -> Unit

    Async type difference: the callback parameter replaces StreamedTurn.events because MoonBit has no AsyncGenerator.

    ThreadError

    pub(all) struct ThreadError {
    message : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L64-L67

    ThreadErrorEvent

    pub(all) struct ThreadErrorEvent {
    message : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L69-L73

    ThreadEvent

    pub(all) enum ThreadEvent {
    ThreadStarted(ThreadStartedEvent)
    TurnStarted(TurnStartedEvent)
    TurnCompleted(TurnCompletedEvent)
    TurnFailed(TurnFailedEvent)
    ItemStarted(ItemStartedEvent)
    ItemUpdated(ItemUpdatedEvent)
    ItemCompleted(ItemCompletedEvent)
    StreamError(ThreadErrorEvent)
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L75-L84

    ThreadItem

    pub(all) enum ThreadItem {
    AgentMessage(AgentMessageItem)
    Reasoning(ReasoningItem)
    CommandExecution(CommandExecutionItem)
    FileChange(FileChangeItem)
    McpToolCall(McpToolCallItem)
    WebSearch(WebSearchItem)
    TodoList(TodoListItem)
    Error(ErrorItem)
    } derive(Eq)

    Type difference: MoonBit uses an enum instead of a discriminated object union.

    ThreadOptions

    pub(all) struct ThreadOptions {
    model : String?
    sandbox_mode : SandboxMode?
    working_directory :
    Path
    ?
    skip_git_repo_check : Bool?
    model_reasoning_effort : ModelReasoningEffort?
    network_access_enabled : Bool?
    web_search_mode : WebSearchMode?
    web_search_enabled : Bool?
    approval_policy : ApprovalMode?
    additional_directories : Array[
    Path
    ]
    } derive(Eq)

    Type difference: filesystem strings are represented by Path.

    ThreadOptions::ThreadOptions

    fn ThreadOptions::ThreadOptions(model? : String, sandbox_mode? : SandboxMode, working_directory? :
    Path
    , skip_git_repo_check? : Bool, model_reasoning_effort? : ModelReasoningEffort, network_access_enabled? : Bool, web_search_mode? : WebSearchMode, web_search_enabled? : Bool, approval_policy? : ApprovalMode, additional_directories? : Array[
    Path
    ]) -> ThreadOptions

    Type difference: MoonBit structs require a constructor to provide the upstream empty-object defaults.

    ThreadStartedEvent

    pub(all) struct ThreadStartedEvent {
    thread_id : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L5-L10

    TodoItem

    pub(all) struct TodoItem {
    text : String
    completed : Bool
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L103-L107

    TodoListItem

    pub(all) struct TodoListItem {
    id : String
    items : ReadOnlyArray[TodoItem]
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L109-L117

    Turn

    #alias(RunResult)
    pub(all) struct Turn {
    items : ReadOnlyArray[ThreadItem]
    final_response : String
    usage : Usage?
    } derive(Eq)

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/thread.ts#L9-L14

    TurnCompletedEvent

    pub(all) struct TurnCompletedEvent {
    usage : Usage
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L34-L38

    TurnFailedEvent

    pub(all) struct TurnFailedEvent {
    error : ThreadError
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L40-L44

    TurnOptions

    pub(all) struct TurnOptions {
    output_schema : Json?
    } derive(Eq,
    Debug
    )

    Type difference: Json replaces TypeScript unknown, and cancelling the owning MoonBit task replaces AbortSignal.

    TurnOptions::TurnOptions

    fn TurnOptions::TurnOptions(output_schema? : Json) -> TurnOptions

    Type difference: MoonBit structs require a constructor to provide the upstream empty-object default.

    TurnStartedEvent

    pub(all) struct TurnStartedEvent {
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L12-L18

    Usage

    pub(all) struct Usage {
    input_tokens : Int
    cached_input_tokens : Int
    cache_write_input_tokens : Int
    output_tokens : Int
    reasoning_output_tokens : Int
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/events.ts#L20-L32

    UserInput

    pub(all) enum UserInput {
    Text(String)
    LocalImage(
    Path
    )
    } derive(Eq)

    Type difference: MoonBit uses an enum instead of a discriminated object union, and Path replaces filesystem strings.

    WebSearchItem

    pub(all) struct WebSearchItem {
    id : String
    query : String
    } derive(Eq,
    Debug
    )

    Upstream: https://github.com/openai/codex/blob/f201c30c52a35f819262865a53df94b6f4ea7a50/sdk/typescript/src/items.ts#L89-L94

    WebSearchMode

    pub(all) enum WebSearchMode {
    Disabled
    Cached
    Live
    } derive(Eq,
    Debug
    )

    Type difference: MoonBit uses an enum instead of a string-literal union.

    WebSearchMode::to_string

    fn WebSearchMode::to_string(self : WebSearchMode) -> String

    Type difference: the explicit conversion is required for the MoonBit enum.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io