Sign in

    genai

    MoonBit bindings for the Google GenAI (Gemini) JavaScript SDK

    genai
    gemini
    google
    ai
    llm
    sdk
    Download zip
    Author
    Version
    0.0.2
    License
    Apache-2.0
    Last updated
    7 months ago
    Downloads
    34

    #tiye/genai

    This project is AI-generated. The code and documentation were produced with GitHub Copilot and are maintained with AI assistance. PRs are welcome — please include a runnable example in src/cmd/main/main.mbt that exercises the new feature, so the AI agent can verify correctness by running it.

    MoonBit bindings for the Google Gemini Interactions API (JS backend, Node.js).

    Tracked SDK: @google/genai v1.42.0


    #Scope

    This package covers only the Interactions API (ai.interactions.*). The following surfaces are intentionally excluded and will not be added:

    Excluded surfaceReason
    generateContent / generateContentStreamLegacy stateless API
    Chat helper classWrapper around generateContent
    Live (WebSocket streaming)Different transport model
    Models, Files, Caches, OperationsOut of scope

    If you need those surfaces, use the JS SDK directly or a different binding package.


    #Implementation status

    #Client

    FeatureStatusNotes
    GoogleGenAI::new(api_key)✅ done
    GoogleGenAI::new_with_base_url(api_key, base_url)✅ doneFor reverse-proxy / internal network

    #interactions.* methods

    JS methodMoonBit methodStatusNotes
    interactions.create(params)ai.interactions_create(params)✅ donenull fields are stripped before sending
    interactions.create(stream)ai.interactions_create_stream(params, cb)✅ doneSSE callback-based streaming
    interactions.get(id)ai.interactions_get(id)✅ done
    interactions.cancel(id)ai.interactions_cancel(id)✅ done
    interactions.delete(id)ai.interactions_delete(id)✅ done
    interactions.list(...)—❌ not implementedNot yet in SDK stable surface
    Tool-result submission—❌ not implementedRequired for RequiresAction flow

    #CreateParams field coverage

    FieldTypeStatusNotes
    modelString✅ done
    inputInput✅ donePlain / Parts / Turns variants
    previous_interaction_idString?✅ done
    storeBool?✅ done
    system_instructionString?✅ done
    generation_configGenerationConfig?✅ donesee below
    toolsArray[Tool]?✅ doneFunction / GoogleSearch / CodeExecution / URLContext / ComputerUse / MCPServer / FileSearch
    response_modalitiesArray[String]?✅ done"text" / "image" / "audio"
    response_formatJson?✅ donepass a JSON Schema
    response_mime_typeString?✅ done
    backgroundBool?✅ doneFor async long-running interactions + cancel (untested)
    streamBool?✅ donePrefer interactions_create_stream instead

    #GenerationConfig field coverage

    FieldTypeStatus
    max_output_tokensInt?✅ done
    temperatureDouble?✅ done
    top_pDouble?✅ done
    seedInt?✅ done
    stop_sequencesArray[String]?✅ done
    thinking_levelString?✅ done
    thinking_summariesString?✅ done
    speech_configArray[SpeechConfig]?✅ done
    image_configImageConfig?✅ doneaspect_ratio, image_size (untested)
    tool_choiceJson?✅ doneFree-form JSON for mode etc. (untested)

    #Interaction (response) field coverage

    FieldTypeStatusNotes
    idString✅ done
    statusInteractionStatus✅ done
    modelString?✅ done
    outputsArray[Content]?✅ done
    previous_interaction_idString?✅ done
    roleString?✅ done
    usageUsage?✅ done
    createdString?✅ doneISO 8601
    updatedString?✅ doneISO 8601
    agentString?✅ doneAgent name (e.g. deep-research) (untested)

    #Content block coverage

    VariantEncodeDecodeNotes
    Text✅✅includes annotations
    Image✅✅base64 data or uri
    Audio✅✅base64 data or uri
    Document✅✅untested — PDF/doc input
    Video✅✅untested — video input
    Thought✅✅signature + summary
    FunctionCall✅✅
    FunctionResult✅✅
    CodeExecutionCall✅✅untested
    CodeExecutionResult✅✅untested
    GoogleSearchCall✅✅untested
    GoogleSearchResult✅✅untested
    URLContextCall✅✅untested
    URLContextResult✅✅untested
    MCPServerToolCall✅✅untested
    MCPServerToolResult✅✅untested
    FileSearchCall✅✅untested
    FileSearchResult✅✅untested

    #Streaming support

    FeatureStatusNotes
    interactions_create_stream(params, on_event)✅ doneCallback-based SSE streaming
    parse_event(json_str)✅ doneDecodes SSE JSON into InteractionEvent
    InteractionEvent enum✅ doneStart / StatusUpdate / ContentStart / Delta / Stop / Complete / Error / Unknown

    #Promise / async utilities

    FunctionStatus
    promise_and_then(p, f)✅ done
    promise_seq(p, f)✅ done
    promise_unit()✅ done
    run_async(p)✅ done
    get_env(key)✅ done
    Promise error handling in MoonBit❌ missing — JSPromise rejection is untyped; no catch binding yet

    #Tests

    AreaStatus
    Unit tests (genai_test.mbt)❌ empty
    White-box tests (genai_wbtest.mbt)❌ empty
    Encode round-trip tests❌ missing
    Decode round-trip tests❌ missing
    Snapshot tests❌ missing


    #Examples (src/cmd/main/main.mbt)

    ExampleCovered featuresStatus
    Single-turn textInput::Plain, basic create + parse✅ verified
    Stateful multi-turnprevious_interaction_id, store✅ verified
    System instructionsystem_instruction✅ verified
    Google Search toolTool::GoogleSearch, grounded responses✅ verified
    Structured JSON outputresponse_format / response_mime_type✅ verified
    Thinking (extended)thinking_level, Thought content parsing✅ verified
    Streaminginteractions_create_stream, parse_event✅ verified
    Input::Parts (multimodal)Image, Audio content blocks❌ missing
    Input::Turns (stateless history)client-managed conversation❌ missing
    Function callingTool::Function, RequiresAction flow❌ missing
    Background interactionbackground: true + interactions_cancel❌ missing
    interactions_getretrieve by id❌ missing
    interactions_deletedelete by id❌ missing


    #Known gaps (priority order for contributors)

    1. JSPromise rejection binding — add promise_catch FFI so MoonBit code can handle rejected promises in a typed way.
    2. Function-call round-trip example — RequiresAction → submit tool results → Completed.
    3. Tests — encode/decode round-trips for all content types; snapshot tests for encode_create_params.
    4. interactions.list — once the SDK stabilises a list endpoint.
    5. Runtime verification of untested features — ComputerUse, MCPServer, FileSearch tools; Document/Video content; ImageConfig; multi-speaker SpeechConfig.speaker; background interactions.


    #SDK version tracking

    When upgrading @google/genai, check the following in node_modules/@google/genai/dist/index.d.ts (or the yarn cache zip):

    • BaseCreateModelInteractionParams — new fields → add to CreateParams + encoder
    • GenerationConfig_2 — new fields → add to GenerationConfig + encoder
    • Interaction response type — new fields → add to struct + decoder
    • Content_2 union — new variants → add to Content enum + encode/decode

    Reference: /tmp/genai.d.ts was extracted from @google/genai@1.42.0.


    #Requirements

    • MoonBit build target: js (Node.js)
    • npm package: @google/genai ≥ 1.42.0

    yarn add @google/genai # Yarn PnP (used in this repo) # or npm install @google/genai


    #Quick start

    let ai = GoogleGenAI::new(get_env("GEMINI_API_KEY"))
    // or, via a reverse proxy:
    // let ai = GoogleGenAI::new_with_base_url(key, "https://your-proxy.example.com")

    run_async(promise_and_then(
    ai.interactions_create({
    model: "gemini-2.5-flash",
    input: Input::Plain("Why is the sky blue?"),
    previous_interaction_id: None,
    generation_config: None,
    tools: None,
    response_modalities: None,
    response_format: None,
    response_mime_type: None,
    system_instruction: None,
    store: None,
    background: None,
    stream: None,
    }),
    fn(json) {
    let ia = parse_interaction(json) catch { e => { println(e); return promise_unit() } }
    println(ia.id)
    promise_unit()
    },
    ))

    Build and run:

    moon build --target js GEMINI_API_KEY=<key> node --require ./.pnp.cjs \ ./_build/js/debug/build/cmd/main/main.js

    GenaiError

    pub(all) suberror GenaiError {
    ParseFailed(String)
    MissingField(String)
    InvalidFormat(String)
    }

    Error raised when parsing or decoding fails.
    impl Show for GenaiError

    Annotation

    pub(all) struct Annotation {
    source : String?
    start_index : Int?
    end_index : Int?
    }

    An annotation (citation) attached to a [TextContent] block.
    impl Show for Annotation

    AudioContent

    pub(all) struct AudioContent {
    data : String?
    mime_type : String?
    uri : String?
    }

    An audio content block (type: "audio").

    Provide either data (base-64) together with mime_type, or a uri.

    CodeExecutionCallContent

    pub(all) struct CodeExecutionCallContent {
    id : String
    arguments : Json
    }

    A code-execution call content block (type: "code_execution_call"). Untested — not yet verified at runtime.

    CodeExecutionResultContent

    pub(all) struct CodeExecutionResultContent {
    id : String
    output : String
    }

    A code-execution result content block (type: "code_execution_result"). Untested — not yet verified at runtime.

    ComputerUseTool

    pub(all) struct ComputerUseTool {
    environment : String?
    excluded_predefined_functions : Array[String]?
    }

    Configuration for the Computer-Use tool. Untested — not yet verified at runtime.

    Content

    pub(all) enum Content {
    Text(TextContent)
    Image(ImageContent)
    Audio(AudioContent)
    Document(DocumentContent)
    Video(VideoContent)
    Thought(ThoughtContent)
    FunctionCall(FunctionCallContent)
    FunctionResult(FunctionResultContent)
    CodeExecutionCall(CodeExecutionCallContent)
    CodeExecutionResult(CodeExecutionResultContent)
    GoogleSearchCall(GoogleSearchCallContent)
    GoogleSearchResult(GoogleSearchResultContent)
    URLContextCall(URLContextCallContent)
    URLContextResult(URLContextResultContent)
    MCPServerToolCall(MCPServerToolCallContent)
    MCPServerToolResult(MCPServerToolResultContent)
    FileSearchCall(FileSearchCallContent)
    FileSearchResult(FileSearchResultContent)
    }

    Discriminated union of all content-block variants produced by / sent to the model via the Interactions API.
    impl Show for Content

    CreateParams

    pub(all) struct CreateParams {
    model : String
    input : Input
    previous_interaction_id : String?
    generation_config : GenerationConfig?
    tools : Array[Tool]?
    response_modalities : Array[String]?
    response_format : Json?
    response_mime_type : String?
    system_instruction : String?
    store : Bool?
    background : Bool?
    stream : Bool?
    }

    Parameters for interactions.create.

    DocumentContent

    pub(all) struct DocumentContent {
    data : String?
    mime_type : String?
    uri : String?
    }

    A document content block (type: "document"). Untested — not yet verified at runtime.

    FileSearchCallContent

    pub(all) struct FileSearchCallContent {
    id : String
    arguments : Json
    }

    A file-search call content block (type: "file_search_call"). Untested — not yet verified at runtime.

    FileSearchResultContent

    pub(all) struct FileSearchResultContent {
    id : String
    result : Json
    }

    A file-search result content block (type: "file_search_result"). Untested — not yet verified at runtime.

    FileSearchTool

    pub(all) struct FileSearchTool {
    file_search_store_names : Array[String]?
    top_k : Int?
    metadata_filter : String?
    }

    Configuration for the File Search tool. Untested — not yet verified at runtime.

    FunctionCallContent

    pub(all) struct FunctionCallContent {
    id : String
    name : String
    arguments : Json
    }

    A function-call content block (type: "function_call").

    FunctionResultContent

    pub(all) struct FunctionResultContent {
    call_id : String
    result : Json
    name : String?
    is_error : Bool?
    }

    A function-result content block (type: "function_result").

    FunctionTool

    pub(all) struct FunctionTool {
    name : String
    description : String?
    parameters : Json?
    }

    A function-type tool declaration.

    GenerationConfig

    pub(all) struct GenerationConfig {
    max_output_tokens : Int?
    temperature : Double?
    top_p : Double?
    seed : Int?
    stop_sequences : Array[String]?
    thinking_level : String?
    thinking_summaries : String?
    speech_config : Array[SpeechConfig]?
    image_config : ImageConfig?
    tool_choice : Json?
    }

    Optional generation configuration for an interaction.

    GoogleGenAI

    pub(all) struct GoogleGenAI {
    // private fields
    }

    A GoogleGenAI client wrapping the @google/genai JS SDK.

    Only the Interactions API surface is exposed here. Example:

    let ai = GoogleGenAI::new("YOUR_GEMINI_API_KEY")

    let p = ai.interactions_create({
    model: "gemini-2.5-flash",
    input: Input::Plain("Hello!"),
    previous_interaction_id: None,
    generation_config: None,
    tools: None,
    response_modalities: None,
    response_format: None,
    response_mime_type: None,
    system_instruction: None,
    store: None,
    })
    // `p` is `JSPromise[String]` — resolves to a JSON-encoded Interaction

    GoogleGenAI::interactions_cancel

    fn GoogleGenAI::interactions_cancel(self : GoogleGenAI, id : String) -> JSPromise[String]

    Cancel a background interaction that is still running.

    Only applies to interactions started with background: true in [GenerationConfig]. Returns a JSPromise resolving to the updated [Interaction].

    GoogleGenAI::interactions_create

    fn GoogleGenAI::interactions_create(self : GoogleGenAI, params : CreateParams) -> JSPromise[String]

    Create a new interaction and return a JSPromise that resolves to a JSON-encoded [Interaction] string.

    Use [parse_interaction] to convert the resolved string to a typed [Interaction] value.

    Example (stateless, single turn)

    let p = ai.interactions_create({
    model: "gemini-2.5-flash",
    input: Input::Plain("Why is the sky blue?"),
    previous_interaction_id: None,
    generation_config: None,
    tools: None,
    response_modalities: None,
    response_format: None,
    response_mime_type: None,
    system_instruction: None,
    store: None,
    })

    Example (stateful multi-turn)

    let p2 = ai.interactions_create({
    ...,
    input: Input::Plain("What about sunsets?"),
    previous_interaction_id: Some(first_interaction_id),
    })

    GoogleGenAI::interactions_create_stream

    fn GoogleGenAI::interactions_create_stream(self : GoogleGenAI, params : CreateParams, on_event : (String) -> Unit) -> JSPromise[Unit]

    Create an interaction with streaming. Each SSE event is delivered to on_event as a JSON string; use [parse_event] to decode it.

    Untested — not yet verified at runtime.

    Example

    let p = ai.interactions_create_stream(
    {
    model: "gemini-2.5-flash",
    input: Input::Plain("Hello!"),
    ..CreateParams::default()
    },
    fn(event_json) {
    // handle each SSE event
    },
    )

    GoogleGenAI::interactions_delete

    fn GoogleGenAI::interactions_delete(self : GoogleGenAI, id : String) -> JSPromise[Unit]

    Delete an interaction by its id.

    GoogleGenAI::interactions_get

    fn GoogleGenAI::interactions_get(self : GoogleGenAI, id : String) -> JSPromise[String]

    Retrieve a previously created interaction by its id.

    Returns a JSPromise that resolves to a JSON-encoded [Interaction].

    GoogleGenAI::new

    fn GoogleGenAI::new(api_key : String) -> GoogleGenAI

    Create a new GoogleGenAI client.

    let ai = GoogleGenAI::new("YOUR_GEMINI_API_KEY")

    GoogleGenAI::new_with_base_url

    fn GoogleGenAI::new_with_base_url(api_key : String, base_url : String) -> GoogleGenAI

    Create a GoogleGenAI client that routes all requests through a custom base_url (e.g. an internal reverse-proxy).

    let ai = GoogleGenAI::new_with_base_url(
    "YOUR_GEMINI_API_KEY", "https://ja3.chenyong.life",
    )

    GoogleSearchCallContent

    pub(all) struct GoogleSearchCallContent {
    id : String
    arguments : Json
    }

    A Google Search call content block (type: "google_search_call"). Untested — not yet verified at runtime.

    GoogleSearchResultContent

    pub(all) struct GoogleSearchResultContent {
    id : String
    result : Json
    }

    A Google Search result content block (type: "google_search_result"). Untested — not yet verified at runtime.

    ImageConfig

    pub(all) struct ImageConfig {
    aspect_ratio : String?
    image_size : String?
    }

    Configuration for image generation. Untested — not yet verified at runtime.
    impl Show for ImageConfig

    ImageContent

    pub(all) struct ImageContent {
    data : String?
    mime_type : String?
    resolution : String?
    uri : String?
    }

    An image content block (type: "image").

    Provide either data (base-64) together with mime_type, or a uri.

    Input

    pub(all) enum Input {
    Plain(String)
    Parts(Array[Content])
    Turns(Array[Turn])
    }

    Input accepted by [GoogleGenAI::interactions_create].

    • Plain(text) — a single text string.
    • Parts(contents) — one or more typed content blocks.
    • Turns(turns) — a full conversation history (for stateless multi-turn).
    impl Show for Input

    Interaction

    pub(all) struct Interaction {
    id : String
    status : InteractionStatus
    model : String?
    outputs : Array[Content]?
    previous_interaction_id : String?
    role : String?
    usage : Usage?
    created : String?
    updated : String?
    agent : String?
    }

    The Interaction resource returned by the API.
    impl Show for Interaction

    InteractionEvent

    pub(all) enum InteractionEvent {
    InteractionStart(Json)
    StatusUpdate(String)
    ContentStart(Int, String)
    ContentDelta(Int, Json)
    ContentStop(Int)
    InteractionComplete(Json)
    Error(Json)
    Unknown(String, Json)
    }

    SSE event types emitted during a streamed interaction. Untested — not yet verified at runtime.

    InteractionStatus

    pub(all) enum InteractionStatus {
    InProgress
    RequiresAction
    Completed
    Failed
    Cancelled
    Incomplete
    }

    Possible states of an [Interaction] returned by the API.

    JSGoogleGenAI

    #external
    pub(all) type JSGoogleGenAI

    Opaque handle to the native GoogleGenAI JS object.

    JSPromise

    #external
    pub(all) type JSPromise[A]

    Opaque handle to a JavaScript Promise<A>.

    The type parameter A is phantom — it tracks what type the promise resolves to in MoonBit's type system, but carries no runtime information.

    MCPServerTool

    pub(all) struct MCPServerTool {
    url : String?
    name : String?
    headers : Json?
    allowed_tools : Json?
    }

    Configuration for a remote MCP server tool. Untested — not yet verified at runtime.

    MCPServerToolCallContent

    pub(all) struct MCPServerToolCallContent {
    id : String
    name : String
    arguments : Json
    }

    An MCP server tool call content block (type: "mcp_server_tool_call"). Untested — not yet verified at runtime.

    MCPServerToolResultContent

    pub(all) struct MCPServerToolResultContent {
    id : String
    result : Json
    }

    An MCP server tool result content block (type: "mcp_server_tool_result"). Untested — not yet verified at runtime.

    SpeechConfig

    pub(all) struct SpeechConfig {
    voice : String?
    language : String?
    speaker : String?
    }

    A voice+language pair for speech output.

    TextContent

    pub(all) struct TextContent {
    text : String?
    annotations : Array[Annotation]?
    }

    A text content block (type: "text").
    impl Show for TextContent

    ThoughtContent

    pub(all) struct ThoughtContent {
    signature : String?
    summary : Json?
    }

    A thought content block (type: "thought"). Untested — not yet verified at runtime.

    Tool

    pub(all) enum Tool {
    Function(FunctionTool)
    GoogleSearch
    CodeExecution
    URLContext
    ComputerUse(ComputerUseTool)
    MCPServer(MCPServerTool)
    FileSearch(FileSearchTool)
    }

    Built-in tool types that the model can use.
    impl Show for Tool

    Turn

    pub(all) struct Turn {
    content : TurnContent?
    role : String?
    }

    A single conversation turn (user or model).
    impl Show for Turn

    TurnContent

    pub(all) enum TurnContent {
    Plain(String)
    Parts(Array[Content])
    }

    Content within a [Turn] — either a plain string or structured blocks.
    impl Show for TurnContent

    URLContextCallContent

    pub(all) struct URLContextCallContent {
    id : String
    arguments : Json
    }

    A URL-context call content block (type: "url_context_call"). Untested — not yet verified at runtime.

    URLContextResultContent

    pub(all) struct URLContextResultContent {
    id : String
    result : Json
    }

    A URL-context result content block (type: "url_context_result"). Untested — not yet verified at runtime.

    Usage

    pub(all) struct Usage {
    total_input_tokens : Int?
    total_output_tokens : Int?
    total_cached_tokens : Int?
    }

    Token-usage counters attached to a completed [Interaction].
    impl Show for Usage

    VideoContent

    pub(all) struct VideoContent {
    data : String?
    mime_type : String?
    resolution : String?
    uri : String?
    }

    A video content block (type: "video"). Untested — not yet verified at runtime.

    get_env

    fn get_env(key : String) -> String

    Read a Node.js environment variable. Returns "" if not set.

    parse_event

    fn parse_event(json_str : String) -> InteractionEvent raise GenaiError

    Parse a JSON-encoded SSE event string into an [InteractionEvent]. Untested — not yet verified at runtime.

    parse_interaction

    fn parse_interaction(json_str : String) -> Interaction raise GenaiError

    Parse a JSON string (as returned by the raw FFI) into an [Interaction]. Returns an error string if parsing fails.

    promise_and_then

    fn promise_and_then(p : JSPromise[String], f : (String) -> JSPromise[Unit]) -> JSPromise[Unit]

    Chain a JSPromise[String] — calls f with the resolved string and returns a new JSPromise[Unit]. Mirrors .then() in JavaScript.

    promise_seq

    fn promise_seq(p : JSPromise[Unit], f : () -> JSPromise[Unit]) -> JSPromise[Unit]

    Sequence two JSPromise[Unit] values — run f after p resolves.

    promise_unit

    fn promise_unit() -> JSPromise[Unit]

    A JSPromise that is already resolved to Unit.

    run_async

    fn run_async(p : JSPromise[Unit]) -> Unit

    Run a JSPromise[Unit] as the top-level async operation. Logs errors to stderr and exits with code 1 on rejection.

    Source Files