@siliconflow-official/dsh-llm-siliconflow 0.1.0-rc.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.
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Register a {@link SiliconFlowAdapter} for the `siliconflow` provider route
3
+ * on `ctx.llm`, with connection facts resolved per request instead of frozen
4
+ * at load: the plugin layers its `cordis.yml` entry config under the optional
5
+ * `llm-siliconflow` user-settings section (`ctx.settings`) and resolves the
6
+ * API key through the optional credential seam (`ctx.credentials`), so a
7
+ * changed base URL, catalog, or key reaches the very next request without
8
+ * restarting anything, while an in-flight stream keeps the facts it started
9
+ * with. The one registration-captured fact — the retry policy — re-registers
10
+ * the route in place when it changes.
11
+ * @module @siliconflow-official/dsh-llm-siliconflow
12
+ */
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import z from '@deepseek-ai/schemastery';
15
+ import type { RetryPolicyConfig } from '@deepseek-ai/dsh-llm';
16
+ import { type LaunchEnvironmentSnapshot } from '@deepseek-ai/dsh-launch-environment';
17
+ import type { SiliconFlowCatalogModel, SiliconFlowConnectionOptions } from './adapter.ts';
18
+ export { DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DISCOVERY_TTL_MS, SiliconFlowAdapter, } from './adapter.ts';
19
+ export { discoverChatModels, listingUrl, readListing } from './discovery.ts';
20
+ export type { SiliconFlowListingEntry } from './discovery.ts';
21
+ export type { SiliconFlowAdapterOptions, SiliconFlowCatalogModel, SiliconFlowConnectionOptions } from './adapter.ts';
22
+ export type * from './types.ts';
23
+ export declare const name = "llm-siliconflow";
24
+ export declare const inject: string[];
25
+ /** Credential reference this plugin reads by default, also used by the setup CLI. */
26
+ export declare const DEFAULT_API_KEY_ENV = "SILICONFLOW_API_KEY";
27
+ /** The single provider route this plugin owns. */
28
+ export declare const PROVIDER = "siliconflow";
29
+ /** Fallback advisory catalog: six widely hosted chat models, also the setup CLI's discovery fallback. */
30
+ export declare const DEFAULT_MODELS: SiliconFlowCatalogModel[];
31
+ /**
32
+ * Plugin config, validated by the same-named schemastery schema and doubling
33
+ * as the `llm-siliconflow` settings-section shape. Every field is optional in
34
+ * yml: a missing API key resolves through {@link Config.apiKeyEnv} at each
35
+ * request (a request without any key fails with `MISSING_CREDENTIAL`, not at
36
+ * plugin load).
37
+ */
38
+ export interface Config {
39
+ /** Credential reference (environment-variable name) resolved per request; defaults to `SILICONFLOW_API_KEY`. */
40
+ apiKeyEnv?: string;
41
+ /** Endpoint base; falls back to $SILICONFLOW_BASE_URL from a trusted environment layer, then the public API. */
42
+ baseURL?: string;
43
+ /** Default per-request output cap (default 8,192); a model's own cap and explicit request values win. */
44
+ maxTokens?: number;
45
+ /** Positive context capacity used when the selected model has no exact value (default 32,768). */
46
+ defaultContextWindow?: number;
47
+ /** Advisory models shown by discovery consumers; defaults to six widely hosted models. */
48
+ models?: SiliconFlowCatalogModel[];
49
+ /** Maximum provider idle time while one stream read is outstanding (default five minutes). */
50
+ streamIdleTimeoutMs?: number;
51
+ /** Provider-owned model-request retry policy; omission uses normal defaults. */
52
+ retryPolicy?: RetryPolicyConfig;
53
+ }
54
+ export declare const Config: z<Config>;
55
+ /** Public API default; the internal endpoint comes from $SILICONFLOW_BASE_URL. */
56
+ export declare const PUBLIC_BASE_URL = "https://api.siliconflow.cn/v1";
57
+ /**
58
+ * One resolution's complete request facts. Connection and credential facts
59
+ * are one value on purpose: a snapshot the resolver rejects keeps the whole
60
+ * previous generation, so a request can never pair a stale endpoint with a
61
+ * newer key.
62
+ */
63
+ export type ResolvedSiliconFlowOptions = SiliconFlowConnectionOptions;
64
+ /**
65
+ * The one explicit resolve step from raw config to validated connection
66
+ * facts. Programmatic construction may bypass Schemastery normalization, so
67
+ * every default and bound is re-judged here — for the composition entry at
68
+ * load (fail loud) and for each settings snapshot at its first use.
69
+ * @param config - raw plugin config or resolved settings snapshot.
70
+ * @param environment - this run's environment layers, or `undefined` outside
71
+ * the product CLI. Every layer may supply an endpoint: the product trusts the
72
+ * project it is launched in, so a checkout can point its own agent at the
73
+ * gateway that checkout is meant to use.
74
+ * @returns validated connection facts plus the credential reference.
75
+ */
76
+ export declare function resolveAdapterOptions(config: Config, environment?: LaunchEnvironmentSnapshot): ResolvedSiliconFlowOptions;
77
+ export declare function apply(ctx: Context, config: Config): void;
78
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@siliconflow-official/dsh-llm-siliconflow`.
3
+ * @module @siliconflow-official/dsh-llm-siliconflow/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "llm-siliconflow-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,30 @@
1
+ /**
2
+ * Serialize harness messages into SiliconFlow chat completions. User text is
3
+ * joined; assistant text becomes `content`, tool calls become `tool_calls`,
4
+ * and tool results become separate tool messages. Assistant reasoning is
5
+ * replayed as `reasoning_content` only on tool-call turns, as hosted reasoning
6
+ * models (DeepSeek-R1 and siblings) require. Core image blocks are rejected
7
+ * explicitly because this wire route is text-only; unknown declaration-merged
8
+ * block types retain the adapter's documented extension fallback.
9
+ * @module dsh-llm-siliconflow/serialize
10
+ */
11
+ import type { GenerateOptions, Message } from '@deepseek-ai/dsh-llm';
12
+ import type { WireMessage, WireRequest } from './types.ts';
13
+ /**
14
+ * Serialize the conversation. `tool-result` blocks become standalone
15
+ * `{role: 'tool'}` messages; the harness puts each tool result in its own
16
+ * user-role message, so a mixed user message contributes its text first and
17
+ * its tool results as separate wire messages after.
18
+ * @param messages - the harness conversation, in order.
19
+ * @returns the wire messages; order preserved, each tool result expanded into its own entry.
20
+ */
21
+ export declare function serializeMessages(messages: Message[]): WireMessage[];
22
+ /**
23
+ * Build the full wire request. Always streaming (`stream: true`, usage
24
+ * reporting on); optional fields are omitted rather than sent as null, so
25
+ * provider defaults apply.
26
+ * @param options - the harness request (model, history, system, tools, sampling).
27
+ * @returns the chat-completions request body.
28
+ */
29
+ export declare function serializeRequest(options: GenerateOptions): WireRequest;
30
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Interactive setup wizard core for {@link @siliconflow-official/dsh-llm-siliconflow}:
3
+ * the pure steps (harness-home and document-path resolution, credential and
4
+ * settings read/write, model-choice parsing) plus the orchestration over an
5
+ * injected I/O face, so the thin bin entry stays untested glue and the whole
6
+ * flow is unit-testable without a terminal.
7
+ *
8
+ * The wizard guides a fresh install to a working route: confirm the default
9
+ * channel, obtain an API key, interrogate the live chat-model listing, pick a
10
+ * default model, then persist `agent-default-model` into `settings.yaml`.
11
+ * @module @siliconflow-official/dsh-llm-siliconflow/setup
12
+ */
13
+ import type { SiliconFlowListingEntry } from './discovery.ts';
14
+ /** Directory name for the default DeepSeek Harness home under the OS home. */
15
+ export declare const DSH_HOME_DIR_NAME = ".dsh";
16
+ /** Environment variable that overrides the default DeepSeek Harness home. */
17
+ export declare const DSH_HOME_ENV = "DSH_HOME";
18
+ /** Settings namespace the wizard writes the default model into. */
19
+ export declare const DEFAULT_MODEL_NAMESPACE = "agent-default-model";
20
+ /** One model row the wizard offers, independent of the discovery source. */
21
+ export interface SetupModel {
22
+ /** Provider-owned model id, exactly as written to `agent-default-model`. */
23
+ id: string;
24
+ /** Optional display name; falls back to the id. */
25
+ name?: string;
26
+ }
27
+ /** Minimal terminal face the wizard talks through. */
28
+ export interface SetupIo {
29
+ /** Ask one question and resolve with the trimmed-free answer. */
30
+ question(prompt: string): Promise<string>;
31
+ /** Print one line of wizard progress. */
32
+ log(message: string): void;
33
+ }
34
+ /** Injected dependencies keeping the wizard testable and network-agnostic. */
35
+ export interface SetupDeps {
36
+ /** Resolved harness home (`settings.yaml` and `.credentials.yaml` live here). */
37
+ home: string;
38
+ /** The terminal face. */
39
+ io: SetupIo;
40
+ /** Live chat-model listing; the wizard falls back to the static catalog on rejection. */
41
+ discover: (apiKey: string | undefined) => Promise<readonly SiliconFlowListingEntry[]>;
42
+ }
43
+ /** A persisted default-model selection. */
44
+ export interface DefaultModelSelection {
45
+ provider: string;
46
+ model: string;
47
+ }
48
+ /**
49
+ * Resolve the DeepSeek Harness home: non-empty `$DSH_HOME`, else `~/.dsh`.
50
+ * @param env - environment mapping; defaults to `process.env`.
51
+ * @returns the normalized absolute home path.
52
+ */
53
+ export declare function resolveHome(env?: Record<string, string | undefined>): string;
54
+ /** The managed credential document path under a harness home. */
55
+ export declare function credentialsPath(home: string): string;
56
+ /** The settings document path under a harness home. */
57
+ export declare function settingsPath(home: string): string;
58
+ /**
59
+ * Read one credential reference from a comment-preserving document.
60
+ * @param path - the credentials document path.
61
+ * @param keyEnv - the top-level reference name (e.g. `SILICONFLOW_API_KEY`).
62
+ * @returns the stored value, or `undefined` when absent or the file is missing.
63
+ */
64
+ export declare function readCredential(path: string, keyEnv: string): Promise<string | undefined>;
65
+ /**
66
+ * Set one credential reference, preserving every other entry and comment.
67
+ * @param path - the credentials document path; created when absent.
68
+ * @param keyEnv - the top-level reference name to write.
69
+ * @param key - the value.
70
+ */
71
+ export declare function writeCredential(path: string, keyEnv: string, key: string): Promise<void>;
72
+ /**
73
+ * Read the persisted default-model selection, if the section is a complete
74
+ * `{provider, model}` map.
75
+ * @param path - the settings document path.
76
+ * @returns the selection, or `undefined` when absent or incomplete.
77
+ */
78
+ export declare function readDefaultModel(path: string): Promise<DefaultModelSelection | undefined>;
79
+ /**
80
+ * Replace the default-model section, preserving every other section and comment.
81
+ * The replacement carries only `provider` and `model`, so a previous
82
+ * `reasoningEffort` (unsupported by SiliconFlow) is dropped with the section.
83
+ * @param path - the settings document path; created when absent.
84
+ * @param selection - the provider/model pair to persist.
85
+ */
86
+ export declare function writeDefaultModel(path: string, selection: DefaultModelSelection): Promise<void>;
87
+ /**
88
+ * Parse a 1-based model-choice answer.
89
+ * @param raw - the user's answer.
90
+ * @param count - the number of offered models.
91
+ * @returns the 0-based index, or `undefined` when the answer is out of range.
92
+ */
93
+ export declare function parseModelIndex(raw: string, count: number): number | undefined;
94
+ /**
95
+ * Run the wizard: confirm the default channel, obtain a key, list models,
96
+ * pick the default, and persist the selection. Never throws for an unroutable
97
+ * endpoint — discovery falls back to the static catalog — but a malformed
98
+ * existing document or an unwritable one fails loud.
99
+ * @param deps - home, terminal face, and discovery function.
100
+ */
101
+ export declare function runSetup(deps: SetupDeps): Promise<void>;
102
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1,25 @@
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
+ * SiliconFlow (OpenAI-compatible) protocol: the literal `[DONE]` is yielded so
7
+ * the caller owns final flushing, and EOF before it raises {@link LlmError}.
8
+ * Framing is spec-strict: an event dispatches only on its blank-line
9
+ * terminator, so an unterminated tail at EOF is truncation, not a flushable
10
+ * payload.
11
+ *
12
+ * @module dsh-llm-siliconflow/sse
13
+ */
14
+ /** The terminal payload SiliconFlow (and OpenAI) send after the last chunk. */
15
+ export declare const DONE = "[DONE]";
16
+ /**
17
+ * Parse an SSE byte stream into data payloads. Yields `[DONE]` as the final
18
+ * value and returns; throws `LlmError('STREAM_CLOSED')` when the stream ends
19
+ * without it (truncated response — the model call cannot be trusted).
20
+ * @param stream - raw SSE bytes; reads may split anywhere, including mid-UTF-8 sequence.
21
+ * @param onComment - optional transport-activity callback; comments never enter the yielded payload stream.
22
+ * @returns each event's data payload in arrival order, the `[DONE]` sentinel last.
23
+ */
24
+ export declare function parseSse(stream: ReadableStream<BufferSource>, onComment?: (comment: string) => void): AsyncGenerator<string>;
25
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Translate SiliconFlow SSE payloads with one stateful harness block per
3
+ * content, reasoning, or tool-call index. An empty initial reasoning delta
4
+ * does not open a block. Finish reason and the latest usage are deferred until
5
+ * `[DONE]`, covering both finish-attached and trailing usage-only shapes while
6
+ * ensuring no chunk follows `finish`.
7
+ *
8
+ * Translate SiliconFlow wire chunks into the harness `StreamChunk` protocol.
9
+ * @module dsh-llm-siliconflow/translate
10
+ */
11
+ import type { FinishReason, StreamChunk, TokenUsage } from '@deepseek-ai/dsh-llm';
12
+ import type { WireUsage } from './types.ts';
13
+ /**
14
+ * Map the wire finish_reason vocabulary to the harness FinishReason.
15
+ * @param reason - the wire `finish_reason` string.
16
+ * @returns the mapped reason; unrecognized values (content_filter, …) become `{kind: 'error'}` with the uppercased value as `code`.
17
+ */
18
+ export declare function mapFinishReason(reason: string): FinishReason;
19
+ /**
20
+ * Map wire usage fields. SiliconFlow's `prompt_tokens` INCLUDES cache hits
21
+ * (`prompt_tokens = prompt_cache_hit_tokens + prompt_cache_miss_tokens`); the
22
+ * harness TokenUsage convention is DISJOINT counts, so cache reads are
23
+ * subtracted out of `inputTokens`.
24
+ * @param usage - wire usage from the finish chunk or the trailing usage-only chunk.
25
+ * @returns disjoint harness counts; cache/reasoning fields present only when the wire reported them.
26
+ */
27
+ export declare function mapUsage(usage: WireUsage): TokenUsage;
28
+ /**
29
+ * Consume SSE data payloads (ending with `[DONE]`) and yield StreamChunks.
30
+ * Malformed JSON payloads abort the stream with `MALFORMED_RESPONSE`.
31
+ * @param payloads - SSE data payloads from {@link parseSse}, `[DONE]`-terminated.
32
+ * @returns deltas as they arrive; `block-end`s, `usage`, and `finish` are all deferred to the `[DONE]` sentinel.
33
+ * A `stop` (or absent) finish with no opened blocks is a degenerate provider completion and maps to an
34
+ * `EMPTY_RESPONSE` error finish instead of a successful empty message.
35
+ */
36
+ export declare function translate(payloads: AsyncIterable<string>): AsyncGenerator<StreamChunk>;
37
+ //# sourceMappingURL=translate.d.ts.map
@@ -0,0 +1,145 @@
1
+ /**
2
+ * SiliconFlow chat-completions wire format (OpenAI-compatible). Types only.
3
+ *
4
+ * Source of truth: the SiliconFlow API docs at https://docs.siliconflow.cn
5
+ * (chat completions), cross-checked against live streams. SiliconFlow hosts
6
+ * reasoning models (DeepSeek-R1, QwQ, Kimi-K2-Thinking, …) whose deltas carry
7
+ * `reasoning_content` exactly like the upstream DeepSeek-R1 wire shape, so the
8
+ * assistant history type keeps that passback field for tool-call turns.
9
+ *
10
+ * @module dsh-llm-siliconflow/types
11
+ */
12
+ /** Request body for `POST {baseURL}/chat/completions`. */
13
+ export interface WireRequest {
14
+ model: string;
15
+ messages: WireMessage[];
16
+ stream: true;
17
+ stream_options: {
18
+ include_usage: true;
19
+ };
20
+ tools?: WireTool[];
21
+ temperature?: number;
22
+ max_tokens?: number;
23
+ /**
24
+ * Stop sequences (OpenAI `stop`): generation halts as soon as the model
25
+ * produces any one of these strings. Mapped from `GenerateOptions.stop`.
26
+ */
27
+ stop?: string[];
28
+ }
29
+ /** System-role message: a single string of instructions. */
30
+ export interface WireSystemMessage {
31
+ role: 'system';
32
+ content: string;
33
+ }
34
+ /** User-role message: a single string of user input. */
35
+ export interface WireUserMessage {
36
+ role: 'user';
37
+ content: string;
38
+ }
39
+ /** Tool-role message: the result of one tool call, keyed by its call id. */
40
+ export interface WireToolMessage {
41
+ role: 'tool';
42
+ tool_call_id: string;
43
+ content: string;
44
+ }
45
+ /** One entry of the request `messages` array, discriminated on `role`. */
46
+ export type WireMessage = WireSystemMessage | WireUserMessage | WireAssistantMessage | WireToolMessage;
47
+ /**
48
+ * Assistant-role history message. The harness replays `content: ""` (never
49
+ * null) on tool-call-only turns — some gateways reject null — and sends null
50
+ * only when the turn carried neither text nor tool calls.
51
+ */
52
+ export interface WireAssistantMessage {
53
+ role: 'assistant';
54
+ content: string | null;
55
+ /**
56
+ * CoT passback for hosted reasoning models (DeepSeek-R1 and siblings).
57
+ * Required on assistant turns that carried tool calls; ignored on
58
+ * tool-call-free turns (omitted there to save tokens).
59
+ */
60
+ reasoning_content?: string;
61
+ tool_calls?: WireToolCall[];
62
+ }
63
+ /** A completed tool call replayed on an assistant history message; `arguments` is the raw JSON string. */
64
+ export interface WireToolCall {
65
+ id: string;
66
+ type: 'function';
67
+ function: {
68
+ name: string;
69
+ arguments: string;
70
+ };
71
+ }
72
+ /** One entry of the request `tools` array; `parameters` is a JSON Schema object. */
73
+ export interface WireTool {
74
+ type: 'function';
75
+ function: {
76
+ name: string;
77
+ description: string;
78
+ parameters: Record<string, unknown>;
79
+ };
80
+ }
81
+ /** One parsed SSE `data:` payload (a chat.completion.chunk). */
82
+ export interface WireChunk {
83
+ choices?: WireChoice[];
84
+ /** Arrives attached to the finish chunk and/or as a trailing usage-only chunk. */
85
+ usage?: WireUsage | null;
86
+ }
87
+ /** One streamed choice (requests always ask for a single one); `finish_reason` is non-null only on its terminal chunk. */
88
+ export interface WireChoice {
89
+ delta?: WireDelta;
90
+ finish_reason?: string | null;
91
+ }
92
+ /** The incremental content of one streamed choice; any subset of fields may be present per chunk. */
93
+ export interface WireDelta {
94
+ role?: string;
95
+ /** Visible text. Null/empty on reasoning/tool-call chunks. */
96
+ content?: string | null;
97
+ /**
98
+ * Reasoning-model CoT. The FIRST chunk carries an empty string (must not
99
+ * open a reasoning block); absent entirely on non-reasoning models.
100
+ */
101
+ reasoning_content?: string | null;
102
+ tool_calls?: WireToolCallDelta[];
103
+ }
104
+ /** A streamed fragment of one tool call; fragments sharing an `index` concatenate into one call. */
105
+ export interface WireToolCallDelta {
106
+ /** Disambiguates parallel tool calls; stable across a call's deltas. */
107
+ index: number;
108
+ /** Present on the first delta of each call only. */
109
+ id?: string;
110
+ type?: 'function';
111
+ function?: {
112
+ /** Present on the first delta of each call only. */
113
+ name?: string;
114
+ /** Argument JSON fragment (concatenate across deltas). */
115
+ arguments?: string;
116
+ };
117
+ }
118
+ /**
119
+ * Wire token accounting. `prompt_tokens` INCLUDES cache hits (it equals
120
+ * `prompt_cache_hit_tokens + prompt_cache_miss_tokens`); `mapUsage` subtracts
121
+ * them to keep the harness convention of disjoint counts.
122
+ * `prompt_tokens_details.cached_tokens` is the OpenAI-compat spelling of the
123
+ * hit count.
124
+ */
125
+ export interface WireUsage {
126
+ prompt_tokens: number;
127
+ completion_tokens: number;
128
+ prompt_cache_hit_tokens?: number;
129
+ prompt_cache_miss_tokens?: number;
130
+ prompt_tokens_details?: {
131
+ cached_tokens?: number;
132
+ };
133
+ completion_tokens_details?: {
134
+ reasoning_tokens?: number;
135
+ };
136
+ }
137
+ /** Non-2xx error body. */
138
+ export interface WireError {
139
+ error?: {
140
+ message?: string;
141
+ type?: string;
142
+ code?: string;
143
+ };
144
+ }
145
+ //# sourceMappingURL=types.d.ts.map