TypeScript SDK

What the SDK ships, how the subpath exports map to source modules, and where to start reading.

Building on OctoStaffdocs/build/10-sdk.mdx
On this page

The @octostaff/sdk package is the shared, framework-agnostic contract layer between the Bubble service and its consumers: the Bubble wire protocol types and the thread assembler that turns events into Bubble messages. Everything else that used to live here — taskqueue, model-stream, stream, env/auth helpers, agent-thread types — has moved into the package that actually uses it.

Subpath Exports

SubpathWhat lives thereDoc page
@octostaff/sdkBubble wire types plus shared runtime codecs for HTTP request/response bodies and both WebSocket directions.Artifact Protocol
@octostaff/sdk/typesCore Bubble event/principal/authz types plus post-assembled BubbleMessage contracts and synthesized data-part types.Thread Assembler
@octostaff/sdk/assemblerStateful translator from BubbleSequencedEvent[] to BubbleMessage[] for assistant-ui-style renderers.Thread Assembler
@octostaff/sdk/clientValidated HTTP/WS client, reconnect and polling lifecycle, durable consumer cursors, and async-iterable subscriptions.Client contract below
@octostaff/sdk/amphibianShared bot runtime plus the harness-neutral local Bubble tool catalog used by scuba adapters.Local Bubble tools below

The root export is the Bubble protocol surface; the assembler lives under its own subpath because it pulls in ai as a peer dependency for the post-assembled message reducer, which not every consumer needs.

src/protocol/core-codecs.ts is the runtime boundary shared by both peers: Bubble verifies client-authored HTTP bodies and WebSocket frames with it and validates server frames before serialization; BubbleConnection validates server HTTP responses and WebSocket frames before exposing them to consumers.

Where to Start Reading

If you are…

  • …rendering a Bubble thread in a React UI: read Thread Assembler. The package's public surface is small (one configured assembler, one stateful thread assembler, and native-part handlers) but the design space it covers — message grouping, segment rules, and idempotency — has a learning curve.
  • …emitting Bubble events from a service: read the Bubble Events doc for the wire schema; the SDK just types it.
  • …writing a new transport or storage adapter that needs to walk a Bubble backlog and hand off to assistant-ui: the thread assembler doc covers the MessageFormatItem chaining shape.
  • …connecting to Bubble: construct BubbleConnection from @octostaff/sdk/client. It starts idle, opens WebSocket lazily, exposes connection-wide failures through onError, and becomes terminal after close(). Public discovery (listAuthenticators, getServerInfo) needs no token; protected calls fail with BubbleClientError when credentials are absent.
  • …storing or transferring artifacts: read Artifact Protocol for the global /v1/artifacts routes, explicit access scopes, and staged transfer flow.

Local Bubble Tools

@octostaff/sdk/amphibian exports one curated, harness-neutral tool catalog. LOCAL_BUBBLE_TOOL_DESCRIPTORS is the schema surface, and runLocalBubbleTool dispatches a validated call through the amphibian's own authenticated BubbleApi. Artifact tools share the catalog with four thread-oriented operations:

  • browse_thread pages lossless events and participant context;
  • open_subthread creates an idempotent agent-only child;
  • search_principals resolves an exact principal before mutation; and
  • invite_to_thread adds one principal as member.

Thread ids are optional where the active thread is the natural default. An explicit id does not widen authority: Bubble still evaluates the caller's current read, child-create, grant-management, discoverability, and invite privacy rights. A harness adapter is responsible only for translating the descriptors, supplying active-thread/tool-call correlation, and rendering the harness-neutral result.

Client Contract

  • HTTP and WebSocket responses are runtime-decoded before entering application state. Every failure is a BubbleClientError; branch on kind for local lifecycle/transport failures and code for Bubble protocol failures.
  • Unacknowledged appendEvent calls preserve registration order with cursor frames until socket handoff, but handoff is not a persistence acknowledgement. Pass { ack: true } when persistence or the assigned seq is required. HTTP acknowledgements are not ordered against earlier fire-and-forget WebSocket writes; use one transport when persistence order matters.
  • subscribeThreadList, subscribeGrants, and subscribePresence fan multiple local listeners onto the protocol's singleton subscription. Their iterable adapters share { opened, changes(), close() } semantics.
  • close() aborts in-flight HTTP, stops reconnect/polling, rejects queued work, and terminates subscriptions. A closed connection cannot be reused.

Layout

text
packages/sdk-typescript/
├── docs/
│   ├── 00-overview.mdx         # this page
│   ├── 10-artifact-protocol.mdx # Artifact HTTP/SDK contract
│   └── 15-assembler.mdx        # Thread Assembler
└── src/
    ├── identity/               # bubble authenticator dispatch
    ├── protocol/               # HTTP/WS shapes + bidirectional runtime codecs
    ├── types/                  # bubble event / principal / authz / message types
    ├── client/                 # connection, consumers, subscriptions, polling
    │   └── transport/          # HTTP, WebSocket, outbound queue, Node adapter
    ├── index.ts                # root barrel re-exporting all of the above
    └── assembler/              # event → BubbleMessage translator
        ├── assembler.ts        # configured assembler + thread lifecycle
        ├── run-segment.ts      # RunSegment class
        ├── tool-parts.ts       # event-neutral AI SDK tool-part traversal
        ├── chunk-helpers.ts    # internal chunk utilities
        ├── segment-reducer.ts  # persistent AI SDK reducer stream
        ├── event-handlers/     # semantic event families
        ├── native-part-handlers/ # core bubble-v1 families
        ├── contracts.ts        # public composition contracts
        └── index.ts            # slim public entrypoint