Utilities
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.