@lihuu/dsh-ollama-cloud 0.1.0
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/README.md +70 -0
- package/cordis.patch.yml +8 -0
- package/dist/index.js +837 -0
- package/lib/adapter.d.ts +111 -0
- package/lib/index.d.ts +62 -0
- package/lib/serialize.d.ts +44 -0
- package/lib/sse.d.ts +23 -0
- package/lib/translate.d.ts +32 -0
- package/lib/types.d.ts +143 -0
- package/package.json +52 -0
- package/src/adapter.ts +423 -0
- package/src/index.ts +214 -0
- package/src/serialize.ts +215 -0
- package/src/sse.ts +40 -0
- package/src/translate.ts +182 -0
- package/src/types.ts +148 -0
package/lib/adapter.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OllamaAdapter`: fetch + SSE against an Ollama (OpenAI-compatible)
|
|
3
|
+
* chat-completions endpoint, emitting harness StreamChunks. Transport-only:
|
|
4
|
+
* connection facts arrive through a thunk resolved once per operation and the
|
|
5
|
+
* bearer token through a per-request resolver.
|
|
6
|
+
*
|
|
7
|
+
* Model ids are normalized to Ollama's `:cloud` naming on every operation: a
|
|
8
|
+
* request for `deepseek-v4-flash` is sent as `deepseek-v4-flash:cloud`, and an
|
|
9
|
+
* already-suffixed id is forwarded unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Dependencies are intentionally minimal: `@deepseek-ai/dsh-llm` (the harness
|
|
12
|
+
* LLM seam contract), `@deepseek-ai/cordis` (plugin framework), and
|
|
13
|
+
* `eventsource-parser` (SSE framing). Everything else is hand-rolled here.
|
|
14
|
+
*
|
|
15
|
+
* @module llm-ollama-cloud/adapter
|
|
16
|
+
*/
|
|
17
|
+
import { LlmAdapter } from '@deepseek-ai/dsh-llm';
|
|
18
|
+
import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, ModelModality, ResolvedRetryPolicy, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
19
|
+
import type { RequestDefaults } from './serialize.ts';
|
|
20
|
+
import type { WireError } from './types.ts';
|
|
21
|
+
/** One optional model entry advertised by the direct-fetch adapter. */
|
|
22
|
+
export interface OllamaCatalogModel {
|
|
23
|
+
/** Wire model id accepted by the configured endpoint; a missing `:cloud` suffix is appended. */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Selector label; defaults to {@link id}. */
|
|
26
|
+
name?: string;
|
|
27
|
+
/** Optional selector detail for deployments with similar model variants. */
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Known combined request/response context capacity; omitted when deployment metadata is unavailable. */
|
|
30
|
+
contextWindow?: number;
|
|
31
|
+
/** Per-request output cap for this model; omission falls back to the profile's {@link OllamaConnectionOptions.maxTokens}. */
|
|
32
|
+
maxTokens?: number;
|
|
33
|
+
/** Accepted request modalities; omission is text-only. */
|
|
34
|
+
inputModalities?: ModelModality[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validated connection facts for one operation. The plugin's
|
|
38
|
+
* `resolveAdapterOptions` is the one explicit resolve step producing this
|
|
39
|
+
* shape; the adapter trusts it and re-reads it per operation.
|
|
40
|
+
*/
|
|
41
|
+
export interface OllamaConnectionOptions {
|
|
42
|
+
/** Endpoint base; `/chat/completions` is appended. */
|
|
43
|
+
baseURL: string;
|
|
44
|
+
/** Environment-variable name holding the bearer token, resolved per request. */
|
|
45
|
+
apiKeyEnv: string;
|
|
46
|
+
/** Request defaults applied to every call (thinking mode, effort). */
|
|
47
|
+
defaults: RequestDefaults;
|
|
48
|
+
/** Default per-request output cap; explicit request values win. */
|
|
49
|
+
maxTokens: number;
|
|
50
|
+
/** Positive context capacity used when the selected model has no exact value. */
|
|
51
|
+
defaultContextWindow: number;
|
|
52
|
+
/** Advisory models exposed to discovery consumers; requests remain unrestricted. */
|
|
53
|
+
models: readonly OllamaCatalogModel[];
|
|
54
|
+
/** Maximum provider idle time while one stream read is outstanding. */
|
|
55
|
+
streamIdleTimeoutMs: number;
|
|
56
|
+
/** Provider-owned model-request retry policy, already resolved. */
|
|
57
|
+
retryPolicy: ResolvedRetryPolicy;
|
|
58
|
+
}
|
|
59
|
+
/** Constructor options for {@link OllamaAdapter}: the operation-local resolution hooks the plugin owns. */
|
|
60
|
+
export interface OllamaAdapterOptions {
|
|
61
|
+
/** Current validated connection facts; called once per operation. */
|
|
62
|
+
options: () => OllamaConnectionOptions;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the bearer token for the connection facts of one request. The
|
|
65
|
+
* snapshot is passed in — never re-read — so the key can only ever come
|
|
66
|
+
* from the same resolution as the endpoint it is sent to.
|
|
67
|
+
*/
|
|
68
|
+
resolveApiKey: (connection: OllamaConnectionOptions) => Promise<string>;
|
|
69
|
+
}
|
|
70
|
+
/** Default maximum idle interval while an adapter stream read is outstanding. */
|
|
71
|
+
export declare const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
72
|
+
/** Default combined request/response context capacity. */
|
|
73
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 1000000;
|
|
74
|
+
/** Default per-request output-token cap. */
|
|
75
|
+
export declare const DEFAULT_MAX_TOKENS = 65536;
|
|
76
|
+
/** The Ollama cloud model-name suffix this adapter appends when missing. */
|
|
77
|
+
export declare const CLOUD_SUFFIX = ":cloud";
|
|
78
|
+
/** Largest value `setTimeout` accepts (2^31 - 1 ms). */
|
|
79
|
+
export declare const MAX_TIMER_DELAY_MS = 2147483647;
|
|
80
|
+
/**
|
|
81
|
+
* Normalize a model id to Ollama's cloud naming. An id already carrying the
|
|
82
|
+
* `:cloud` suffix is returned unchanged; any other id gets it appended. This
|
|
83
|
+
* is the one place a bare harness model name becomes a wire model name.
|
|
84
|
+
* @param model - the requested model id.
|
|
85
|
+
* @returns the id with a `:cloud` suffix.
|
|
86
|
+
*/
|
|
87
|
+
export declare function normalizeCloud(model: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Map an HTTP status to a stable LlmError code.
|
|
90
|
+
* @param status - status of a non-2xx provider response.
|
|
91
|
+
* @param error - parsed provider error body, when available.
|
|
92
|
+
* @returns the normalized harness error code.
|
|
93
|
+
*/
|
|
94
|
+
export declare function httpErrorCode(status: number, error?: WireError['error']): string;
|
|
95
|
+
/**
|
|
96
|
+
* One instance serves every model name it was registered under. The harness
|
|
97
|
+
* model name is normalized to its cloud form and IS the wire model name.
|
|
98
|
+
*
|
|
99
|
+
* One stable signal reaches both initial fetch and body reads. Caller aborts
|
|
100
|
+
* map to `ABORTED`; the configured per-read idle watchdog maps to `TIMEOUT`.
|
|
101
|
+
*/
|
|
102
|
+
export declare class OllamaAdapter extends LlmAdapter {
|
|
103
|
+
private readonly config;
|
|
104
|
+
constructor(config: OllamaAdapterOptions);
|
|
105
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
106
|
+
providerRetryPolicy(_provider: string): ResolvedRetryPolicy;
|
|
107
|
+
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
108
|
+
resolveModel(provider: string, model: string, _signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
109
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
110
|
+
private request;
|
|
111
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register an {@link OllamaAdapter} for the `ollama-cloud-direct` provider route
|
|
3
|
+
* on `ctx.llm`, with connection facts resolved once per operation from the
|
|
4
|
+
* plugin's `cordis.yml` mount config and the bearer token resolved per request
|
|
5
|
+
* through the credential seam (`ctx.credentials`), falling back to the
|
|
6
|
+
* process environment.
|
|
7
|
+
*
|
|
8
|
+
* Dependencies are intentionally minimal — `@deepseek-ai/dsh-llm` (the harness
|
|
9
|
+
* LLM seam contract), `@deepseek-ai/dsh-credentials` (the credential seam),
|
|
10
|
+
* `@deepseek-ai/cordis` (plugin framework), and `eventsource-parser` (SSE
|
|
11
|
+
* framing). There is no settings-section wiring and no schema library:
|
|
12
|
+
* configuration is static from the mount, and validation is hand-rolled. The
|
|
13
|
+
* route is `ollama-cloud-direct` (not `ollama-cloud`) so it can coexist with a
|
|
14
|
+
* pi-ai-configured `ollama-cloud` route.
|
|
15
|
+
*
|
|
16
|
+
* @module llm-ollama-cloud
|
|
17
|
+
*/
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import type { RetryPolicyConfig } from '@deepseek-ai/dsh-llm';
|
|
20
|
+
import type { OllamaCatalogModel, OllamaConnectionOptions } from './adapter.ts';
|
|
21
|
+
export { DEFAULT_CONTEXT_WINDOW, DEFAULT_MAX_TOKENS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, MAX_TIMER_DELAY_MS, normalizeCloud, OllamaAdapter, } from './adapter.ts';
|
|
22
|
+
export type { OllamaAdapterOptions, OllamaCatalogModel, OllamaConnectionOptions } from './adapter.ts';
|
|
23
|
+
export type { RequestDefaults } from './serialize.ts';
|
|
24
|
+
export type * from './types.ts';
|
|
25
|
+
export declare const name = "llm-ollama-cloud";
|
|
26
|
+
export declare const inject: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Plugin config from the `cordis.yml` mount entry. Every field is optional: a
|
|
29
|
+
* missing API key fails per request with `MISSING_CREDENTIAL`, omitted
|
|
30
|
+
* thinking mode uses the provider default, and omitted reasoning effort lets
|
|
31
|
+
* the server auto-enable thinking at its default.
|
|
32
|
+
*/
|
|
33
|
+
export interface Config {
|
|
34
|
+
/** Environment-variable name resolved per request; defaults to `OLLAMA_CLOUD_API_KEY`. */
|
|
35
|
+
apiKeyEnv?: string;
|
|
36
|
+
/** Endpoint base; defaults to the Ollama cloud API. */
|
|
37
|
+
baseURL?: string;
|
|
38
|
+
/** Deployment thinking policy; `disabled` limits every conversation request to `none` effort. */
|
|
39
|
+
thinking?: 'enabled' | 'disabled';
|
|
40
|
+
/** Default thinking effort (default unset, so the server picks); `off` maps to wire `none`. */
|
|
41
|
+
reasoningEffort?: 'off' | 'low' | 'high' | 'max';
|
|
42
|
+
/** Default per-request output cap (default 65,536); a model's own cap and explicit request values win. */
|
|
43
|
+
maxTokens?: number;
|
|
44
|
+
/** Positive context capacity used when the selected model has no exact value (default 1,000,000). */
|
|
45
|
+
defaultContextWindow?: number;
|
|
46
|
+
/** Advisory models shown by discovery consumers; a missing `:cloud` suffix is appended. */
|
|
47
|
+
models?: OllamaCatalogModel[];
|
|
48
|
+
/** Maximum provider idle time while one stream read is outstanding (default five minutes). */
|
|
49
|
+
streamIdleTimeoutMs?: number;
|
|
50
|
+
/** Provider-owned model-request retry policy; omission uses normal mode with five retries. */
|
|
51
|
+
retryPolicy?: RetryPolicyConfig;
|
|
52
|
+
}
|
|
53
|
+
/** The public Ollama cloud API base. */
|
|
54
|
+
export declare const PUBLIC_BASE_URL = "https://ollama.com/v1";
|
|
55
|
+
/**
|
|
56
|
+
* The one explicit resolve step from raw mount config to validated connection
|
|
57
|
+
* facts, with every default and bound re-judged here (fail loud at load).
|
|
58
|
+
* @param config - raw plugin config.
|
|
59
|
+
* @returns validated connection facts plus the credential reference.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveAdapterOptions(config: Config): OllamaConnectionOptions;
|
|
62
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize harness messages into an Ollama chat completions request.
|
|
3
|
+
* Text-only (the OpenAI-compatible endpoint's image path is deferred); tool
|
|
4
|
+
* results become standalone `role: 'tool'` messages. Reasoning is replayed as
|
|
5
|
+
* the `reasoning` assistant field only for reasoning-capable models (a wire id
|
|
6
|
+
* containing `deepseek`), so non-reasoning models keep clean traces.
|
|
7
|
+
* @module dsh-llm-ollama-cloud/serialize
|
|
8
|
+
*/
|
|
9
|
+
import type { GenerateOptions, Message } from '@deepseek-ai/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' | 'low' | 'high' | 'max' | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** The Ollama reasoning-effort values this adapter emits on the wire. */
|
|
17
|
+
export type WireReasoningEffort = 'none' | 'low' | 'high' | 'max';
|
|
18
|
+
/**
|
|
19
|
+
* Whether a model's reasoning should be passed back on assistant history.
|
|
20
|
+
* Only reasoning-capable models accept the `reasoning` field; a non-reasoning
|
|
21
|
+
* model ignores it, so it is written only for wire ids containing `deepseek`.
|
|
22
|
+
* @param model - the wire model id.
|
|
23
|
+
* @returns true when the model is treated as reasoning-capable.
|
|
24
|
+
*/
|
|
25
|
+
export declare function passReasoning(model: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Serialize the conversation. `tool-result` blocks become standalone
|
|
28
|
+
* `{role: 'tool'}` messages; the harness puts each tool result in its own
|
|
29
|
+
* user-role message, so a mixed user message contributes its text first and
|
|
30
|
+
* its tool results as separate wire messages after.
|
|
31
|
+
* @param model - the wire model id, used to decide reasoning passback.
|
|
32
|
+
* @param messages - the harness conversation, in order.
|
|
33
|
+
* @returns the wire messages; order preserved, each tool result expanded into its own entry.
|
|
34
|
+
*/
|
|
35
|
+
export declare function serializeMessages(model: string, messages: Message[]): WireMessage[];
|
|
36
|
+
/**
|
|
37
|
+
* Build the full wire request. Always streaming (`stream: true`, usage
|
|
38
|
+
* reporting on); optional fields are omitted rather than sent as null, so
|
|
39
|
+
* provider defaults apply.
|
|
40
|
+
* @param options - the harness request (model, history, system, tools, sampling).
|
|
41
|
+
* @param defaults - adapter-level thinking defaults; undefined fields put nothing on the wire.
|
|
42
|
+
* @returns the chat-completions request body.
|
|
43
|
+
*/
|
|
44
|
+
export declare function serializeRequest(options: GenerateOptions, defaults?: RequestDefaults): WireRequest;
|
package/lib/sse.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
* OpenAI-compatible protocol: the literal `[DONE]` is yielded so the caller
|
|
7
|
+
* owns final flushing, and EOF before it raises {@link LlmError}. Framing is
|
|
8
|
+
* spec-strict: an event dispatches only on its blank-line terminator, so an
|
|
9
|
+
* unterminated tail at EOF is truncation, not a flushable payload.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-llm-ollama-cloud/sse
|
|
12
|
+
*/
|
|
13
|
+
/** The terminal payload OpenAI-compatible endpoints 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>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate Ollama wire chunks into the harness `StreamChunk` protocol with
|
|
3
|
+
* one stateful harness block per content, reasoning, or tool call index. An
|
|
4
|
+
* empty initial reasoning delta does not open a block. Finish reason and the
|
|
5
|
+
* latest usage are deferred until `[DONE]`, covering both finish-attached and
|
|
6
|
+
* trailing usage-only shapes while ensuring no chunk follows `finish`.
|
|
7
|
+
* @module dsh-llm-ollama-cloud/translate
|
|
8
|
+
*/
|
|
9
|
+
import type { FinishReason, StreamChunk, TokenUsage } from '@deepseek-ai/dsh-llm';
|
|
10
|
+
import type { WireUsage } from './types.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Map the wire finish_reason vocabulary to the harness FinishReason.
|
|
13
|
+
* @param reason - the wire `finish_reason` string.
|
|
14
|
+
* @returns the mapped reason; unrecognized values (content_filter, …) become `{kind: 'error'}` with the uppercased value as `code`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function mapFinishReason(reason: string): FinishReason;
|
|
17
|
+
/**
|
|
18
|
+
* Map wire usage fields to the harness convention of DISJOINT counts. Cache
|
|
19
|
+
* hits and reasoning tokens are carried only when the wire reported them.
|
|
20
|
+
* @param usage - wire usage from the finish chunk or the trailing usage-only chunk.
|
|
21
|
+
* @returns disjoint harness counts; cache/reasoning fields present only when the wire reported them.
|
|
22
|
+
*/
|
|
23
|
+
export declare function mapUsage(usage: WireUsage): TokenUsage;
|
|
24
|
+
/**
|
|
25
|
+
* Consume SSE data payloads (ending with `[DONE]`) and yield StreamChunks.
|
|
26
|
+
* Malformed JSON payloads abort the stream with `MALFORMED_RESPONSE`.
|
|
27
|
+
* @param payloads - SSE data payloads from {@link parseSse}, `[DONE]`-terminated.
|
|
28
|
+
* @returns deltas as they arrive; `block-end`s, `usage`, and `finish` are all deferred to the `[DONE]` sentinel.
|
|
29
|
+
* A `stop` (or absent) finish with no opened blocks is a degenerate provider completion and maps to an
|
|
30
|
+
* `EMPTY_RESPONSE` error finish instead of a successful empty message.
|
|
31
|
+
*/
|
|
32
|
+
export declare function translate(payloads: AsyncIterable<string>): AsyncGenerator<StreamChunk>;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama chat-completions wire format (OpenAI-compatible). Types only.
|
|
3
|
+
*
|
|
4
|
+
* Source of truth: Ollama's OpenAI-compatible `/v1/chat/completions` endpoint
|
|
5
|
+
* (https://ollama.com) plus the empirical behaviour of local Ollama serving
|
|
6
|
+
* `deepseek-v4-flash:cloud` (2026-08). Reasoning reaches the model in the
|
|
7
|
+
* `reasoning` delta field (not `reasoning_content`), and reasoning effort is a
|
|
8
|
+
* single `reasoning_effort` value (`none`/`low`/`medium`/`high`/`max`) rather
|
|
9
|
+
* than a separate `thinking` toggle: omitting the field auto-enables thinking
|
|
10
|
+
* at the server default, while `none` disables it.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-llm-ollama-cloud/types
|
|
13
|
+
*/
|
|
14
|
+
/** Request body for `POST {baseURL}/chat/completions`. */
|
|
15
|
+
export interface WireRequest {
|
|
16
|
+
model: string;
|
|
17
|
+
messages: WireMessage[];
|
|
18
|
+
stream: true;
|
|
19
|
+
stream_options: {
|
|
20
|
+
include_usage: true;
|
|
21
|
+
};
|
|
22
|
+
/** Thinking effort; `none` disables reasoning and an omission uses the provider default. */
|
|
23
|
+
reasoning_effort?: 'none' | 'low' | 'medium' | 'high' | 'max';
|
|
24
|
+
tools?: WireTool[];
|
|
25
|
+
temperature?: number;
|
|
26
|
+
max_tokens?: number;
|
|
27
|
+
/** Stop sequences (OpenAI `stop`); generation halts as soon as the model produces one. */
|
|
28
|
+
stop?: string[];
|
|
29
|
+
}
|
|
30
|
+
/** System-role message: a single string of instructions. */
|
|
31
|
+
export interface WireSystemMessage {
|
|
32
|
+
role: 'system';
|
|
33
|
+
content: string;
|
|
34
|
+
}
|
|
35
|
+
/** User-role message; Ollama accepts a plain string for text-only input. */
|
|
36
|
+
export interface WireUserMessage {
|
|
37
|
+
role: 'user';
|
|
38
|
+
content: string;
|
|
39
|
+
}
|
|
40
|
+
/** Tool-role message: the result of one tool call, keyed by its call id. */
|
|
41
|
+
export interface WireToolMessage {
|
|
42
|
+
role: 'tool';
|
|
43
|
+
tool_call_id: string;
|
|
44
|
+
content: string;
|
|
45
|
+
}
|
|
46
|
+
/** One entry of the request `messages` array, discriminated on `role`. */
|
|
47
|
+
export type WireMessage = WireSystemMessage | WireUserMessage | WireAssistantMessage | WireToolMessage;
|
|
48
|
+
/**
|
|
49
|
+
* Assistant-role history message. The harness replays `content: ""` (never
|
|
50
|
+
* null) on tool-call-only turns — some gateways reject null — and sends null
|
|
51
|
+
* only when the turn carried neither text nor tool calls.
|
|
52
|
+
*/
|
|
53
|
+
export interface WireAssistantMessage {
|
|
54
|
+
role: 'assistant';
|
|
55
|
+
content: string | null;
|
|
56
|
+
/**
|
|
57
|
+
* CoT passback, present only on a turn whose assistant content carried
|
|
58
|
+
* reasoning AND whose model is reasoning-capable (a wire id containing
|
|
59
|
+
* `deepseek`). Ollama accepts the `reasoning` field on assistant history
|
|
60
|
+
* messages; a non-reasoning model simply ignores it, so it is only written
|
|
61
|
+
* for reasoning-capable models to keep non-reasoning traces clean.
|
|
62
|
+
*/
|
|
63
|
+
reasoning?: string;
|
|
64
|
+
tool_calls?: WireToolCall[];
|
|
65
|
+
}
|
|
66
|
+
/** A completed tool call replayed on an assistant history message; `arguments` is the raw JSON string. */
|
|
67
|
+
export interface WireToolCall {
|
|
68
|
+
id: string;
|
|
69
|
+
type: 'function';
|
|
70
|
+
function: {
|
|
71
|
+
name: string;
|
|
72
|
+
arguments: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** One entry of the request `tools` array; `parameters` is a JSON Schema object. */
|
|
76
|
+
export interface WireTool {
|
|
77
|
+
type: 'function';
|
|
78
|
+
function: {
|
|
79
|
+
name: string;
|
|
80
|
+
description: string;
|
|
81
|
+
parameters: Record<string, unknown>;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** One parsed SSE `data:` payload (a chat.completion.chunk). */
|
|
85
|
+
export interface WireChunk {
|
|
86
|
+
choices?: WireChoice[];
|
|
87
|
+
/** Arrives attached to the finish chunk and/or as a trailing usage-only chunk. */
|
|
88
|
+
usage?: WireUsage | null;
|
|
89
|
+
}
|
|
90
|
+
/** One streamed choice (requests always ask for a single one); `finish_reason` is non-null only on its terminal chunk. */
|
|
91
|
+
export interface WireChoice {
|
|
92
|
+
delta?: WireDelta;
|
|
93
|
+
finish_reason?: string | null;
|
|
94
|
+
}
|
|
95
|
+
/** The incremental content of one streamed choice; any subset of fields may be present per chunk. */
|
|
96
|
+
export interface WireDelta {
|
|
97
|
+
role?: string;
|
|
98
|
+
/** Visible text. Null/empty on reasoning/tool-call chunks. */
|
|
99
|
+
content?: string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Thinking-mode CoT. The FIRST chunk carries an empty string (must not open
|
|
102
|
+
* a reasoning block); absent entirely in non-thinking mode.
|
|
103
|
+
*/
|
|
104
|
+
reasoning?: string | null;
|
|
105
|
+
tool_calls?: WireToolCallDelta[];
|
|
106
|
+
}
|
|
107
|
+
/** A streamed fragment of one tool call; fragments sharing an `index` concatenate into one call. */
|
|
108
|
+
export interface WireToolCallDelta {
|
|
109
|
+
/** Disambiguates parallel tool calls; stable across a call's deltas. */
|
|
110
|
+
index: number;
|
|
111
|
+
/** Present on the first delta of each call only. */
|
|
112
|
+
id?: string;
|
|
113
|
+
type?: 'function';
|
|
114
|
+
function?: {
|
|
115
|
+
/** Present on the first delta of each call only. */
|
|
116
|
+
name?: string;
|
|
117
|
+
/** Argument JSON fragment (concatenate across deltas). */
|
|
118
|
+
arguments?: string;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Wire token accounting. Ollama's OpenAI-compatible endpoint reports standard
|
|
123
|
+
* `prompt_tokens`/`completion_tokens`; the cache and reasoning details follow
|
|
124
|
+
* the OpenAI-compat spelling when the backend supplies them.
|
|
125
|
+
*/
|
|
126
|
+
export interface WireUsage {
|
|
127
|
+
prompt_tokens: number;
|
|
128
|
+
completion_tokens: number;
|
|
129
|
+
prompt_tokens_details?: {
|
|
130
|
+
cached_tokens?: number;
|
|
131
|
+
};
|
|
132
|
+
completion_tokens_details?: {
|
|
133
|
+
reasoning_tokens?: number;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Non-2xx error body. */
|
|
137
|
+
export interface WireError {
|
|
138
|
+
error?: {
|
|
139
|
+
message?: string;
|
|
140
|
+
type?: string;
|
|
141
|
+
code?: string;
|
|
142
|
+
};
|
|
143
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lihuu/dsh-ollama-cloud",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DeepSeek Harness plugin: adds the Ollama cloud chat-completions provider for LLM models.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"dsh": {
|
|
17
|
+
"bundle": {
|
|
18
|
+
"patch": "./cordis.patch.yml"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist/index.js",
|
|
26
|
+
"lib/**/*.d.ts",
|
|
27
|
+
"src",
|
|
28
|
+
"cordis.patch.yml",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.json && node build.mjs",
|
|
33
|
+
"build:types": "tsc -p tsconfig.json",
|
|
34
|
+
"build:bundle": "node build.mjs"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@deepseek-ai/dsh-llm": "*",
|
|
38
|
+
"@deepseek-ai/dsh-credentials": "*"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"typescript": "^5.5.0",
|
|
43
|
+
"@types/node": "^22.0.0"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"deepseek-harness",
|
|
47
|
+
"dsh",
|
|
48
|
+
"cordis",
|
|
49
|
+
"llm",
|
|
50
|
+
"ollama"
|
|
51
|
+
]
|
|
52
|
+
}
|