Add two DeepSeek LLM adapters: dsh-llm-deepseek and dsh-llm-pi-ai
The first real LlmAdapter implementations, shipped as a deliberate pair:
same models and wire protocol, completely different internals, so the
StreamChunk protocol is verified across independent implementations.
- dsh-llm-deepseek: hand-rolled fetch + SSE parser + chunk-translation
state machine against the official chat-completions format (thinking
mode via top-level thinking/reasoning_effort; the empty-string
reasoning_content first chunk; usage attached to the finish chunk or
trailing; reasoning_content passback on tool-call turns; disjoint
cache-token accounting).
- dsh-llm-pi-ai: the same endpoint through @earendil-works/pi-ai,
mapping its event vocabulary (parsed tool arguments, in-stream error
events, folded reasoning tokens) onto the same chunks.
The agent loop now honors the in-band error path: an adapter that ends
its stream with finish {kind:error|aborted} (the only option for
adapters that can't throw mid-stream, like pi-ai) is translated into a
step error, so the turn ends error/aborted with a logged error event
instead of a normal completed assistant message. This makes the
StreamChunk error contract real for both adapters; docs/architecture.md
and the StreamChunk doc are updated accordingly.
New yarn test:e2e (vitest.e2e.config.ts, *.e2e.ts) runs key-gated
real-API matrices for both adapters across V4 Flash/Pro and all
thinking/effort levels; it self-skips without DEEPSEEK_API_KEY. Unit
suites run against local node:http mock SSE servers at 100% per-file
coverage.
This commit is contained in:
60
packages/llm-pi-ai/README.md
Normal file
60
packages/llm-pi-ai/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# @deepseek-ai/dsh-llm-pi-ai
|
||||
|
||||
DeepSeek adapter for the harness LLM seam backed by
|
||||
[`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai)
|
||||
(the LLM library behind the pi agent).
|
||||
|
||||
## Why a second adapter exists
|
||||
|
||||
`@deepseek-ai/dsh-llm-deepseek` already talks to the same endpoint. This
|
||||
package is its **design-verification twin**: same models, same wire
|
||||
protocol, completely different internals — a unified LLM library with its
|
||||
own event vocabulary versus hand-rolled fetch/SSE. Anything the harness
|
||||
`StreamChunk` protocol cannot express for BOTH implementations is a
|
||||
core-vocabulary bug. The differences it exercised on purpose:
|
||||
|
||||
- pi-ai hands back tool-call `arguments` as **parsed objects**; the harness
|
||||
keeps raw JSON strings (re-stringified at `block-end`).
|
||||
- pi-ai reports failures as **in-stream error events** (it never throws
|
||||
mid-stream); these map to `finish {kind:'error'|'aborted'}` chunks — the
|
||||
protocol's other sanctioned error path besides throwing (which
|
||||
llm-deepseek uses).
|
||||
- pi-ai folds reasoning tokens into `usage.output`; there is no separate
|
||||
reasoning count to map.
|
||||
- pi-ai's options omit stop sequences; `GenerateOptions.stop` is injected
|
||||
via its `onPayload` hook.
|
||||
|
||||
## Config
|
||||
|
||||
Same shape as llm-deepseek (one-line swap in cordis.yml), with pi-ai's
|
||||
thinking-level vocabulary:
|
||||
|
||||
```yaml
|
||||
- id: llm
|
||||
name: '@deepseek-ai/dsh-llm-pi-ai'
|
||||
config:
|
||||
apiKey: !!js process.env.DEEPSEEK_API_KEY
|
||||
baseURL: !!js process.env.DEEPSEEK_BASE_URL
|
||||
models: [deepseek-v4-flash, deepseek-v4-pro]
|
||||
reasoning: high # off | high | xhigh (xhigh → wire 'max')
|
||||
```
|
||||
|
||||
## Dependency weight
|
||||
|
||||
pi-ai declares the openai/anthropic/google/mistral/AWS SDKs as install-time
|
||||
dependencies. They are lazy-loaded — only the openai SDK actually loads for
|
||||
this adapter — but they do land in `node_modules`. Accepted for a package
|
||||
whose purpose is design verification.
|
||||
|
||||
## Limitations
|
||||
|
||||
Same MVP contract as llm-deepseek: `prefill` throws `UNSUPPORTED`, images
|
||||
are not representable, `tool_choice` is not mapped.
|
||||
|
||||
## Testing
|
||||
|
||||
Unit suites run against a local `node:http` mock SSE server (pi-ai's openai
|
||||
SDK happily talks to any base URL). Real-API coverage in
|
||||
`tests/adapter.e2e.ts` (`yarn test:e2e`, key-gated): V4 Flash + V4 Pro across
|
||||
all exposed reasoning levels (off/high/xhigh), the thinking+tools round trip,
|
||||
and a cross-adapter structural-equivalence check against llm-deepseek.
|
||||
Reference in New Issue
Block a user