# elelem-openai

> Connects elelem to OpenAI models through the Chat Completions API, with streaming and tool calls.

Maturity: alpha. Install: `gem install elelem-openai`. Source: https://src.mokhan.ca/elelem/openai/


`elelem-openai` connects elelem to OpenAI. It registers the `openai`
provider, which calls the Chat Completions API at
`https://api.openai.com/v1/chat/completions`. Use it when you want a hosted
OpenAI model.

## Install

```bash
gem install elelem elelem-builtins elelem-openai
```

`elelem-builtins` is optional but gives the agent its default tools.
Requires Ruby 4.0.

## Configure

```bash
export OPENAI_API_KEY=sk-...
```

`--model` overrides `OPENAI_MODEL`. The base URL is fixed to
`https://api.openai.com/v1`; there is no environment variable to point it
at another OpenAI-compatible server.

## Use

```bash
elelem -p openai
elelem -p openai --model gpt-4.1
git diff | elelem ask -p openai "explain this diff"
```

The gem also installs `elelem-openai`, which is `elelem` with `openai` as
the default provider:

```bash
elelem-openai chat
```

Unlike `elelem`, `elelem-openai` does not load `elelem-builtins`, so the
agent has no tools unless a plugin file in `~/.agents/plugins` adds them.

## How it works

Each turn is one `POST` to `chat/completions` with `stream: true`,
`tool_choice: "auto"`, and elelem's messages and tools as they are. Tool
definitions are already in the OpenAI `function` format, so the provider
does no conversion. Requests use `Net::HTTP` with a 3600-second
read timeout and a 10-second open timeout.

The response is read as server-sent events. Each `delta.content` becomes
part of the reply. Tool call fragments are collected by index, and their
`arguments` strings are joined and parsed as JSON when the stream ends.
elelem prints the reply once the turn is done.

## Limitations

- Earlier tool calls are sent back in elelem's internal shape
  (`id`, `name`, `arguments`), not OpenAI's `function` wrapper with string
  arguments. The API may reject the follow-up request after a tool call;
  check this before relying on multi-step tool use.
- No thinking or reasoning output. Only `delta.content` and
  `delta.tool_calls` are read.
- `tools` and `tool_choice` are sent on every request, even when the tool
  list is empty.
- If a tool call's arguments are not valid JSON, the turn fails with a
  parse error instead of guessing.
- No setting for the base URL, temperature, or other sampling parameters.
- Any non-2xx response raises `HTTP CODE: BODY`. There are no retries.

## Development

```bash
git clone https://git.mokhan.ca/elelem/openai.git
cd openai
bin/setup
bin/test
bin/lint
```

The spec injects a fake HTTP adapter, so the tests make no network calls.


## Environment

| Variable | Default | Description |
|---|---|---|
| `OPENAI_API_KEY` | none | Required. Sent as a bearer token. |
| `OPENAI_MODEL` | `gpt-4o` | Model to use when --model is not given. |

Canonical: https://elelem.sh/plugins/openai/

