Skip to main content
Moss.Inference is the Elixir client for Moss Inference. Its Responses.create/3 takes OpenAI’s Responses body as a map and searches your indexes. It answers with OpenAI’s field names as string keys.

Install

Then run mix deps.get. Moss.Inference needs moss 1.11.0 or later. For the rest of the SDK setup, see Install.

Create a client

Copy the project id and key from the Moss portal. Build one client and reuse it for every call, from any process. It is plain data with nothing to close. The examples below use this client and the Responses alias.

Get a response

params is OpenAI’s Responses body, with atom or string keys. create/3 returns {:ok, response}. response["output_text"] joins the text of the response’s messages. response["output"] holds its items. response["request_id"] is the response’s X-Moss-Request-Id. A stream has the same stream.request_id. Include it when you report a problem. Both are nil when the response has none. Moss stores no response, so input holds the whole conversation. Pass a string, or a list of items such as %{role: "user", content: "Hi"} and the "output" items of earlier responses. See Conversations.

Stream a response

With stream: true, create/3 returns {:ok, stream} once the response starts. Each event is a map with OpenAI’s "type", such as response.output_text.delta, and the fields of that type. The stream ends after one of two events:
  • response.completed, when the response is done.
  • response.incomplete, when max_output_tokens or a content filter cut the response short.
The "response" map of that last event holds "output" and "usage". It has no "output_text" or "request_id". Join the text from the response.output_text.delta events or from "output". Read the request id from stream.request_id. Read the stream once, in the process that called create/3. To stop early, halt the stream, for example with Enum.take/2. You can also call Moss.Inference.ResponseStream.close(stream) from any process. Either one closes the connection, which stops the model. Streaming lists every event.

Ground it in your indexes

Moss searches the faq index and adds what it finds to the prompt. The Quickstart creates that index. :indexes goes in opts, the third argument, not in params. Code written for OpenAI keeps its body and adds :indexes. Without :indexes, Moss does not search and the model answers from input alone. You can name at most 32. retrieve: false skips the search on a call that names indexes. Ground answers in your indexes covers the options and the cost.

Use a vendor model

Name a model from OpenAI, Anthropic or Google in model. The search of your indexes works the same for every model. Models lists them all.

On the Moss key

Without your own key, a listed vendor model runs on the Moss key and bills your credits. Routes shows who bills each call. A listed model that is not served right now returns {:error, error} with code "model_not_enabled". Send moss/fastlane-1 or use your own key.

With your own key

Pass your OpenAI, Anthropic or Google key to a client as :api_key:
The key goes in the X-Moss-Provider-Key header, never in the body. To use a key for one call only, pass :api_key in the opts of create/3. response["model"] is the name you sent. Bring your own key covers model names and billing.

Tool calls

Pass OpenAI function tools in tools, inside params. A function tool is flat, as in OpenAI’s Responses API. Your code runs the tools. Each call the model makes comes as a "function_call" item of "output". Put the "output" items back into input as they are. Add one "function_call_output" item per call, and call again until the response has no calls:
lookup_order/1 stands for your own code. It gets the arguments as a JSON string and returns the result as a string. Each item goes back unchanged. It keeps every field the model sent, such as Gemini’s extra_content. Tool calling covers tool_choice, parallel_tool_calls and structured output.

MCP servers

A Moss.Inference.McpServer struct in tools names an MCP server. Moss Inference runs its tools for the model during the response. Your code sends no "function_call_output" items for them.
Each call comes as an "mcp_call" item. It arrives in response.output_item.added when it starts, and in response.output_item.done when it ends. The same items are in the response’s "output". Send the items back in input with the rest of "output". The model then sees the earlier tool results. MCP failures give a Moss.Inference.Error with status, type, code and retry_after. A call that fails after a tool ran has code "failed_after_tool_call". The tool may already have changed data, so Moss Inference does not retry the call. Never replay a request that failed with failed_after_tool_call. MCP servers covers the server fields and every MCP error.

Errors

A failed call gives a Moss.Inference.Error. new/3 raises it, and create/3 returns it as {:error, error}. Once a stream has started, reading it raises the error. A response.failed event raises it too. A field the failure lacks is nil. The SDK sets these types itself, with status nil: Every other error carries what Moss Inference sent. Errors and limits lists every code. For a 429, see Limits.

Options

Moss.Inference.new(project_id, project_key, opts): Moss.Inference.Responses.create(client, params, opts) takes OpenAI’s Responses body in params. The Moss options go in opts: