Tianyi Cui cb6bee3d03 Add ESLint: typescript-eslint strict-type-checked + stylistic formatting 3 bulan lalu
..
src cb6bee3d03 Add ESLint: typescript-eslint strict-type-checked + stylistic formatting 3 bulan lalu
tests d2fb352f3e Enable maximum-strict TypeScript across our packages 3 bulan lalu
README.md 7f024a1a9d Document the codebase thoroughly and tighten type safety 3 bulan lalu
package.json d5a1d9bb75 Add abstract service interface packages 3 bulan lalu
tsconfig.json d5a1d9bb75 Add abstract service interface packages 3 bulan lalu

README.md

dsh-llm

Provider-neutral LLM vocabulary and abstract service. This package defines the canonical language spoken by the agent loop, session logs, and every plugin.

Service: LlmService (ctx key: llm)

An adapter registry plus streaming / non-streaming call surfaces. Both call surfaces are interceptable via waterfall events.

Public API

  • ctx.llm.registerAdapter(models: string[], adapter: LlmAdapter): () => void Register an adapter for the given model names. Disposed with the calling fiber.
  • ctx.llm.models(): string[] — model names with a registered adapter.
  • ctx.llm.stream(options: GenerateOptions): AsyncIterable<StreamChunk> Stream one model call as raw chunks (token-level deltas).
  • ctx.llm.streamBlocks(options: GenerateOptions): AsyncIterable<ContentBlock> Stream as completed content blocks (convenience view).
  • ctx.llm.generate(options: GenerateOptions): Promise<GenerateResult> One model call, fully assembled.

Events

Event Mode Purpose
llm/stream waterfall Intercept/wrap every streaming model call (retry, caching, routing)
llm/generate waterfall Intercept/wrap every non-streaming model call
llm/adapter-change emit An adapter was registered or unregistered

Extension points

  • Subclass LlmAdapter and call ctx.llm.registerAdapter(models, adapter) to add a new model provider.
  • Wrap llm/stream or llm/generate via ctx.on() waterfall listeners for caching, retry, logging, rate-limiting, etc.

Content-block vocabulary (types.ts)

Messages are arrays of typed content blocks: text, reasoning, tool-call, tool-result, image. The union is derived from the merge-extensible ContentBlockMap, so plugins can add block types via declaration merging.

Streaming is a raw chunk protocol (block-start, text-delta, reasoning-delta, tool-call-delta, block-end, usage, finish). BlockAssembler is the single shared implementation that assembles chunks into blocks/messages.

Classes

  • LlmAdapter — abstract base class for provider adapters. The only required method is stream().
  • BlockAssembler — incrementally assembles raw chunks into complete content blocks and an assistant message. Used by the agent loop (raw chunks for replay
    • assembled for history) and by streamBlocks()/generate().
  • LlmError — typed error with a code string (NO_ADAPTER, DUPLICATE_ADAPTER).

What is NOT here (TODO)

  • DeepSeek V4 adapter — the first real adapter lands in a later phase.
  • Streaming protocol review — the chunk protocol has TODO(review) markers and needs careful review before the first real adapter (DeepSeek V4 wire format, partial JSON arguments, interleaved reasoning signatures, ...).