Adapter SDK

Utilities

Exported helpers for formatters and custom orchestrators — chunkText, truncateText, computeContainerTitle, toolSummary, block builders, PendingOutbound.

Utilities

The adapter SDK exports a small toolbox of helpers you'll reach for when building a Formatter or a custom orchestrator. Every helper listed here is also used internally by the runtime — they're public so your code can stay consistent with the SDK's own behaviour.

Text chunking & truncation

import { chunkText, truncateText } from '@oro.ad/bridge-adapter-sdk'

chunkText('hello world', 5)  // ['hello', ' worl', 'd']
truncateText('a long sentence', 8)  // 'a long …'
truncateText('short', 10)           // 'short'
truncateText('abc', 5, '...')       // 'abc'  (ellipsis only applied when truncating)

Use chunkText when a platform enforces a per-message size cap (Telegram 4096, Discord 2000, Slack 40000). It does NOT try to break at word or paragraph boundaries — wrap your own smart splitter if that matters.

Container title normalization

import { computeContainerTitle } from '@oro.ad/bridge-adapter-sdk'

computeContainerTitle(
  { conversationId: 'claude_abc...', title: 'My Session' },
  { maxLength: 40 },
)
// 'My Session'

computeContainerTitle(
  { conversationId: 'claude_abc123', title: '' },
  { maxLength: 40, fallback: (s) => `Session ${s.conversationId.slice(0, 8)}` },
)
// 'Session claude_a'

Applied consistently by the Reconciler and PlatformToBridge so titles don't diverge between the two sides.

Tool summary

import { toolSummary } from '@oro.ad/bridge-adapter-sdk'

toolSummary('Read', { file_path: '/very/long/path/to/file.ts' })
// '…/long/path/to/file.ts'

toolSummary('Bash', { command: 'git log --oneline | head' })
// 'git log --oneline | head'

Knows the conventional input schema for common Claude tools (Read, Write, Edit, MultiEdit, NotebookRead/Edit, Bash, Grep, Glob, WebFetch, WebSearch, Task, TodoWrite) and falls back to stringifying the first input value otherwise. Output capped at 80 characters.

Semantic-block builders

Use these to convert bridge events into semantic blocks before rendering. The runtime already calls them for you; the exports are useful for custom paths (e.g. rendering a stashed BridgeMessage in a side panel).

import {
  streamUserMessageToBlocks,
  streamToolCallToBlocks,
  streamResultToBlocks,
  sessionErrorToBlocks,
  bridgeMessageToBlocks,
} from '@oro.ad/bridge-adapter-sdk'

// A stream:tool_use without its result yet
const cardPartial = streamToolCallToBlocks(toolUseEvent)

// Same, with the matching stream:tool_result
const cardFull = streamToolCallToBlocks(toolUseEvent, toolResultEvent)

// Replay an historical BridgeMessage
const blocks = bridgeMessageToBlocks(msg)

PendingOutbound

Deduplication primitive used to suppress the echo fan-out of our own POSTed messages. The runtime constructs one per adapter; if you're wiring a custom runtime, use it like this:

import { PendingOutbound } from '@oro.ad/bridge-adapter-sdk'

const pending = new PendingOutbound({ ttlMs: 10_000 })

// Right before POSTing to bridge
const token = pending.register(conversationId, content)
try {
  await bridgeApi.sendMessage(conversationId, { content })
}
catch (err) {
  pending.cancel(token)      // prevent false echo matches
  throw err
}

// Later, in the `stream:user_message` handler:
if (pending.consumeIfMatching(e.conversationId, e.content)) return  // skip echo

Key is (conversationId, content.trim()) — identical content sent twice in rapid succession will collide; raise the TTL or disambiguate via metadata if that's a concern for your platform.