Skip to content

feat: misina/stream — tool-call accumulator + stream.collect() helpers #85

@productdevbook

Description

@productdevbook

Problem

LLM streaming protocols (OpenAI, Anthropic) deliver tool-call arguments as deltas:

  • OpenAI: choices[].delta.tool_calls[] with index, function.name (first chunk), function.arguments (concat across chunks)
  • Anthropic: content_block_startcontent_block_delta (input_json_delta.partial_json chunks) → content_block_stop

Every consumer rewrites the merge logic. Misina can ship two helpers and a generic accumulator.

Proposal

misina/stream adds:

// Generic stream consumer with reducer
const final = await stream.collect(reducer, initial)

// Provider-specific
import { accumulateOpenAIToolCalls, accumulateAnthropicMessage } from 'misina/stream'

const toolCalls = await accumulateOpenAIToolCalls(sseStream(response))
const message = await accumulateAnthropicMessage(sseStream(response))

Both helpers stop at the appropriate sentinel ([DONE] for OpenAI, message_stop for Anthropic). They're 50-80 lines each.

Acceptance criteria

  • Generic collect(reducer, initial) async iterator helper
  • OpenAI tool-call accumulator (handles index, name, partial JSON arguments)
  • Anthropic message accumulator (content blocks, tool_use input_json_delta)
  • Tests with realistic streaming fixtures
  • Doc with both providers

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Nice to haveai-llmLLM/AI client patternsstreamingSSE, NDJSON, stream helperssubpathNew misina/* subpath helper

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions