docs.bend
bend-anthropic-sdk@0.1.0.0 · 226 lines · 0 definitions
1# An unofficial Anthropic SDK for Bend, with typed requests, streaming, and tool calling.
2
3import Base
4
5# # anthropic-bend
6#
7# **An unofficial Anthropic SDK for Bend, with typed requests, streaming, and tool calling.**
8#
9# Call Claude from Bend through a small authenticated localhost companion using the official Anthropic TypeScript SDK. Native and JavaScript Bend programs use the same interface.
10#
11# [Examples](https://github.com/gouveags/anthropic-bend/tree/main/examples) · [Source](https://github.com/gouveags/anthropic-bend) · [Issues](https://github.com/gouveags/anthropic-bend/issues) · [OpenAI companion project](https://github.com/gouveags/openai-bend)
12#
13# > Experimental v0.1.0. A community project, not an official Anthropic or Bend project. This release covers the Messages API, not the entire SDK. Tests use a local mock API; live Claude inference has not been tested.
14#
15# ## Install from Bend Hub
16#
17# [**bend-anthropic-sdk@0.1.0.0**](https://hub.bend-lang.com/n/bend-anthropic-sdk) · [Packaged documentation](https://github.com/gouveags/anthropic-bend/blob/main/docs.bend) · [Source and examples](https://github.com/gouveags/anthropic-bend)
18#
19# Use **Bend 2.0.27 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.
20#
21# ```bend
22# import bend-anthropic-sdk@0.1.0.0/anthropic.bend as Anthropic
23# import bend-anthropic-sdk@0.1.0.0/json.bend as Json
24# ```
25#
26# 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.
27#
28# This first named release adds updated documentation and the bundled license; the SDK API and bridge protocol are unchanged. Existing imports of the [previous hash](https://hub.bend-lang.com/0x44dbbb9fe7023c9f8cc89550f8343cd3) continue to work. Published versions are immutable; future updates use a new version.
29#
30# ## Features
31#
32# | Capability | Implementation |
33# | ------------------------------------------------------ | --------------------------------------------------------------- |
34# | Create messages | Typed model, max_tokens and messages; arbitrary JSON options |
35# | Streaming | Message, content-block, thinking, tool-input and unknown events |
36# | Message helpers | Text, tool uses, stop reason, usage and original JSON |
37# | Structured outputs | `output_config.format` JSON Schema helper |
38# | Tool use | Definitions, typed extraction and tool-result builder |
39# | Images/documents | Content blocks supplied as JSON; no upload helper |
40# | Cancellation | Close a stream or cancel its ID separately |
41# | Error metadata | HTTP status, request ID and Retry-After |
42# | Batches, uploads, token-count endpoint, managed agents | Not implemented |
43# | Bedrock, Vertex and beta-header configuration | Not implemented |
44#
45# No automatic tool execution, agent loop, arbitrary schema derivation, or stream-to-final-message accumulator is included. Raw payloads retain details without convenience helpers.
46#
47# ## Install the companion
48#
49# Requirements: [Bend 2.0.27+](https://github.com/bendlang/bend), [Bun 1.4.2](https://bun.sh/), and Git. Native builds also need Clang and Make. Linux x86_64 is tested; macOS is not yet validated.
50#
51# ```sh
52# git clone https://github.com/gouveags/anthropic-bend.git
53# cd anthropic-bend
54# git checkout v0.1.0
55# bun install --frozen-lockfile
56# ```
57#
58# Load your key into `ANTHROPIC_API_KEY` through your secret manager or private shell input. Never commit it or put it in a command saved to shell history.
59#
60# ```sh
61# export ANTHROPIC_BEND_TOKEN="$(openssl rand -hex 32)"
62# export ANTHROPIC_BEND_PORT=42102
63# export ANTHROPIC_MODEL='your-available-claude-model-id'
64# bun run bridge
65# ```
66#
67# Expected startup:
68#
69# ```text
70# anthropic-bend 0.1.0 listening on 127.0.0.1:42102 (protocol 1)
71# ```
72#
73# Give your Bend process the same bridge token and port. It does not need the Anthropic API key. Share the token between terminals through your local secret-management mechanism; the bridge never prints it.
74#
75# **The Bend Hub package installs only the Bend modules. Install the companion and its Bun dependencies separately using these steps.**
76#
77# ## Quick start
78#
79# With the companion running and the same bridge environment available:
80#
81# ```sh
82# make build/request.js
83# bun build/request.js example-1 once \
84# "{\"model\":\"$ANTHROPIC_MODEL\",\"max_tokens\":256,\"messages\":[{\"role\":\"user\",\"content\":\"Say hello.\"}]}"
85#
86# # Change 'once' to 'stream' to print every event.
87# # Or use the native client:
88# make build/request
89# ./build/request example-2 stream \
90# "{\"model\":\"$ANTHROPIC_MODEL\",\"max_tokens\":256,\"messages\":[{\"role\":\"user\",\"content\":\"Explain interaction nets briefly.\"}]}"
91# ```
92#
93# The Makefile emits C and compiles with Clang `-O1`. Builds are sequential; allow roughly 4 GiB of available compiler memory. This integration makes no claim of faster inference or GPU acceleration.
94#
95# ## Typed Bend API
96#
97# Within this checkout:
98#
99# ```bend
100# import Base
101# import ./anthropic.bend as Anthropic
102#
103# def start(token: String, model: String) ->
104# IO(Result<&1, &1, Anthropic.Error, Anthropic.Stream>):
105# Anthropic.create(
106# Anthropic.Client{42102, token},
107# "my-unique-request-id",
108# Anthropic.text_request(model, "Say hello.", 256))
109# ```
110#
111# Use `Anthropic.stream` for streaming or `Anthropic.open_raw` for a JSON request body. Typed requests are `Request{model, max_tokens, messages, options}`. Options are JSON fields such as `system`, `thinking`, `tools`, `tool_choice` and `output_config`; model support varies.
112#
113# Both methods return an owned stream handle. `Anthropic.next` yields:
114#
115# - `Event{stream, kind, data, request_id}`: process the payload, then read using the returned stream.
116# - `Finished{}`: the transport ended correctly and the socket has closed.
117# - `Failed{error}`: the socket has closed with an API, protocol or transport failure.
118#
119# Nonstreaming calls produce a `result`. `Anthropic.message(data)` extracts `Message{id, stop_reason, text, calls, usage, raw}`. Streaming begins with bridge `metadata`, then provider events such as `message_start`, `content_block_delta`, `message_delta` and `message_stop`.
120#
121# **Transport completion is not a successful model outcome by itself.** Inspect `stop_reason` or the final `message_delta`: `max_tokens` means truncated output; `tool_use` requests tool results. Stream `error` events remain visible. Missing terminal events fail explicitly. Anthropic usage deltas are cumulative, not values to sum blindly.
122#
123# The companion uses the official SDK's raw SSE decoder to preserve unknown event types and pings. For text, inspect `content_block_delta` with `delta.type` equal to `text_delta`. Thinking and tool JSON deltas remain separate. See [the streaming reference](https://platform.claude.com/docs/en/build-with-claude/streaming).
124#
125# Call `Anthropic.close(stream)` when abandoning a result. `Anthropic.cancel(client, id)` uses a separate connection, allowing another computation to cancel a blocked read. Cancellation requests an abort; remote processing or billing may already have occurred.
126#
127# ## Examples
128#
129# - [hello.bend](https://github.com/gouveags/anthropic-bend/blob/main/examples/hello.bend): basic typed request.
130# - [request.bend](https://github.com/gouveags/anthropic-bend/blob/main/examples/request.bend): complete event reader and JSON CLI.
131# - [structured.bend](https://github.com/gouveags/anthropic-bend/blob/main/examples/structured.bend): JSON Schema output.
132# - [tools.bend](https://github.com/gouveags/anthropic-bend/blob/main/examples/tools.bend): request a tool call without automatic execution.
133# - [cancel.bend](https://github.com/gouveags/anthropic-bend/blob/main/examples/cancel.bend): cancellation; cancellation intentionally exits nonzero.
134#
135# Compile with `bend examples/hello.bend -o build/hello.js`, then run `bun build/hello.js`. Examples read `ANTHROPIC_BEND_PORT`, `ANTHROPIC_BEND_TOKEN` and, where needed, `ANTHROPIC_MODEL`.
136#
137# ## Structured outputs
138#
139# Add `Json.Field{"output_config", Anthropic.json_schema(schema)}` to request options. It produces `output_config: {format: {type: "json_schema", schema: ...}}`.
140#
141# Use [Anthropic's supported schemas](https://platform.claude.com/docs/en/build-with-claude/structured-outputs). Check the stop reason/refusal before parsing output with `Json.read`, then validate your application's fields. Arbitrary schemas are not automatically proven equivalent to Bend types.
142#
143# ## Tool-use round trip
144#
145# Define a tool using `Anthropic.tool(name, description, input_schema)`. `Message.calls` contains `ToolUse{id, name, input, raw}` records. Validate names and inputs against an application-owned registry before executing anything.
146#
147# Create results with `Anthropic.tool_result(tool_use_id, content, is_error)`. Send the conversation again, preserving the assistant content and adding a user message with the tool results:
148#
149# ```json
150# [
151# { "role": "user", "content": "What is the weather?" },
152# {
153# "role": "assistant",
154# "content": [
155# {
156# "type": "tool_use",
157# "id": "toolu_example",
158# "name": "weather",
159# "input": { "city": "Sao Paulo" }
160# }
161# ]
162# },
163# {
164# "role": "user",
165# "content": [
166# {
167# "type": "tool_result",
168# "tool_use_id": "toolu_example",
169# "content": "22 C",
170# "is_error": false
171# }
172# ]
173# }
174# ]
175# ```
176#
177# The assistant content is abbreviated here. Real continuations must retain the full content, including thinking/signature blocks, and return results for the relevant tool uses. Anthropic continues through messages, not OpenAI's `previous_response_id`. Read the [official tool guidance](https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools).
178#
179# ## JSON behavior
180#
181# The JSON module supports null, booleans, decimal number strings, Unicode strings, arrays and objects. `Json.get` distinguishes absent fields (`None`) from explicit null (`Some{Null{}}`). Omit an optional field by leaving it out.
182#
183# Numbers do not pass through Bend's `F32`. The JavaScript companion and SDK still have IEEE-754 limitations: integers beyond JavaScript's safe range are not guaranteed exact across the whole system. Supply valid decimal strings in `Json.Number`. Unknown fields remain available in raw JSON.
184#
185# ## Security and architecture
186#
187# ```text
188# Bend → authenticated localhost TCP → companion → official Anthropic SDK → HTTPS API
189# ```
190#
191# - Loopback binding to `127.0.0.1`; never expose or proxy this service publicly.
192# - Separate random bridge token, at least 32 characters; constant-time comparison for equal-length tokens.
193# - Only `messages.create` and local cancellation are allowed. Request bodies cannot choose SDK methods, URLs, headers or credentials.
194# - The CLI fixes the API URL to `https://api.anthropic.com` and disables SDK logging.
195# - One request per connection; 32 connections; 1 MiB requests; 4 MiB frames. JSON decoding caps nesting at 64 levels and tokens at 65536.
196# - Partial requests expire after 10 seconds. Completed/rejected connections have a bounded close timeout. The upstream deadline defaults to 120 seconds; `ANTHROPIC_BEND_DEADLINE_MS` accepts up to 600000.
197# - The SDK owns retries (two configured). The bridge never replays disconnected requests; consider duplicate cost/execution before retrying partial results.
198# - Writes respect backpressure. Disconnects/cancellation abort upstream requests. ASCII-escaped JSON avoids UTF-8 fragmentation at socket boundaries.
199# - This project implements no telemetry or prompt logging. Provider errors may contain submitted content and go only to authenticated callers. Examples intentionally print outputs.
200#
201# This is a single-user, trusted-machine design, not a multi-tenant gateway. Local TCP has no TLS. A compromised account, privileged process, stolen token or malicious replacement companion is outside its protection. Bend's checks do not prove the provider, foreign socket runtime or entire SDK secure. Externally driven loops and structurally unrecognized recursion are explicitly marked `@unsafe`.
202#
203# ## Test and contribute
204#
205# ```sh
206# bun install --frozen-lockfile
207# make test
208# bun audit
209# ```
210#
211# Tests exercise the actual official SDK against local HTTP mocks, real TCP, native/JavaScript clients, documented examples and fresh content-addressed package imports. They use no real API key or paid inference. Passing mocks proves the integration contract, not model behavior, account access or all provider features.
212#
213# [compatibility.json](https://github.com/gouveags/anthropic-bend/blob/main/compatibility.json) records pinned versions. CI checks types, formatting, compilation, tests and dependency advisories. Coverage includes Unicode, nesting, malformed input, auth, connection limits, deadlines, cancellation, disconnects and incomplete streams.
214#
215# For connection failures, check the companion, port and shared token. For API failures, inspect status/request ID and verify credentials/model access in the companion. [Report reproducible issues](https://github.com/gouveags/anthropic-bend/issues) without private prompts or credentials.
216#
217# ## License
218#
219# MIT. Anthropic's SDK and Bend are separately licensed. The JSON and transport foundation is shared with [openai-bend](https://github.com/gouveags/openai-bend).
220#
221
222def repository() -> String:
223 "https://github.com/gouveags/anthropic-bend"
224
225def version() -> String:
226 "0.1.0"