@stackstackstack/dsh-llm-deepseek 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +114 -0
- package/README.zh.md +114 -0
- package/lib/index.js +781 -0
- package/lib/invariant.js +23 -0
- package/lib/types/adapter.d.ts +102 -0
- package/lib/types/index.d.ts +76 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/serialize.d.ts +34 -0
- package/lib/types/sse.d.ts +24 -0
- package/lib/types/translate.d.ts +36 -0
- package/lib/types/types.d.ts +150 -0
- package/package.json +58 -0
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@stackstackstack/dsh-llm-deepseek`.
|
|
4
|
+
* @module @stackstackstack/dsh-llm-deepseek/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@stackstackstack/dsh-llm-deepseek";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "llm-deepseek-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this package exposes no independent event sequence or mutable data relation
|
|
13
|
+
* beyond contracts enforced at its owning seam.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `DeepSeekAdapter`: fetch + SSE against a DeepSeek (OpenAI-compatible)
|
|
3
|
+
* chat-completions endpoint, emitting harness StreamChunks. The adapter is
|
|
4
|
+
* transport-only: connection facts arrive through a thunk resolved once per
|
|
5
|
+
* operation and the bearer token through a per-request resolver, so the
|
|
6
|
+
* registering plugin owns validation, layering, and credential policy.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-llm-deepseek/adapter
|
|
9
|
+
*/
|
|
10
|
+
import { LlmAdapter } from '@stackstackstack/dsh-llm';
|
|
11
|
+
import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, ResolvedRetryPolicy, StreamChunk } from '@stackstackstack/dsh-llm';
|
|
12
|
+
import type { CredentialRef } from '@stackstackstack/dsh-credentials';
|
|
13
|
+
import type { AnonymousUserId } from '@stackstackstack/dsh-anonymous-user-id';
|
|
14
|
+
import type { RequestDefaults } from './serialize.ts';
|
|
15
|
+
import type { WireError } from './types.ts';
|
|
16
|
+
/** One optional model entry advertised by the direct-fetch adapter. */
|
|
17
|
+
export interface DeepSeekCatalogModel {
|
|
18
|
+
/** Wire model id accepted by the configured endpoint. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Selector label; defaults to {@link id}. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Optional selector detail for deployments with similar model variants. */
|
|
23
|
+
description?: string;
|
|
24
|
+
/** Known combined request/response context capacity; omitted when deployment metadata is unavailable. */
|
|
25
|
+
contextWindow?: number;
|
|
26
|
+
/** Per-request output cap for this model; omission falls back to the profile's {@link DeepSeekConnectionOptions.maxTokens}. */
|
|
27
|
+
maxTokens?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validated connection facts for one operation. The plugin's
|
|
31
|
+
* `resolveAdapterOptions` is the one explicit resolve step producing this
|
|
32
|
+
* shape; the adapter trusts it and re-reads it per operation, which is what
|
|
33
|
+
* makes a configuration change reach the next request without re-registration.
|
|
34
|
+
*/
|
|
35
|
+
export interface DeepSeekConnectionOptions {
|
|
36
|
+
/** Endpoint base; `/chat/completions` is appended. */
|
|
37
|
+
baseURL: string;
|
|
38
|
+
/**
|
|
39
|
+
* Credential reference of this same resolution, resolved per request.
|
|
40
|
+
* Travelling with the endpoint is the point: a request can never pair one
|
|
41
|
+
* generation's URL with another generation's secret. Configuration carries
|
|
42
|
+
* only this name — a literal key is not a configuration value.
|
|
43
|
+
*/
|
|
44
|
+
apiKeyEnv: CredentialRef;
|
|
45
|
+
/** Request defaults applied to every call (thinking mode, effort). */
|
|
46
|
+
defaults: RequestDefaults;
|
|
47
|
+
/** Default per-request output cap; explicit request values win. */
|
|
48
|
+
maxTokens: number;
|
|
49
|
+
/** Positive context capacity used when the selected model has no exact value. */
|
|
50
|
+
defaultContextWindow: number;
|
|
51
|
+
/** Advisory models exposed to discovery consumers; requests remain unrestricted. */
|
|
52
|
+
models: readonly DeepSeekCatalogModel[];
|
|
53
|
+
/** Maximum provider idle time while one stream read is outstanding. */
|
|
54
|
+
streamIdleTimeoutMs: number;
|
|
55
|
+
/** Provider-owned model-request retry policy, already resolved. */
|
|
56
|
+
retryPolicy: ResolvedRetryPolicy;
|
|
57
|
+
}
|
|
58
|
+
/** Constructor options for {@link DeepSeekAdapter}: the operation-local resolution hooks the plugin owns. */
|
|
59
|
+
export interface DeepSeekAdapterOptions {
|
|
60
|
+
/** Current validated connection facts; called once per operation. */
|
|
61
|
+
options: () => DeepSeekConnectionOptions;
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the bearer token for the connection facts of one request. The
|
|
64
|
+
* snapshot is passed in — never re-read — so the key can only ever come
|
|
65
|
+
* from the same resolution as the endpoint it is sent to. Throws `LlmError`
|
|
66
|
+
* `MISSING_CREDENTIAL` when no key is available anywhere.
|
|
67
|
+
*/
|
|
68
|
+
resolveApiKey: (connection: DeepSeekConnectionOptions) => Promise<string>;
|
|
69
|
+
/** Resolve the harness-home anonymous id shared with telemetry and feedback. */
|
|
70
|
+
resolveUserId: () => AnonymousUserId;
|
|
71
|
+
}
|
|
72
|
+
/** Default maximum idle interval while an adapter stream read is outstanding. */
|
|
73
|
+
export declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
74
|
+
/** Default combined request/response context capacity. */
|
|
75
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 1000000;
|
|
76
|
+
/** Default per-request output-token cap. */
|
|
77
|
+
export declare const DEFAULT_MAX_TOKENS = 256000;
|
|
78
|
+
/**
|
|
79
|
+
* Map an HTTP status to a stable LlmError code.
|
|
80
|
+
* @param status - status of a non-2xx provider response.
|
|
81
|
+
* @param error - parsed provider error body, when available.
|
|
82
|
+
* @returns the normalized harness error code.
|
|
83
|
+
*/
|
|
84
|
+
export declare function httpErrorCode(status: number, error?: WireError['error']): string;
|
|
85
|
+
/**
|
|
86
|
+
* The first real `LlmAdapter`. One instance serves every model name it was
|
|
87
|
+
* registered under (the harness model name IS the wire model name).
|
|
88
|
+
*
|
|
89
|
+
* One stable signal reaches both initial fetch and body reads. Caller aborts
|
|
90
|
+
* map to `ABORTED`; the configured per-read idle watchdog maps to `TIMEOUT`.
|
|
91
|
+
*/
|
|
92
|
+
export declare class DeepSeekAdapter extends LlmAdapter {
|
|
93
|
+
private readonly config;
|
|
94
|
+
constructor(config: DeepSeekAdapterOptions);
|
|
95
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
96
|
+
providerRetryPolicy(_provider: string): ResolvedRetryPolicy;
|
|
97
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
98
|
+
resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
99
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
100
|
+
private request;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register a {@link DeepSeekAdapter} for the `deepseek-official` provider route on
|
|
3
|
+
* `ctx.llm`, with connection facts resolved per request instead of frozen at
|
|
4
|
+
* load: the plugin layers its `cordis.yml` entry config under the optional
|
|
5
|
+
* `llm-deepseek` user-settings section (`ctx.settings`) and resolves the API
|
|
6
|
+
* key through the optional credential seam (`ctx.credentials`), so a changed
|
|
7
|
+
* base URL, catalog, or key reaches the very next request without restarting
|
|
8
|
+
* anything, while an in-flight stream keeps the facts it started with. The
|
|
9
|
+
* one registration-captured fact — the retry policy — re-registers the route
|
|
10
|
+
* in place when it changes.
|
|
11
|
+
* @module @stackstackstack/dsh-llm-deepseek
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import z from '@deepseek-ai/schemastery';
|
|
15
|
+
import type { RetryPolicyConfig } from '@stackstackstack/dsh-llm';
|
|
16
|
+
import { type LaunchEnvironmentSnapshot } from '@stackstackstack/dsh-launch-environment';
|
|
17
|
+
import type { DeepSeekCatalogModel, DeepSeekConnectionOptions } from './adapter.ts';
|
|
18
|
+
export { DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DeepSeekAdapter, } from './adapter.ts';
|
|
19
|
+
export type { DeepSeekAdapterOptions, DeepSeekCatalogModel, DeepSeekConnectionOptions } from './adapter.ts';
|
|
20
|
+
export type { RequestDefaults } from './serialize.ts';
|
|
21
|
+
export type * from './types.ts';
|
|
22
|
+
export declare const name = "llm-deepseek";
|
|
23
|
+
export declare const inject: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Plugin config, validated by the same-named schemastery schema and doubling
|
|
26
|
+
* as the `llm-deepseek` settings-section shape. Every field is optional in
|
|
27
|
+
* yml: a missing API key resolves through {@link Config.apiKeyEnv} at each
|
|
28
|
+
* request (a request without any key fails with `MISSING_CREDENTIAL`, not at
|
|
29
|
+
* plugin load), omitted thinking mode uses the provider default, and omitted
|
|
30
|
+
* reasoning effort resolves to `high`.
|
|
31
|
+
*/
|
|
32
|
+
export interface Config {
|
|
33
|
+
/** Credential reference (environment-variable name) resolved per request; defaults to `DEEPSEEK_API_KEY`. */
|
|
34
|
+
apiKeyEnv?: string;
|
|
35
|
+
/** Endpoint base; falls back to $DEEPSEEK_BASE_URL from a trusted environment layer, then the public API. */
|
|
36
|
+
baseURL?: string;
|
|
37
|
+
/** Deployment thinking policy; `disabled` limits every conversation request to `off`. */
|
|
38
|
+
thinking?: 'enabled' | 'disabled';
|
|
39
|
+
/** Default thinking effort (default `high`); `off` disables thinking per request. */
|
|
40
|
+
reasoningEffort?: 'off' | 'high' | 'max';
|
|
41
|
+
/** Default per-request output cap (default 256,000); a model's own cap and explicit request values win. */
|
|
42
|
+
maxTokens?: number;
|
|
43
|
+
/** Positive context capacity used when the selected model has no exact value (default 1,000,000). */
|
|
44
|
+
defaultContextWindow?: number;
|
|
45
|
+
/** Advisory models shown by discovery consumers; defaults to V4 Flash and V4 Pro. */
|
|
46
|
+
models?: DeepSeekCatalogModel[];
|
|
47
|
+
/** Maximum provider idle time while one stream read is outstanding (default five minutes). */
|
|
48
|
+
streamIdleTimeoutMs?: number;
|
|
49
|
+
/** Provider-owned model-request retry policy; omission uses normal defaults. */
|
|
50
|
+
retryPolicy?: RetryPolicyConfig;
|
|
51
|
+
}
|
|
52
|
+
export declare const Config: z<Config>;
|
|
53
|
+
/** Public API default; the internal endpoint comes from $DEEPSEEK_BASE_URL. */
|
|
54
|
+
export declare const PUBLIC_BASE_URL = "https://api.deepseek.com";
|
|
55
|
+
/**
|
|
56
|
+
* One resolution's complete request facts. Connection and credential facts
|
|
57
|
+
* are one value on purpose: a snapshot the resolver rejects keeps the whole
|
|
58
|
+
* previous generation, so a request can never pair a stale endpoint with a
|
|
59
|
+
* newer key.
|
|
60
|
+
*/
|
|
61
|
+
export type ResolvedDeepSeekOptions = DeepSeekConnectionOptions;
|
|
62
|
+
/**
|
|
63
|
+
* The one explicit resolve step from raw config to validated connection
|
|
64
|
+
* facts. Programmatic construction may bypass Schemastery normalization, so
|
|
65
|
+
* every default and bound is re-judged here — for the composition entry at
|
|
66
|
+
* load (fail loud) and for each settings snapshot at its first use.
|
|
67
|
+
* @param config - raw plugin config or resolved settings snapshot.
|
|
68
|
+
* @param environment - this run's environment layers, or `undefined` outside
|
|
69
|
+
* the product CLI. Every layer may supply an endpoint: the product trusts the
|
|
70
|
+
* project it is launched in, so a checkout can point its own agent at the
|
|
71
|
+
* gateway that checkout is meant to use.
|
|
72
|
+
* @returns validated connection facts plus the credential reference.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveAdapterOptions(config: Config, environment?: LaunchEnvironmentSnapshot): ResolvedDeepSeekOptions;
|
|
75
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@stackstackstack/dsh-llm-deepseek`.
|
|
3
|
+
* @module @stackstackstack/dsh-llm-deepseek/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "llm-deepseek-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize harness messages into DeepSeek chat completions. User text is joined; assistant text
|
|
3
|
+
* becomes `content`, tool calls become `tool_calls`, and tool results become separate tool messages.
|
|
4
|
+
* Assistant reasoning is replayed as `reasoning_content` only on tool-call turns, as required by
|
|
5
|
+
* thinking-mode passback. Core image blocks are rejected explicitly because this wire route is text-only;
|
|
6
|
+
* unknown declaration-merged block types retain the adapter's documented extension fallback.
|
|
7
|
+
* @module dsh-llm-deepseek/serialize
|
|
8
|
+
*/
|
|
9
|
+
import type { GenerateOptions, Message } from '@stackstackstack/dsh-llm';
|
|
10
|
+
import type { WireMessage, WireRequest } from './types.ts';
|
|
11
|
+
/** Adapter-level request defaults (from plugin config). */
|
|
12
|
+
export interface RequestDefaults {
|
|
13
|
+
thinking?: 'enabled' | 'disabled' | undefined;
|
|
14
|
+
reasoningEffort?: 'off' | 'high' | 'max' | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Serialize the conversation. `tool-result` blocks become standalone
|
|
18
|
+
* `{role: 'tool'}` messages; the harness puts each tool result in its own
|
|
19
|
+
* user-role message, so a mixed user message contributes its text first and
|
|
20
|
+
* its tool results as separate wire messages after.
|
|
21
|
+
* @param messages - the harness conversation, in order.
|
|
22
|
+
* @returns the wire messages; order preserved, each tool result expanded into its own entry.
|
|
23
|
+
*/
|
|
24
|
+
export declare function serializeMessages(messages: Message[]): WireMessage[];
|
|
25
|
+
/**
|
|
26
|
+
* Build the full wire request. Always streaming (`stream: true`, usage
|
|
27
|
+
* reporting on); optional fields are omitted rather than sent as null, so
|
|
28
|
+
* provider defaults apply.
|
|
29
|
+
* @param options - the harness request (model, history, system, tools, sampling).
|
|
30
|
+
* @param defaults - adapter-level thinking defaults; undefined fields put nothing on the wire.
|
|
31
|
+
* @returns the chat-completions request body.
|
|
32
|
+
*/
|
|
33
|
+
export declare function serializeRequest(options: GenerateOptions, defaults?: RequestDefaults): WireRequest;
|
|
34
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decode an SSE byte stream into event `data` payloads. Framing — chunk
|
|
3
|
+
* reassembly, UTF-8/CRLF/BOM handling, comment and non-data field skipping,
|
|
4
|
+
* multi-`data:` joining — is `eventsource-parser`'s. Comments are reported
|
|
5
|
+
* only through an optional transport-activity callback. This module keeps the
|
|
6
|
+
* DeepSeek protocol: the literal `[DONE]` is yielded so the caller owns final
|
|
7
|
+
* flushing, and EOF before it raises {@link LlmError}. Framing is spec-strict:
|
|
8
|
+
* an event dispatches only on its blank-line terminator, so an unterminated
|
|
9
|
+
* tail at EOF is truncation, not a flushable payload.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-llm-deepseek/sse
|
|
12
|
+
*/
|
|
13
|
+
/** The terminal payload DeepSeek (and OpenAI) send after the last chunk. */
|
|
14
|
+
export declare const DONE = "[DONE]";
|
|
15
|
+
/**
|
|
16
|
+
* Parse an SSE byte stream into data payloads. Yields `[DONE]` as the final
|
|
17
|
+
* value and returns; throws `LlmError('STREAM_CLOSED')` when the stream ends
|
|
18
|
+
* without it (truncated response — the model call cannot be trusted).
|
|
19
|
+
* @param stream - raw SSE bytes; reads may split anywhere, including mid-UTF-8 sequence.
|
|
20
|
+
* @param onComment - optional transport-activity callback; comments never enter the yielded payload stream.
|
|
21
|
+
* @returns each event's data payload in arrival order, the `[DONE]` sentinel last.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseSse(stream: ReadableStream<BufferSource>, onComment?: (comment: string) => void): AsyncGenerator<string>;
|
|
24
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate DeepSeek SSE payloads with one stateful harness block per content, reasoning, or tool
|
|
3
|
+
* call index. An empty initial reasoning delta does not open a block. Finish reason and the latest
|
|
4
|
+
* usage are deferred until `[DONE]`, covering both finish-attached and trailing usage-only shapes
|
|
5
|
+
* while ensuring no chunk follows `finish`.
|
|
6
|
+
*
|
|
7
|
+
* Translate DeepSeek wire chunks into the harness `StreamChunk` protocol.
|
|
8
|
+
* @module dsh-llm-deepseek/translate
|
|
9
|
+
*/
|
|
10
|
+
import type { FinishReason, StreamChunk, TokenUsage } from '@stackstackstack/dsh-llm';
|
|
11
|
+
import type { WireUsage } from './types.ts';
|
|
12
|
+
/**
|
|
13
|
+
* Map the wire finish_reason vocabulary to the harness FinishReason.
|
|
14
|
+
* @param reason - the wire `finish_reason` string.
|
|
15
|
+
* @returns the mapped reason; unrecognized values (content_filter, …) become `{kind: 'error'}` with the uppercased value as `code`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function mapFinishReason(reason: string): FinishReason;
|
|
18
|
+
/**
|
|
19
|
+
* Map wire usage fields. DeepSeek's `prompt_tokens` INCLUDES cache hits
|
|
20
|
+
* (`prompt_tokens = prompt_cache_hit_tokens + prompt_cache_miss_tokens`,
|
|
21
|
+
* api/create-chat-completion); the harness TokenUsage convention is
|
|
22
|
+
* DISJOINT counts, so cache reads are subtracted out of `inputTokens`.
|
|
23
|
+
* @param usage - wire usage from the finish chunk or the trailing usage-only chunk.
|
|
24
|
+
* @returns disjoint harness counts; cache/reasoning fields present only when the wire reported them.
|
|
25
|
+
*/
|
|
26
|
+
export declare function mapUsage(usage: WireUsage): TokenUsage;
|
|
27
|
+
/**
|
|
28
|
+
* Consume SSE data payloads (ending with `[DONE]`) and yield StreamChunks.
|
|
29
|
+
* Malformed JSON payloads abort the stream with `MALFORMED_RESPONSE`.
|
|
30
|
+
* @param payloads - SSE data payloads from {@link parseSse}, `[DONE]`-terminated.
|
|
31
|
+
* @returns deltas as they arrive; `block-end`s, `usage`, and `finish` are all deferred to the `[DONE]` sentinel.
|
|
32
|
+
* A `stop` (or absent) finish with no opened blocks is a degenerate provider completion and maps to an
|
|
33
|
+
* `EMPTY_RESPONSE` error finish instead of a successful empty message.
|
|
34
|
+
*/
|
|
35
|
+
export declare function translate(payloads: AsyncIterable<string>): AsyncGenerator<StreamChunk>;
|
|
36
|
+
//# sourceMappingURL=translate.d.ts.map
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek chat-completions wire format (OpenAI-compatible). Types only.
|
|
3
|
+
*
|
|
4
|
+
* Source of truth: the official API docs at
|
|
5
|
+
* `~/repos/deepsuite-docs/apps/docs/docs` (api/create-chat-completion,
|
|
6
|
+
* guides/thinking_mode.mdx, guides/tool_calls.md), cross-checked against
|
|
7
|
+
* live streams from the internal endpoint (2026-06).
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-llm-deepseek/types
|
|
10
|
+
*/
|
|
11
|
+
/** Request body for `POST {baseURL}/chat/completions`. */
|
|
12
|
+
export interface WireRequest {
|
|
13
|
+
model: string;
|
|
14
|
+
messages: WireMessage[];
|
|
15
|
+
stream: true;
|
|
16
|
+
stream_options: {
|
|
17
|
+
include_usage: true;
|
|
18
|
+
};
|
|
19
|
+
/** Thinking-mode toggle (top level, NOT inside extra_body on the wire). */
|
|
20
|
+
thinking?: {
|
|
21
|
+
type: 'enabled' | 'disabled';
|
|
22
|
+
};
|
|
23
|
+
/** Thinking effort (official levels; low/medium map to high server-side). */
|
|
24
|
+
reasoning_effort?: 'high' | 'max';
|
|
25
|
+
tools?: WireTool[];
|
|
26
|
+
temperature?: number;
|
|
27
|
+
max_tokens?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Stop sequences (OpenAI `stop`): generation halts as soon as the model
|
|
30
|
+
* produces any one of these strings. Mapped from `GenerateOptions.stop`.
|
|
31
|
+
*/
|
|
32
|
+
stop?: string[];
|
|
33
|
+
}
|
|
34
|
+
/** System-role message: a single string of instructions. */
|
|
35
|
+
export interface WireSystemMessage {
|
|
36
|
+
role: 'system';
|
|
37
|
+
content: string;
|
|
38
|
+
}
|
|
39
|
+
/** User-role message: a single string of user input. */
|
|
40
|
+
export interface WireUserMessage {
|
|
41
|
+
role: 'user';
|
|
42
|
+
content: string;
|
|
43
|
+
}
|
|
44
|
+
/** Tool-role message: the result of one tool call, keyed by its call id. */
|
|
45
|
+
export interface WireToolMessage {
|
|
46
|
+
role: 'tool';
|
|
47
|
+
tool_call_id: string;
|
|
48
|
+
content: string;
|
|
49
|
+
}
|
|
50
|
+
/** One entry of the request `messages` array, discriminated on `role`. */
|
|
51
|
+
export type WireMessage = WireSystemMessage | WireUserMessage | WireAssistantMessage | WireToolMessage;
|
|
52
|
+
/**
|
|
53
|
+
* Assistant-role history message. The harness replays `content: ""` (never
|
|
54
|
+
* null) on tool-call-only turns — some gateways reject null — and sends null
|
|
55
|
+
* only when the turn carried neither text nor tool calls.
|
|
56
|
+
*/
|
|
57
|
+
export interface WireAssistantMessage {
|
|
58
|
+
role: 'assistant';
|
|
59
|
+
content: string | null;
|
|
60
|
+
/**
|
|
61
|
+
* CoT passback. REQUIRED on assistant turns that carried tool calls
|
|
62
|
+
* (thinking mode); ignored on tool-call-free turns (we omit it there to
|
|
63
|
+
* save tokens). See guides/thinking_mode.mdx § Tool Calls.
|
|
64
|
+
*/
|
|
65
|
+
reasoning_content?: string;
|
|
66
|
+
tool_calls?: WireToolCall[];
|
|
67
|
+
}
|
|
68
|
+
/** A completed tool call replayed on an assistant history message; `arguments` is the raw JSON string. */
|
|
69
|
+
export interface WireToolCall {
|
|
70
|
+
id: string;
|
|
71
|
+
type: 'function';
|
|
72
|
+
function: {
|
|
73
|
+
name: string;
|
|
74
|
+
arguments: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** One entry of the request `tools` array; `parameters` is a JSON Schema object. */
|
|
78
|
+
export interface WireTool {
|
|
79
|
+
type: 'function';
|
|
80
|
+
function: {
|
|
81
|
+
name: string;
|
|
82
|
+
description: string;
|
|
83
|
+
parameters: Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** One parsed SSE `data:` payload (a chat.completion.chunk). */
|
|
87
|
+
export interface WireChunk {
|
|
88
|
+
choices?: WireChoice[];
|
|
89
|
+
/** Arrives attached to the finish chunk and/or as a trailing usage-only chunk. */
|
|
90
|
+
usage?: WireUsage | null;
|
|
91
|
+
}
|
|
92
|
+
/** One streamed choice (requests always ask for a single one); `finish_reason` is non-null only on its terminal chunk. */
|
|
93
|
+
export interface WireChoice {
|
|
94
|
+
delta?: WireDelta;
|
|
95
|
+
finish_reason?: string | null;
|
|
96
|
+
}
|
|
97
|
+
/** The incremental content of one streamed choice; any subset of fields may be present per chunk. */
|
|
98
|
+
export interface WireDelta {
|
|
99
|
+
role?: string;
|
|
100
|
+
/** Visible text. Null/empty on reasoning/tool-call chunks. */
|
|
101
|
+
content?: string | null;
|
|
102
|
+
/**
|
|
103
|
+
* Thinking-mode CoT. The FIRST chunk carries an empty string (must not
|
|
104
|
+
* open a reasoning block); absent entirely in non-thinking mode.
|
|
105
|
+
*/
|
|
106
|
+
reasoning_content?: string | null;
|
|
107
|
+
tool_calls?: WireToolCallDelta[];
|
|
108
|
+
}
|
|
109
|
+
/** A streamed fragment of one tool call; fragments sharing an `index` concatenate into one call. */
|
|
110
|
+
export interface WireToolCallDelta {
|
|
111
|
+
/** Disambiguates parallel tool calls; stable across a call's deltas. */
|
|
112
|
+
index: number;
|
|
113
|
+
/** Present on the first delta of each call only. */
|
|
114
|
+
id?: string;
|
|
115
|
+
type?: 'function';
|
|
116
|
+
function?: {
|
|
117
|
+
/** Present on the first delta of each call only. */
|
|
118
|
+
name?: string;
|
|
119
|
+
/** Argument JSON fragment (concatenate across deltas). */
|
|
120
|
+
arguments?: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Wire token accounting. `prompt_tokens` INCLUDES cache hits (it equals
|
|
125
|
+
* `prompt_cache_hit_tokens + prompt_cache_miss_tokens`); `mapUsage` subtracts
|
|
126
|
+
* them to keep the harness convention of disjoint counts.
|
|
127
|
+
* `prompt_tokens_details.cached_tokens` is the OpenAI-compat spelling of the
|
|
128
|
+
* hit count.
|
|
129
|
+
*/
|
|
130
|
+
export interface WireUsage {
|
|
131
|
+
prompt_tokens: number;
|
|
132
|
+
completion_tokens: number;
|
|
133
|
+
prompt_cache_hit_tokens?: number;
|
|
134
|
+
prompt_cache_miss_tokens?: number;
|
|
135
|
+
prompt_tokens_details?: {
|
|
136
|
+
cached_tokens?: number;
|
|
137
|
+
};
|
|
138
|
+
completion_tokens_details?: {
|
|
139
|
+
reasoning_tokens?: number;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** Non-2xx error body. */
|
|
143
|
+
export interface WireError {
|
|
144
|
+
error?: {
|
|
145
|
+
message?: string;
|
|
146
|
+
type?: string;
|
|
147
|
+
code?: string;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=types.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stackstackstack/dsh-llm-deepseek",
|
|
3
|
+
"description": "DeepSeek chat-completions adapter for the DeepSeek Harness LLM seam",
|
|
4
|
+
"version": "0.1.5",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/llm/llm-deepseek"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@stackstackstack/dsh-credentials": "^0.1.5",
|
|
36
|
+
"@stackstackstack/dsh-llm": "^0.1.5",
|
|
37
|
+
"@stackstackstack/dsh-invariants": "^0.1.5",
|
|
38
|
+
"@stackstackstack/dsh-timeout": "^0.1.5",
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
40
|
+
"@stackstackstack/dsh-settings": "^0.1.5",
|
|
41
|
+
"@stackstackstack/dsh-launch-environment": "^0.1.5",
|
|
42
|
+
"@stackstackstack/dsh-anonymous-user-id": "^0.1.5"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"eventsource-parser": "^3.1.0",
|
|
46
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@stackstackstack/dsh-credentials": "^0.1.5",
|
|
50
|
+
"@stackstackstack/dsh-launch-environment": "^0.1.5",
|
|
51
|
+
"@stackstackstack/dsh-settings": "^0.1.5",
|
|
52
|
+
"@stackstackstack/dsh-llm": "^0.1.5",
|
|
53
|
+
"@stackstackstack/dsh-invariants": "^0.1.5",
|
|
54
|
+
"@stackstackstack/dsh-anonymous-user-id": "^0.1.5",
|
|
55
|
+
"@stackstackstack/dsh-timeout": "^0.1.5",
|
|
56
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
57
|
+
}
|
|
58
|
+
}
|