- Version 0.1.0 · Purity pure zero-dep (browser-safe)
- Purpose Parse runtime/Gateway message frames into typed text/thinking/tool blocks and build/merge ordered transcript entries.
- Workspace deps none
- External deps none (devDependency:
@clawboo/tsconfig)
A single flat barrel, no subpath exports. All consumers import from @clawboo/protocol.
Public API
Functions
extractText(message: unknown): string | null, pull display text from a message; strips the [[reply_to_current]] assistant prefix + thinking tags (assistant role), or the channel envelope + appended exec-approval-wait policy (other roles). src/index.ts:315
extractTextCached(message: unknown): string | null, extractText memoized per object via a module-level WeakMap. src/index.ts:342
extractThinking(message: unknown): string | null, extract reasoning from block content, direct fields (thinking/analysis/reasoning/…), or tagged streams. src/index.ts:387
extractThinkingCached(message: unknown): string | null, extractThinking memoized per object. src/index.ts:451
extractThinkingFromTaggedText(text: string): string, extract content between closed <think>/<analysis>/<thought>/<antthinking> tags only. src/index.ts:352
extractThinkingFromTaggedStream(text: string): string, like above but also returns the tail after a still-open thinking tag (streaming in progress). src/index.ts:369
extractToolCalls(message: unknown): ToolCallRecord[], read type: 'toolCall' items from array content → { id?, name?, arguments }. src/index.ts:514
extractToolResult(message: unknown): ToolResultRecord | null, read a role: 'toolResult' | 'tool' message → { toolCallId?, toolName?, details, isError?, text }. src/index.ts:532
extractToolLines(message: unknown): string[], format any tool calls + result as [[tool]]/[[tool-result]] markdown lines. src/index.ts:572
formatThinkingMarkdown(text: string): string, wrap each non-empty line in _…_ under a [[trace]] prefix. src/index.ts:460
formatToolCallMarkdown(call: ToolCallRecord): string, render a tool call as a [[tool]] line with a fenced JSON args block. src/index.ts:550
formatToolResultMarkdown(result: ToolResultRecord): string, render a tool result as a [[tool-result]] line with status meta + fenced text body. src/index.ts:558
parseToolMarkdown(line: string): ParsedToolMarkdown, split a [[tool]]/[[tool-result]] line into { kind, label, body }. src/index.ts:596
formatMetaMarkdown(meta): string, serialize { role, timestamp, thinkingDurationMs? } to a [[meta]] JSON line. src/index.ts:612
parseMetaMarkdown(line): { role, timestamp, thinkingDurationMs? } | null, parse a [[meta]] line back; null on invalid/missing role or non-positive timestamp. src/index.ts:626
stripTraceMarkdown(line: string): string, drop the leading [[trace]] prefix. src/index.ts:591
Markdown type guards
isTraceMarkdown(line: string): boolean, line starts with [[trace]]. src/index.ts:586
isToolMarkdown(line: string): boolean, line starts with [[tool]] or [[tool-result]]. src/index.ts:587
isMetaMarkdown(line: string): boolean, line starts with [[meta]]. src/index.ts:589
stripUiMetadata(text: string): string, remove reset/system-event/project-path injections, [message_id:…] tags, and the channel envelope. src/index.ts:652
isUiMetadataPrefix(text: string): boolean, text starts with a project/workspace-path or reset-session preamble. src/index.ts:663
isHeartbeatPrompt(text: string): boolean, text is a Read HEARTBEAT.md… prompt or carries a heartbeat-file-path line. src/index.ts:664
Main parser
parseMessage(raw: unknown): ParsedMessage, full parse → { text, thinking, toolCalls, toolResults, metadata }. src/index.ts:672
Agent helpers
buildAgentInstruction(params: { message: string }): string, trim a message into an agent instruction. src/index.ts:608
isAgentFileName(value: string): value is AgentFileName, type guard over AGENT_FILE_NAMES. src/index.ts:176
createAgentFilesState(): Record<AgentFileName, AgentFileState>, empty { content: '', exists: false } map keyed by every agent file name. src/index.ts:179
Transcript v2 utilities
fnv1a(value: string): string, FNV-1a 32-bit hash → 8-char hex. src/index.ts:729
createTranscriptEntryFromLine(params): TranscriptEntry | null, build one entry from a line; derives kind/role from markdown prefixes, resolves timestamp, computes the dedup fingerprint + entryId. src/index.ts:860
buildTranscriptEntriesFromLines(params: BuildTranscriptEntriesFromLinesParams): TranscriptEntry[], map lines → entries, threading sequence + the active [[meta]] timestamp. src/index.ts:910
sortTranscriptEntries(entries: TranscriptEntry[]): TranscriptEntry[], dedup by entryId, then sort by timestampMs with sequenceKey as tiebreak. src/index.ts:835
mergeTranscriptEntriesWithHistory(params): MergeTranscriptEntriesResult, fold persisted history into live entries (entryId then text/kind/role match), returning merge/confirmed/conflict counts. src/index.ts:994
buildOutputLinesFromTranscriptEntries(entries: TranscriptEntry[]): string[], extract the .text of each entry. src/index.ts:840
areTranscriptEntriesEqual(left: TranscriptEntry[], right: TranscriptEntry[]): boolean, shallow positional equality on entryId/text/timestamp/confirmed. src/index.ts:843
Types & interfaces
ToolCall: { id?, name, arguments: Record<string, unknown> }. src/index.ts:34
ToolResult: { toolCallId?, name, output, isError?, details? }. src/index.ts:40
MessageMeta: { role?, timestamp?, thinkingDurationMs? }. src/index.ts:48
ParsedMessage: { text, thinking, toolCalls, toolResults, metadata }, the parseMessage return. src/index.ts:54
ParsedToolMarkdown: { kind: 'call' | 'result', label, body }. src/index.ts:62
ToolResultRecord: { toolCallId?, toolName?, details, isError?, text? }, the extractToolResult shape. src/index.ts:476
TranscriptEntryKind: 'meta' | 'user' | 'assistant' | 'thinking' | 'tool'. src/index.ts:70
TranscriptEntryRole: 'user' | 'assistant' | 'tool' | 'system' | 'other'. src/index.ts:72
TranscriptEntrySource: 'local-send' | 'runtime-chat' | 'runtime-agent' | 'history' | 'legacy'. src/index.ts:74
TranscriptEntry: the canonical transcript row: { entryId, role, kind, text, sessionKey, runId, source, timestampMs, sequenceKey, confirmed, fingerprint }. src/index.ts:81
TranscriptAppendMeta: optional append-time overrides for an entry. src/index.ts:95
BuildTranscriptEntriesFromLinesParams: input shape for buildTranscriptEntriesFromLines. src/index.ts:106
MergeTranscriptEntriesResult: { entries, mergedCount, confirmedCount, conflictCount }. src/index.ts:117
AgentFileName: union of the 7 AGENT_FILE_NAMES literals. src/index.ts:136
AgentFileMeta: { title, hint }. src/index.ts:138
AgentFileState: { content, exists }. src/index.ts:143
AgentFileDef: backward-compat { filename, label, description, editable }. src/index.ts:149
ToolCallRecord is referenced in several function signatures above (formatToolCallMarkdown, extractToolCalls) but is a module-local type, not exported from the barrel.
Constants
AGENT_FILE_NAMES: readonly ['AGENTS.md', 'SOUL.md', 'IDENTITY.md', 'USER.md', 'TOOLS.md', 'HEARTBEAT.md', 'MEMORY.md']. src/index.ts:126
AGENT_FILE_META: Record<AgentFileName, AgentFileMeta>: { title, hint } per file. src/index.ts:156
AGENT_FILE_PLACEHOLDERS: Record<AgentFileName, string>: editor placeholder text per file. src/index.ts:166
AGENT_FILES: AgentFileDef[]: backward-compat 7-entry list ({ filename, label, description, editable }); MEMORY.md is editable: false. src/index.ts:185
Used by
@clawboo/events, Bridge parsers reuse extractText / parseMessage / isReasoningStream shapes for the policy pipeline.
@clawboo/adapter-openclaw, maps Gateway frames → RuntimeEvent via the pure parseChatPayload/parseMessage/extractText helpers.
apps/web chat + group-chat surfaces, parseToolMarkdown, the [[tool]]/[[trace]]/[[meta]] guards, TranscriptEntry ordering (sortTranscriptEntries, mergeTranscriptEntriesWithHistory), and AGENT_FILE_NAMES / AGENT_FILE_META for the agent file editor.
@clawboo/agent-registry, mirrors AGENT_FILE_NAMES locally to stay dependency-free (does not import this package).
Source
Barrel: packages/protocol/src/index.ts (single flat module; no subpath exports in package.json).
See also