docs.bend source
docs.bend on the hub · documented module
# An unofficial OpenAI SDK for Bend, with typed requests, streaming, and tool calling.import Base# # openai-bend## **An unofficial OpenAI SDK for Bend, with typed requests, streaming, and tool calling.**## Write your application in Bend. Use OpenAI's official TypeScript SDK for the network connection. A small, authenticated companion process connects the two over localhost.## [Examples](https://github.com/gouveags/openai-bend/tree/main/examples) · [Source](https://github.com/gouveags/openai-bend) · [Report an issue](https://github.com/gouveags/openai-bend/issues) · [Anthropic companion project](https://github.com/gouveags/anthropic-bend)## > Experimental companion v0.1.1 / Bend library v0.1.0. This is a community project, not an official OpenAI or Bend project. It implements the foreground Responses API. It is not a feature-complete replacement for the Python or TypeScript SDKs.## ## Install from Bend Hub## [**bend-openai-sdk@0.1.0.1**](https://hub.bend-lang.com/n/bend-openai-sdk) · [Packaged documentation](https://github.com/gouveags/openai-bend/blob/main/docs.bend) · [Source and examples](https://github.com/gouveags/openai-bend)## Use **Bend 2.0.34 or newer** for named imports. Bend fetches the exact release, resolves it to an immutable content hash, and verifies the downloaded files. There is no separate install command for the Bend modules.## ```bend# import bend-openai-sdk@0.1.0.1/openai.bend as OpenAI# import bend-openai-sdk@0.1.0.1/json.bend as Json# ```## Install and start the localhost companion below as well: the Hub package contains the Bend modules, documentation and MIT license, not the Bun companion or its dependencies. Provider API keys stay in the companion process.## Release `0.1.0.1` fixes the JSON parser constructor collision with Bend 2.0.28+ and updates the example CLIs for Bend 2.0.34. The SDK API and bridge protocol are unchanged. Existing imports of the [previous hash](https://hub.bend-lang.com/0x7d1714d98ca88352be07e0302e547a19) remain available, but require the older compiler they were published with. Use `0.1.0.1` on current Bend. Published versions are immutable; future updates use a new version.## ## What you get## | Capability | v0.1.0 |# | --------------------------------------------------- | ------------------------------------------------------------------ |# | Create responses | Typed request builder plus arbitrary JSON options |# | Streaming | Every semantic event, including unknown future events |# | Response helpers | Text, function calls, usage and complete raw JSON |# | Structured outputs | JSON Schema request helper; application-controlled decoding |# | Function calling | Tool definitions, typed call extraction and function-output helper |# | Images and files | References in request JSON; no upload helper |# | Cancellation | Close a stream, or cancel by ID over a separate connection |# | Error metadata | API status, request ID and Retry-After |# | Native / JavaScript | Same Bend API and companion protocol |# | Uploads, pagination, background responses, Realtime | Not implemented |## Function execution is deliberately explicit: the library never executes a command or function just because the model named it. Refusals, failed/incomplete responses, annotations and provider-specific details remain available in the raw response or event.## ## Requirements## - Linux or macOS. The tested platform is Linux x86_64; macOS is not yet validated.# - [Bend 2.0.34+](https://github.com/bendlang/bend), [Bun](https://bun.sh/), and Git.# - Clang 14+ and Make for native builds.# - An OpenAI API key and access to your selected model for real inference.## The companion is a separate local process. **Installing the Bend Hub package does not install Bun, the companion, or its dependencies.**## ## Install the companion## ```sh# git clone https://github.com/gouveags/openai-bend.git# cd openai-bend# git checkout main# bun install --frozen-lockfile# ```## Load your API key into `OPENAI_API_KEY` using your secret manager or shell's private input facility. Do not put it in source code, commit an environment file, or paste it into a command that will be saved in shell history.## Generate a separate local bridge token:## ```sh# export OPENAI_BEND_TOKEN="$(openssl rand -hex 32)"# export OPENAI_BEND_PORT=42101# export OPENAI_MODEL='your-available-model-id'# bun run bridge# ```## Expected startup message:## ```text# openai-bend 0.1.1 listening on 127.0.0.1:42101 (protocol 1)# ```## Your Bend process needs `OPENAI_BEND_TOKEN`, `OPENAI_BEND_PORT` and your model selection. **It does not need the OpenAI API key.** When using separate terminals, share the same bridge token through your local secret-management mechanism. The bridge does not print credentials.## ## Run an example## From another terminal with the bridge token available:## ```sh# make build/request.js# bun build/request.js example-1 once \# "{\"model\":\"$OPENAI_MODEL\",\"input\":\"Say hello.\"}"## # Stream every event:# bun build/request.js example-2 stream \# "{\"model\":\"$OPENAI_MODEL\",\"input\":\"Explain interaction nets briefly.\"}"# ```## The command prints the result or each semantic event, then `finished`. Provider, protocol and transport failures exit nonzero. `finished` means the transport ended correctly: inspect the response status or terminal event to distinguish completed, failed and incomplete model output.## For native execution:## ```sh# make build/request# ./build/request example-3 once \# "{\"model\":\"$OPENAI_MODEL\",\"input\":\"Say hello.\"}"# ```## The Makefile emits C using Bend and compiles with Clang `-O1` by default to keep development builds manageable. Override `CFLAGS` for an optimized build after validating it on your machine. This project makes no performance claim.## ## Use the Bend library## Within this checkout, a minimal typed request looks like this:## ```bend# import Base# import ./openai.bend as OpenAI## def start(token: String, model: String) -># IO(Result<&1, &1, OpenAI.Error, OpenAI.Stream>):# OpenAI.create(# OpenAI.Client{42101, token},# "my-unique-request-id",# OpenAI.text_request(model, "Say hello."))# ```## `create` and `stream` return an owned stream handle. Call `OpenAI.next` until it returns:## - `Event{stream, kind, data, request_id}` — process the event and use the returned stream for the next read.# - `Finished{}` — the connection has closed cleanly.# - `Failed{error}` — the connection has closed with a transport, API or protocol error.## For nonstreaming calls, the event kind is `result`. Streaming calls first expose `metadata`, followed by provider event names such as `response.output_text.delta`. All events include their original JSON payload. `OpenAI.response(data)` extracts a typed response from a `result` payload; for a terminal streaming event, pass its nested `response` object.## Call `OpenAI.close(stream)` if you stop consuming early. To cancel a blocked request from another Bend computation, use `OpenAI.cancel(client, request_id)`. Cancellation requests an upstream abort; it cannot guarantee that remote processing or billing has not already happened.## See [the complete reader](https://github.com/gouveags/openai-bend/blob/main/examples/request.bend), [hello](https://github.com/gouveags/openai-bend/blob/main/examples/hello.bend), [structured outputs](https://github.com/gouveags/openai-bend/blob/main/examples/structured.bend), [tools](https://github.com/gouveags/openai-bend/blob/main/examples/tools.bend), and [cancellation](https://github.com/gouveags/openai-bend/blob/main/examples/cancel.bend). All examples read `OPENAI_BEND_PORT` and `OPENAI_BEND_TOKEN`.## ## Structured outputs and tools## `OpenAI.Request{model, input, options}` accepts a JSON input and additional fields. Use `Json.Text` for a simple prompt, or a `Json.Array` for messages, image/file references and tool results.## ```bend# # Add these fields to Request.options:# Json.Field{"text", OpenAI.json_schema("person", schema)}# Json.Field{"tools", Json.Array{[# OpenAI.function_tool("weather", "Look up weather", schema)# ]}}# ```## The schema must meet [OpenAI's supported JSON Schema rules](https://developers.openai.com/api/docs/guides/structured-outputs). Structured output is not automatically converted into an arbitrary Bend datatype: inspect the response status/refusal, parse its text with `Json.read`, then validate your application's fields.## For tools, inspect `Response.calls`. Each `FunctionCall` contains `id`, `call_id`, `name`, JSON-encoded `arguments`, and the complete raw item. Validate the name and arguments against an application-owned allowlist before executing anything. Return a result with `OpenAI.function_output(call_id, output)`.## For a stored-response continuation, submit that item in the next input with `previous_response_id` set to the response ID. Repeat instructions and tool definitions as needed; instructions are not automatically inherited. For stateless/manual replay, follow the [official continuation guidance](https://developers.openai.com/api/docs/guides/function-calling), including reasoning items. There is no automatic tool loop in this release.## ## JSON and forward compatibility## `json.bend` supplies `Null`, `Boolean`, `Number`, `Text`, `Array` and `Object`, with `Field` entries for objects. `Json.get` returns `None` for an absent property and `Some{Null{}}` for explicit null. Omit an option by leaving it out of the field list.## Numbers are stored as decimal strings and do not pass through Bend's `F32`. The companion uses JavaScript JSON and the official SDK, so its normal IEEE-754 numeric limitations still apply. Do not send integers beyond JavaScript's safe range expecting lossless end-to-end arithmetic.## Use valid JSON number strings in `Json.Number`. Unknown response fields and event types are preserved. `OpenAI.open_raw` accepts an arbitrary JSON request object for newly added fields, but supports only the allowlisted Responses create operation. Request options cannot change the companion's URL, credentials or SDK method.## ## Architecture and security## ```text# Bend application ── authenticated localhost TCP ── companion# │# official openai SDK# │ HTTPS# OpenAI API# ```## - The companion binds only `127.0.0.1`. It is not a public server and must not be exposed through a proxy or tunnel.# - A token of at least 32 characters is required. Use a randomly generated token, not a memorable password. API credentials remain in the companion process.# - One request per connection; cancellation uses a separate connection and request ID. Use unique IDs for simultaneous requests.# - JSON decoding is limited to 64 nesting levels and 65536 tokens. Requests are capped at 1 MiB; output frames at 4 MiB; concurrent connections at 32. Partial requests expire after 10 seconds.# - The upstream deadline defaults to 120 seconds and can be configured with `OPENAI_BEND_DEADLINE_MS`, up to 600000. Socket inactivity is also bounded.# - The official SDK owns retries (two retries configured in the CLI). The bridge does not replay requests after disconnect or restart. Do not automatically retry a partly received inference result without considering duplicate execution/cost.# - Frames are newline-delimited JSON, with non-ASCII characters escaped. The Bend reader handles fragmented/coalesced frames and Unicode surrogate pairs.# - The CLI fixes the upstream URL to `https://api.openai.com/v1`. Alternate upstream clients exist only as programmatic configuration for tests or an operator-controlled integration.# - No telemetry or prompt logging is implemented by this project. Provider error messages are returned to the authenticated caller and may contain submitted content. Example programs intentionally print responses.## The bridge token is sent over local TCP without TLS. This design assumes a trusted local machine and companion. It does not protect against a compromised local account, privileged process, malicious replacement bridge, or someone who can read your process environment. Bend's termination/type checks do not prove the socket runtime, provider behavior or the entire SDK secure. The source marks the few externally driven or structurally unrecognized recursive functions `@unsafe` explicitly.## ## Development and validation## ```sh# bun install --frozen-lockfile# make test# bun audit# ```## Tests use the actual OpenAI TypeScript SDK against a local HTTP mock, plus real TCP connections and compiled Bend clients. They require no real API key and make no inference requests to OpenAI. A successful local mock run proves protocol and integration behavior, not model behavior or account access.## The dependency lockfile is committed. Formatting and TypeScript checks are part of `make test`. See [compatibility.json](https://github.com/gouveags/openai-bend/blob/main/compatibility.json) for the pinned compiler, companion protocol and SDK versions.## ## Troubleshooting## | Symptom | Check |# | ------------------------------------- | ------------------------------------------------------------------------------- |# | Connection refused | Start the companion and check the port. |# | Unauthorized / request-ID mismatch | Use the same bridge token in both processes. |# | API 401/403 | Check the companion's API key and project/model access. |# | API 429 | Inspect error metadata; avoid adding another unbounded retry loop. |# | Truncated stream | Treat the partial output as incomplete; do not silently call it success. |# | Native build consumes too much memory | Use the tested compiler and default Makefile flags; report a reproducible case. |## ## License## MIT. The OpenAI TypeScript SDK is a separately licensed dependency. Bend is a separate project. Contributions and reproducible bug reports are welcome at [GitHub](https://github.com/gouveags/openai-bend/issues).## ### Companion 0.1.1## The command-line examples return a nonzero exit status for failed or incomplete responses. SDK diagnostic logging is disabled. This companion patch retains the library API from v0.1.0 and works with the named Hub release above.## ## Releases and live validation## [Release workflow and credential renewal](https://github.com/gouveags/openai-bend/blob/main/docs/releasing.md). New Hub versions publish automatically after their version bump lands on `main` and CI succeeds.## For an explicitly authorized real-provider check, load your API key into the environment securely, build with the compiler in `compatibility.json`, then run:## ```sh# make build# SDK_LIVE_TEST=1 bun run test:live# ```## This makes two billed requests (JavaScript nonstreaming and native streaming), each limited to 64 output tokens with retries disabled. It checks the actual reply and completion status. Regular `make test` uses local mocks and does not call a paid API. Provider keys are never needed by the release workflow.## Live smoke validation on September 30, 2026 passed with `gpt-4.1-nano`: both the JavaScript nonstreaming and native streaming clients received a completed `SDK_OK` reply. This verifies basic real-provider integration, not every model or API feature.#def repository() -> String: "https://github.com/gouveags/openai-bend"def version() -> String: "0.1.0"