@graphorin/provider 0.5.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/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +6 -0
- package/dist/adapters/llamacpp-server.d.ts +69 -0
- package/dist/adapters/llamacpp-server.d.ts.map +1 -0
- package/dist/adapters/llamacpp-server.js +51 -0
- package/dist/adapters/llamacpp-server.js.map +1 -0
- package/dist/adapters/ollama.d.ts +43 -0
- package/dist/adapters/ollama.d.ts.map +1 -0
- package/dist/adapters/ollama.js +246 -0
- package/dist/adapters/ollama.js.map +1 -0
- package/dist/adapters/openai-compatible.d.ts +48 -0
- package/dist/adapters/openai-compatible.d.ts.map +1 -0
- package/dist/adapters/openai-compatible.js +28 -0
- package/dist/adapters/openai-compatible.js.map +1 -0
- package/dist/adapters/vercel.d.ts +135 -0
- package/dist/adapters/vercel.d.ts.map +1 -0
- package/dist/adapters/vercel.js +306 -0
- package/dist/adapters/vercel.js.map +1 -0
- package/dist/counters/anthropic.d.ts +36 -0
- package/dist/counters/anthropic.d.ts.map +1 -0
- package/dist/counters/anthropic.js +63 -0
- package/dist/counters/anthropic.js.map +1 -0
- package/dist/counters/bedrock.d.ts +27 -0
- package/dist/counters/bedrock.d.ts.map +1 -0
- package/dist/counters/bedrock.js +29 -0
- package/dist/counters/bedrock.js.map +1 -0
- package/dist/counters/dispatcher.d.ts +34 -0
- package/dist/counters/dispatcher.d.ts.map +1 -0
- package/dist/counters/dispatcher.js +78 -0
- package/dist/counters/dispatcher.js.map +1 -0
- package/dist/counters/global.d.ts +26 -0
- package/dist/counters/global.d.ts.map +1 -0
- package/dist/counters/global.js +31 -0
- package/dist/counters/global.js.map +1 -0
- package/dist/counters/google.d.ts +27 -0
- package/dist/counters/google.d.ts.map +1 -0
- package/dist/counters/google.js +29 -0
- package/dist/counters/google.js.map +1 -0
- package/dist/counters/heuristic.d.ts +37 -0
- package/dist/counters/heuristic.d.ts.map +1 -0
- package/dist/counters/heuristic.js +64 -0
- package/dist/counters/heuristic.js.map +1 -0
- package/dist/counters/index.d.ts +9 -0
- package/dist/counters/index.js +10 -0
- package/dist/counters/js-tiktoken.d.ts +63 -0
- package/dist/counters/js-tiktoken.d.ts.map +1 -0
- package/dist/counters/js-tiktoken.js +73 -0
- package/dist/counters/js-tiktoken.js.map +1 -0
- package/dist/counters/serialize.d.ts +37 -0
- package/dist/counters/serialize.d.ts.map +1 -0
- package/dist/counters/serialize.js +57 -0
- package/dist/counters/serialize.js.map +1 -0
- package/dist/errors/errors.d.ts +167 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +182 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +3 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/abort.js +34 -0
- package/dist/internal/abort.js.map +1 -0
- package/dist/internal/http.js +163 -0
- package/dist/internal/http.js.map +1 -0
- package/dist/internal/openai-shaped.js +308 -0
- package/dist/internal/openai-shaped.js.map +1 -0
- package/dist/internal/sse.js +104 -0
- package/dist/internal/sse.js.map +1 -0
- package/dist/internal/url-utils.js +24 -0
- package/dist/internal/url-utils.js.map +1 -0
- package/dist/middleware/compose.d.ts +85 -0
- package/dist/middleware/compose.d.ts.map +1 -0
- package/dist/middleware/compose.js +174 -0
- package/dist/middleware/compose.js.map +1 -0
- package/dist/middleware/index.d.ts +10 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/production-hook.d.ts +27 -0
- package/dist/middleware/production-hook.d.ts.map +1 -0
- package/dist/middleware/production-hook.js +21 -0
- package/dist/middleware/production-hook.js.map +1 -0
- package/dist/middleware/with-cost-limit.d.ts +46 -0
- package/dist/middleware/with-cost-limit.d.ts.map +1 -0
- package/dist/middleware/with-cost-limit.js +66 -0
- package/dist/middleware/with-cost-limit.js.map +1 -0
- package/dist/middleware/with-cost-tracking.d.ts +91 -0
- package/dist/middleware/with-cost-tracking.d.ts.map +1 -0
- package/dist/middleware/with-cost-tracking.js +95 -0
- package/dist/middleware/with-cost-tracking.js.map +1 -0
- package/dist/middleware/with-fallback.d.ts +25 -0
- package/dist/middleware/with-fallback.d.ts.map +1 -0
- package/dist/middleware/with-fallback.js +84 -0
- package/dist/middleware/with-fallback.js.map +1 -0
- package/dist/middleware/with-rate-limit.d.ts +36 -0
- package/dist/middleware/with-rate-limit.d.ts.map +1 -0
- package/dist/middleware/with-rate-limit.js +141 -0
- package/dist/middleware/with-rate-limit.js.map +1 -0
- package/dist/middleware/with-redaction.d.ts +60 -0
- package/dist/middleware/with-redaction.d.ts.map +1 -0
- package/dist/middleware/with-redaction.js +305 -0
- package/dist/middleware/with-redaction.js.map +1 -0
- package/dist/middleware/with-retry.d.ts +26 -0
- package/dist/middleware/with-retry.d.ts.map +1 -0
- package/dist/middleware/with-retry.js +157 -0
- package/dist/middleware/with-retry.js.map +1 -0
- package/dist/middleware/with-tracing.d.ts +21 -0
- package/dist/middleware/with-tracing.d.ts.map +1 -0
- package/dist/middleware/with-tracing.js +55 -0
- package/dist/middleware/with-tracing.js.map +1 -0
- package/dist/model-tier/classify.d.ts +34 -0
- package/dist/model-tier/classify.d.ts.map +1 -0
- package/dist/model-tier/classify.js +117 -0
- package/dist/model-tier/classify.js.map +1 -0
- package/dist/model-tier/index.d.ts +2 -0
- package/dist/model-tier/index.js +3 -0
- package/dist/provider.d.ts +51 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +64 -0
- package/dist/provider.js.map +1 -0
- package/dist/reasoning/apply-policy.d.ts +22 -0
- package/dist/reasoning/apply-policy.d.ts.map +1 -0
- package/dist/reasoning/apply-policy.js +47 -0
- package/dist/reasoning/apply-policy.js.map +1 -0
- package/dist/reasoning/classify-contract.d.ts +41 -0
- package/dist/reasoning/classify-contract.d.ts.map +1 -0
- package/dist/reasoning/classify-contract.js +59 -0
- package/dist/reasoning/classify-contract.js.map +1 -0
- package/dist/reasoning/index.d.ts +4 -0
- package/dist/reasoning/index.js +5 -0
- package/dist/reasoning/retention.d.ts +39 -0
- package/dist/reasoning/retention.d.ts.map +1 -0
- package/dist/reasoning/retention.js +33 -0
- package/dist/reasoning/retention.js.map +1 -0
- package/dist/tool-examples.d.ts +14 -0
- package/dist/tool-examples.d.ts.map +1 -0
- package/dist/tool-examples.js +35 -0
- package/dist/tool-examples.js.map +1 -0
- package/dist/trust/classify-local-provider.d.ts +47 -0
- package/dist/trust/classify-local-provider.d.ts.map +1 -0
- package/dist/trust/classify-local-provider.js +164 -0
- package/dist/trust/classify-local-provider.js.map +1 -0
- package/dist/trust/index.d.ts +3 -0
- package/dist/trust/index.js +3 -0
- package/package.json +128 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oleksiy Stepurenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# `@graphorin/provider`
|
|
2
|
+
|
|
3
|
+
> Vendor-neutral LLM provider layer for the
|
|
4
|
+
> [**Graphorin**](https://github.com/o-stepper/graphorin) framework.
|
|
5
|
+
|
|
6
|
+
The package owns four moving parts:
|
|
7
|
+
|
|
8
|
+
1. **`createProvider(...)`** — wraps any adapter in a stable `Provider`
|
|
9
|
+
shape with sensitivity, capability, and reasoning-retention defaults.
|
|
10
|
+
2. **Adapters** — `vercelAdapter` (default cloud path; wraps the Vercel
|
|
11
|
+
AI SDK), `ollamaAdapter` (direct Ollama HTTP), `llamaCppServerAdapter`
|
|
12
|
+
(the upstream `llama-server` binary from llama.cpp), and
|
|
13
|
+
`openAICompatibleAdapter` (LMStudio / LocalAI / vLLM / Together-style
|
|
14
|
+
self-host endpoints).
|
|
15
|
+
3. **Middleware** — `composeProviderMiddleware([...])` enforces a
|
|
16
|
+
canonical order at startup and throws `MiddlewareOrderingError` on
|
|
17
|
+
violation. Built-ins: `withTracing`, `withRetry`, `withRateLimit`,
|
|
18
|
+
`withCostLimit`, `withCostTracking`, `withFallback`, and
|
|
19
|
+
`withRedaction` (mandatory in production).
|
|
20
|
+
4. **Token counting** — pluggable `TokenCounter` dispatcher. Default
|
|
21
|
+
`JsTiktokenCounter` for OpenAI-compatible models; per-vendor native
|
|
22
|
+
counters for Anthropic, Google, and Bedrock; heuristic fallback for
|
|
23
|
+
unknown providers with a one-time WARN.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @graphorin/provider
|
|
29
|
+
# Optional peer for the cloud adapter:
|
|
30
|
+
pnpm add ai
|
|
31
|
+
# Optional peer for the default token counter:
|
|
32
|
+
pnpm add js-tiktoken
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For the in-process llama.cpp companion adapter, install the separate
|
|
36
|
+
package:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add @graphorin/provider-llamacpp-node node-llama-cpp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { composeProviderMiddleware, createProvider } from '@graphorin/provider';
|
|
46
|
+
import { vercelAdapter } from '@graphorin/provider/adapters/vercel';
|
|
47
|
+
import {
|
|
48
|
+
withCostLimit,
|
|
49
|
+
withFallback,
|
|
50
|
+
withRateLimit,
|
|
51
|
+
withRedaction,
|
|
52
|
+
withRetry,
|
|
53
|
+
withTracing,
|
|
54
|
+
} from '@graphorin/provider/middleware';
|
|
55
|
+
import { BUILT_IN_PATTERNS } from '@graphorin/observability/redaction/patterns';
|
|
56
|
+
import { openai } from '@ai-sdk/openai';
|
|
57
|
+
|
|
58
|
+
const provider = createProvider(vercelAdapter(openai('gpt-4o')));
|
|
59
|
+
|
|
60
|
+
const safeProvider = composeProviderMiddleware([
|
|
61
|
+
withTracing(),
|
|
62
|
+
withRetry({ maxRetries: 3 }),
|
|
63
|
+
withRateLimit({ requestsPerMinute: 60 }),
|
|
64
|
+
withCostLimit({ maxPerSession: 1.0 }),
|
|
65
|
+
withFallback([fallbackProvider]),
|
|
66
|
+
withRedaction({ patterns: BUILT_IN_PATTERNS }), // INNERMOST
|
|
67
|
+
])(provider);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Local-first stack
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { ollamaAdapter } from '@graphorin/provider/adapters/ollama';
|
|
74
|
+
|
|
75
|
+
// Auto-classified as 'loopback' — no warning, no first-run prompt.
|
|
76
|
+
const local = createProvider(
|
|
77
|
+
ollamaAdapter({ model: 'llama3.1:8b', baseUrl: 'http://127.0.0.1:11434' }),
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The same `LocalProviderTrust` classifier (`'loopback' | 'private' |
|
|
82
|
+
'public-tls' | 'public-cleartext'`) drives the trust auto-detection,
|
|
83
|
+
the sensitivity-tier defaults, and the `withRedaction` policy table
|
|
84
|
+
for every `baseUrl`-driven adapter — `ollamaAdapter`,
|
|
85
|
+
`llamaCppServerAdapter`, and `openAICompatibleAdapter`. The classifier
|
|
86
|
+
lives at `@graphorin/provider/trust`. Public-cleartext URLs refuse to
|
|
87
|
+
start with `LocalProviderInsecureTransportError`.
|
|
88
|
+
|
|
89
|
+
## Cost-tier vocabulary
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import type { ModelHint } from '@graphorin/core';
|
|
93
|
+
import { classifyModelTier } from '@graphorin/provider/model-tier';
|
|
94
|
+
|
|
95
|
+
classifyModelTier(provider); // ⇒ 'fast' | 'balanced' | 'smart' | undefined
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The classifier is consumed by the agent runtime (Phase 12) to validate
|
|
99
|
+
operator-supplied per-tier mappings and to surface tier-not-mapped
|
|
100
|
+
recommendations.
|
|
101
|
+
|
|
102
|
+
## Project metadata
|
|
103
|
+
|
|
104
|
+
- **Project Graphorin** · v0.5.0 · MIT License · © 2026 Oleksiy Stepurenko
|
|
105
|
+
- Repository: <https://github.com/o-stepper/graphorin>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { LlamaCppServerAdapterOptions, llamaCppServerAdapter } from "./llamacpp-server.js";
|
|
2
|
+
import { OllamaAdapterOptions, ollamaAdapter } from "./ollama.js";
|
|
3
|
+
import { OpenAICompatibleAdapterOptions, openAICompatibleAdapter } from "./openai-compatible.js";
|
|
4
|
+
import { VercelAdapterOptions, vercelAdapter } from "./vercel.js";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as _graphorin_core0 from "@graphorin/core";
|
|
2
|
+
import { Provider, Sensitivity } from "@graphorin/core";
|
|
3
|
+
|
|
4
|
+
//#region src/adapters/llamacpp-server.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default port used by the upstream `llama-server` binary.
|
|
8
|
+
*
|
|
9
|
+
* @stable
|
|
10
|
+
*/
|
|
11
|
+
declare const DEFAULT_LLAMACPP_SERVER_BASE_URL = "http://127.0.0.1:8080";
|
|
12
|
+
/**
|
|
13
|
+
* Options accepted by {@link llamaCppServerAdapter}.
|
|
14
|
+
*
|
|
15
|
+
* @stable
|
|
16
|
+
*/
|
|
17
|
+
interface LlamaCppServerAdapterOptions {
|
|
18
|
+
/** GGUF model identifier exposed by the running server (e.g. `'qwen2.5:7b-instruct-q4_k_m'`). */
|
|
19
|
+
readonly model: string;
|
|
20
|
+
/** Base URL of the running `llama-server` process. Defaults to `http://127.0.0.1:8080`. */
|
|
21
|
+
readonly baseUrl?: string;
|
|
22
|
+
/** Optional bearer-auth API key (`--api-key` flag on the server). */
|
|
23
|
+
readonly apiKey?: string;
|
|
24
|
+
/** Extra headers merged on top of `content-type` + `accept` defaults. */
|
|
25
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
26
|
+
/** Custom `fetch` implementation; useful for tests. */
|
|
27
|
+
readonly fetchImpl?: typeof fetch;
|
|
28
|
+
/**
|
|
29
|
+
* Time-to-response budget per request (PS-24). Default
|
|
30
|
+
* `DEFAULT_REQUEST_TIMEOUT_MS` (120s); `0` disables.
|
|
31
|
+
*/
|
|
32
|
+
readonly timeoutMs?: number;
|
|
33
|
+
/** Capability overrides merged on top of the adapter defaults. */
|
|
34
|
+
readonly capabilities?: Partial<_graphorin_core0.ProviderCapabilities>;
|
|
35
|
+
/**
|
|
36
|
+
* Acknowledge the risk of running over plaintext HTTP against a
|
|
37
|
+
* public host. Without this flag the adapter throws
|
|
38
|
+
* {@link import('../errors/errors.js').LocalProviderInsecureTransportError}.
|
|
39
|
+
*/
|
|
40
|
+
readonly allowInsecureTransport?: boolean;
|
|
41
|
+
/** Override for the default `acceptsSensitivity` value. */
|
|
42
|
+
readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;
|
|
43
|
+
/** Provider name attached to spans / log lines. */
|
|
44
|
+
readonly name?: string;
|
|
45
|
+
/** Optional log sink. Tests pass a fixture sink to silence the console. */
|
|
46
|
+
readonly logger?: (level: 'warn' | 'info', message: string, meta?: object) => void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build a Graphorin {@link Provider} backed by the upstream
|
|
50
|
+
* `llama-server` binary. The factory does not start the binary —
|
|
51
|
+
* operators launch it themselves with the desired model + GPU flags
|
|
52
|
+
* and pass the URL here.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const local = createProvider(
|
|
57
|
+
* llamaCppServerAdapter({
|
|
58
|
+
* model: 'qwen2.5:7b-instruct-q4_k_m',
|
|
59
|
+
* baseUrl: 'http://127.0.0.1:8080',
|
|
60
|
+
* }),
|
|
61
|
+
* );
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @stable
|
|
65
|
+
*/
|
|
66
|
+
declare function llamaCppServerAdapter(options: LlamaCppServerAdapterOptions): Provider;
|
|
67
|
+
//#endregion
|
|
68
|
+
export { DEFAULT_LLAMACPP_SERVER_BASE_URL, LlamaCppServerAdapterOptions, llamaCppServerAdapter };
|
|
69
|
+
//# sourceMappingURL=llamacpp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llamacpp-server.d.ts","names":[],"sources":["../../src/adapters/llamacpp-server.ts"],"sourcesContent":[],"mappings":";;;;;AAgFA;;;;;cAzDa,gCAAA;;;;;;UAOI,4BAAA;;;;;;;;qBAQI,SAAS;;8BAEA;;;;;;;0BAOJ,QAPS,gBAAA,CAOyB,oBAAA;;;;;;;;gCAQ5B,cAAc;;;;;;;;;;;;;;;;;;;;;;;;iBAyB9B,qBAAA,UAA+B,+BAA+B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { buildOpenAIShapedProvider } from "../internal/openai-shaped.js";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/llamacpp-server.ts
|
|
4
|
+
/**
|
|
5
|
+
* Default port used by the upstream `llama-server` binary.
|
|
6
|
+
*
|
|
7
|
+
* @stable
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_LLAMACPP_SERVER_BASE_URL = "http://127.0.0.1:8080";
|
|
10
|
+
/**
|
|
11
|
+
* Build a Graphorin {@link Provider} backed by the upstream
|
|
12
|
+
* `llama-server` binary. The factory does not start the binary —
|
|
13
|
+
* operators launch it themselves with the desired model + GPU flags
|
|
14
|
+
* and pass the URL here.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const local = createProvider(
|
|
19
|
+
* llamaCppServerAdapter({
|
|
20
|
+
* model: 'qwen2.5:7b-instruct-q4_k_m',
|
|
21
|
+
* baseUrl: 'http://127.0.0.1:8080',
|
|
22
|
+
* }),
|
|
23
|
+
* );
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @stable
|
|
27
|
+
*/
|
|
28
|
+
function llamaCppServerAdapter(options) {
|
|
29
|
+
const baseUrl = options.baseUrl ?? DEFAULT_LLAMACPP_SERVER_BASE_URL;
|
|
30
|
+
return buildOpenAIShapedProvider({
|
|
31
|
+
providerName: options.name ?? `llamacpp-server-${options.model}`,
|
|
32
|
+
model: options.model,
|
|
33
|
+
baseUrl,
|
|
34
|
+
...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
|
|
35
|
+
...options.headers !== void 0 ? { headers: options.headers } : {},
|
|
36
|
+
...options.fetchImpl !== void 0 ? { fetchImpl: options.fetchImpl } : {},
|
|
37
|
+
...options.allowInsecureTransport !== void 0 ? { allowInsecureTransport: options.allowInsecureTransport } : {},
|
|
38
|
+
...options.acceptsSensitivity !== void 0 ? { acceptsSensitivity: options.acceptsSensitivity } : {},
|
|
39
|
+
...options.logger !== void 0 ? { logger: options.logger } : {},
|
|
40
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
|
|
41
|
+
capabilities: {
|
|
42
|
+
multimodal: false,
|
|
43
|
+
parallelToolCalls: false,
|
|
44
|
+
...options.capabilities
|
|
45
|
+
}
|
|
46
|
+
}).provider;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { DEFAULT_LLAMACPP_SERVER_BASE_URL, llamaCppServerAdapter };
|
|
51
|
+
//# sourceMappingURL=llamacpp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llamacpp-server.js","names":[],"sources":["../../src/adapters/llamacpp-server.ts"],"sourcesContent":["/**\n * Direct adapter for the upstream `llama-server` binary from the\n * llama.cpp project. The binary speaks the OpenAI-compatible REST\n * contract end-to-end (`POST /v1/chat/completions`, `POST /v1/completions`,\n * `POST /v1/embeddings`); streaming is via `text/event-stream` chunks\n * terminated by `data: [DONE]` exactly as the upstream OpenAI shape.\n *\n * The adapter shares a single `LocalProviderTrust` classifier with\n * `ollamaAdapter` and `openAICompatibleAdapter` — one classifier, one\n * policy table, one error type.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, Sensitivity } from '@graphorin/core';\n\nimport { buildOpenAIShapedProvider } from '../internal/openai-shaped.js';\n\n/**\n * Default port used by the upstream `llama-server` binary.\n *\n * @stable\n */\nexport const DEFAULT_LLAMACPP_SERVER_BASE_URL = 'http://127.0.0.1:8080';\n\n/**\n * Options accepted by {@link llamaCppServerAdapter}.\n *\n * @stable\n */\nexport interface LlamaCppServerAdapterOptions {\n /** GGUF model identifier exposed by the running server (e.g. `'qwen2.5:7b-instruct-q4_k_m'`). */\n readonly model: string;\n /** Base URL of the running `llama-server` process. Defaults to `http://127.0.0.1:8080`. */\n readonly baseUrl?: string;\n /** Optional bearer-auth API key (`--api-key` flag on the server). */\n readonly apiKey?: string;\n /** Extra headers merged on top of `content-type` + `accept` defaults. */\n readonly headers?: Readonly<Record<string, string>>;\n /** Custom `fetch` implementation; useful for tests. */\n readonly fetchImpl?: typeof fetch;\n /**\n * Time-to-response budget per request (PS-24). Default\n * `DEFAULT_REQUEST_TIMEOUT_MS` (120s); `0` disables.\n */\n readonly timeoutMs?: number;\n /** Capability overrides merged on top of the adapter defaults. */\n readonly capabilities?: Partial<import('@graphorin/core').ProviderCapabilities>;\n /**\n * Acknowledge the risk of running over plaintext HTTP against a\n * public host. Without this flag the adapter throws\n * {@link import('../errors/errors.js').LocalProviderInsecureTransportError}.\n */\n readonly allowInsecureTransport?: boolean;\n /** Override for the default `acceptsSensitivity` value. */\n readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;\n /** Provider name attached to spans / log lines. */\n readonly name?: string;\n /** Optional log sink. Tests pass a fixture sink to silence the console. */\n readonly logger?: (level: 'warn' | 'info', message: string, meta?: object) => void;\n}\n\n/**\n * Build a Graphorin {@link Provider} backed by the upstream\n * `llama-server` binary. The factory does not start the binary —\n * operators launch it themselves with the desired model + GPU flags\n * and pass the URL here.\n *\n * @example\n * ```ts\n * const local = createProvider(\n * llamaCppServerAdapter({\n * model: 'qwen2.5:7b-instruct-q4_k_m',\n * baseUrl: 'http://127.0.0.1:8080',\n * }),\n * );\n * ```\n *\n * @stable\n */\nexport function llamaCppServerAdapter(options: LlamaCppServerAdapterOptions): Provider {\n const baseUrl = options.baseUrl ?? DEFAULT_LLAMACPP_SERVER_BASE_URL;\n const providerName = options.name ?? `llamacpp-server-${options.model}`;\n const built = buildOpenAIShapedProvider({\n providerName,\n model: options.model,\n baseUrl,\n ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n ...(options.allowInsecureTransport !== undefined\n ? { allowInsecureTransport: options.allowInsecureTransport }\n : {}),\n ...(options.acceptsSensitivity !== undefined\n ? { acceptsSensitivity: options.acceptsSensitivity }\n : {}),\n ...(options.logger !== undefined ? { logger: options.logger } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n capabilities: { multimodal: false, parallelToolCalls: false, ...options.capabilities },\n });\n return built.provider;\n}\n"],"mappings":";;;;;;;;AAuBA,MAAa,mCAAmC;;;;;;;;;;;;;;;;;;;AAyDhD,SAAgB,sBAAsB,SAAiD;CACrF,MAAM,UAAU,QAAQ,WAAW;AAmBnC,QAjBc,0BAA0B;EACtC,cAFmB,QAAQ,QAAQ,mBAAmB,QAAQ;EAG9D,OAAO,QAAQ;EACf;EACA,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;EAClE,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EACrE,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC3E,GAAI,QAAQ,2BAA2B,SACnC,EAAE,wBAAwB,QAAQ,wBAAwB,GAC1D,EAAE;EACN,GAAI,QAAQ,uBAAuB,SAC/B,EAAE,oBAAoB,QAAQ,oBAAoB,GAClD,EAAE;EACN,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;EAClE,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC3E,cAAc;GAAE,YAAY;GAAO,mBAAmB;GAAO,GAAG,QAAQ;GAAc;EACvF,CAAC,CACW"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Provider, ProviderCapabilities, Sensitivity } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/ollama.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default Ollama base URL.
|
|
7
|
+
*
|
|
8
|
+
* @stable
|
|
9
|
+
*/
|
|
10
|
+
declare const DEFAULT_OLLAMA_BASE_URL = "http://127.0.0.1:11434";
|
|
11
|
+
/**
|
|
12
|
+
* Options accepted by {@link ollamaAdapter}.
|
|
13
|
+
*
|
|
14
|
+
* @stable
|
|
15
|
+
*/
|
|
16
|
+
interface OllamaAdapterOptions {
|
|
17
|
+
readonly model: string;
|
|
18
|
+
readonly baseUrl?: string;
|
|
19
|
+
readonly chatPath?: string;
|
|
20
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
21
|
+
readonly fetchImpl?: typeof fetch;
|
|
22
|
+
/**
|
|
23
|
+
* Time-to-response budget per request (PS-24). Default
|
|
24
|
+
* `DEFAULT_REQUEST_TIMEOUT_MS` (120s); `0` disables.
|
|
25
|
+
*/
|
|
26
|
+
readonly timeoutMs?: number;
|
|
27
|
+
readonly allowInsecureTransport?: boolean;
|
|
28
|
+
readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;
|
|
29
|
+
readonly capabilities?: Partial<ProviderCapabilities>;
|
|
30
|
+
readonly name?: string;
|
|
31
|
+
readonly logger?: (level: 'warn' | 'info', message: string, meta?: object) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a Graphorin {@link Provider} backed by Ollama's native HTTP
|
|
35
|
+
* API. The adapter is fail-safe by default: public-cleartext URLs
|
|
36
|
+
* refuse to start with `LocalProviderInsecureTransportError`.
|
|
37
|
+
*
|
|
38
|
+
* @stable
|
|
39
|
+
*/
|
|
40
|
+
declare function ollamaAdapter(options: OllamaAdapterOptions): Provider;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { DEFAULT_OLLAMA_BASE_URL, OllamaAdapterOptions, ollamaAdapter };
|
|
43
|
+
//# sourceMappingURL=ollama.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.d.ts","names":[],"sources":["../../src/adapters/ollama.ts"],"sourcesContent":[],"mappings":";;;;;AAoFA;;;;cA5Ca,uBAAA;;;;;;UAOI,oBAAA;;;;qBAII,SAAS;8BACA;;;;;;;gCAOE,cAAc;0BACpB,QAAQ;;;;;;;;;;;iBAwBlB,aAAA,UAAuB,uBAAuB"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { LocalProviderInsecureTransportError, ProviderStreamParseError } from "../errors/errors.js";
|
|
2
|
+
import { applyReasoningPolicy } from "../reasoning/apply-policy.js";
|
|
3
|
+
import { resolveReasoningRetention } from "../reasoning/retention.js";
|
|
4
|
+
import { classifyLocalProvider } from "../trust/classify-local-provider.js";
|
|
5
|
+
import { callJsonHttp, makeStreamStartEvent, toOllamaChatMessages } from "../internal/http.js";
|
|
6
|
+
import { parseNdJsonStream } from "../internal/sse.js";
|
|
7
|
+
import { stripTrailingSlashes } from "../internal/url-utils.js";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
|
|
10
|
+
//#region src/adapters/ollama.ts
|
|
11
|
+
/**
|
|
12
|
+
* Direct adapter for the Ollama HTTP API. The adapter speaks the
|
|
13
|
+
* native Ollama streaming JSON protocol (`POST /api/chat` returning
|
|
14
|
+
* newline-delimited JSON objects). For operators who prefer the
|
|
15
|
+
* OpenAI-compatible variant exposed by recent Ollama releases, the
|
|
16
|
+
* generic {@link openAICompatibleAdapter} is the better choice — both
|
|
17
|
+
* adapters share the same {@link LocalProviderTrust} classifier and
|
|
18
|
+
* {@link LocalProviderInsecureTransportError} startup behaviour.
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Default Ollama base URL.
|
|
24
|
+
*
|
|
25
|
+
* @stable
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_OLLAMA_BASE_URL = "http://127.0.0.1:11434";
|
|
28
|
+
const DEFAULT_CAPABILITIES = {
|
|
29
|
+
streaming: true,
|
|
30
|
+
toolCalling: true,
|
|
31
|
+
parallelToolCalls: false,
|
|
32
|
+
multimodal: false,
|
|
33
|
+
structuredOutput: true,
|
|
34
|
+
reasoning: false,
|
|
35
|
+
contextWindow: 8192,
|
|
36
|
+
maxOutput: 4096,
|
|
37
|
+
reasoningContract: "optional"
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Build a Graphorin {@link Provider} backed by Ollama's native HTTP
|
|
41
|
+
* API. The adapter is fail-safe by default: public-cleartext URLs
|
|
42
|
+
* refuse to start with `LocalProviderInsecureTransportError`.
|
|
43
|
+
*
|
|
44
|
+
* @stable
|
|
45
|
+
*/
|
|
46
|
+
function ollamaAdapter(options) {
|
|
47
|
+
const baseUrl = options.baseUrl ?? DEFAULT_OLLAMA_BASE_URL;
|
|
48
|
+
const classification = classifyLocalProvider(baseUrl);
|
|
49
|
+
if (classification.trust === "public-cleartext" && options.allowInsecureTransport !== true) throw new LocalProviderInsecureTransportError(baseUrl);
|
|
50
|
+
emitTrustWarning(options.logger ?? defaultLogger, classification, baseUrl);
|
|
51
|
+
const acceptsSensitivity = options.acceptsSensitivity ?? classification.acceptsSensitivity;
|
|
52
|
+
const providerName = options.name ?? `ollama-${options.model}`;
|
|
53
|
+
const capabilities = {
|
|
54
|
+
...DEFAULT_CAPABILITIES,
|
|
55
|
+
...options.capabilities
|
|
56
|
+
};
|
|
57
|
+
const chatPath = options.chatPath ?? "/api/chat";
|
|
58
|
+
const url = `${stripTrailingSlashes(baseUrl)}${chatPath}`;
|
|
59
|
+
return {
|
|
60
|
+
name: providerName,
|
|
61
|
+
modelId: options.model,
|
|
62
|
+
capabilities,
|
|
63
|
+
acceptsSensitivity,
|
|
64
|
+
stream(req) {
|
|
65
|
+
return streamOllama(options, providerName, url, applyOllamaPreflight(req, capabilities));
|
|
66
|
+
},
|
|
67
|
+
async generate(req) {
|
|
68
|
+
return generateOllama(options, providerName, url, applyOllamaPreflight(req, capabilities));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function applyOllamaPreflight(req, capabilities) {
|
|
73
|
+
const retention = resolveReasoningRetention({
|
|
74
|
+
...req.reasoningRetention !== void 0 ? { requested: req.reasoningRetention } : {},
|
|
75
|
+
...capabilities.reasoningContract !== void 0 ? { contract: capabilities.reasoningContract } : {}
|
|
76
|
+
});
|
|
77
|
+
if (retention === "pass-through-all") return req;
|
|
78
|
+
const filtered = applyReasoningPolicy({
|
|
79
|
+
messages: req.messages,
|
|
80
|
+
retention
|
|
81
|
+
});
|
|
82
|
+
if (filtered === req.messages) return req;
|
|
83
|
+
return {
|
|
84
|
+
...req,
|
|
85
|
+
messages: filtered
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function* streamOllama(options, providerName, url, req) {
|
|
89
|
+
const body = buildBody(options.model, req, true, options.capabilities?.structuredOutput ?? true);
|
|
90
|
+
const resp = await callJsonHttp({
|
|
91
|
+
providerName,
|
|
92
|
+
url,
|
|
93
|
+
headers: buildHeaders(options),
|
|
94
|
+
body,
|
|
95
|
+
...req.signal !== void 0 ? { signal: req.signal } : {},
|
|
96
|
+
...options.fetchImpl !== void 0 ? { fetchImpl: options.fetchImpl } : {},
|
|
97
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
98
|
+
});
|
|
99
|
+
yield makeStreamStartEvent({
|
|
100
|
+
providerName,
|
|
101
|
+
modelId: options.model
|
|
102
|
+
});
|
|
103
|
+
let usage = {
|
|
104
|
+
promptTokens: 0,
|
|
105
|
+
completionTokens: 0,
|
|
106
|
+
totalTokens: 0
|
|
107
|
+
};
|
|
108
|
+
let finishReason = "stop";
|
|
109
|
+
for await (const line of parseNdJsonStream(resp.body, req.signal !== void 0 ? { signal: req.signal } : {})) {
|
|
110
|
+
if (req.signal?.aborted) {
|
|
111
|
+
finishReason = "aborted";
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
let chunk;
|
|
115
|
+
try {
|
|
116
|
+
chunk = JSON.parse(line);
|
|
117
|
+
} catch (cause) {
|
|
118
|
+
throw new ProviderStreamParseError(providerName, `failed to parse ndjson line: ${cause.message}`, cause);
|
|
119
|
+
}
|
|
120
|
+
if (chunk.message?.content !== void 0 && chunk.message.content.length > 0) yield {
|
|
121
|
+
type: "text-delta",
|
|
122
|
+
delta: chunk.message.content
|
|
123
|
+
};
|
|
124
|
+
if (Array.isArray(chunk.message?.tool_calls)) for (const tc of chunk.message.tool_calls) {
|
|
125
|
+
const toolCallId = tc.id ?? `call_${randomUUID()}`;
|
|
126
|
+
const toolName = tc.function?.name ?? "";
|
|
127
|
+
if (toolName.length === 0) continue;
|
|
128
|
+
yield {
|
|
129
|
+
type: "tool-call-start",
|
|
130
|
+
toolCallId,
|
|
131
|
+
toolName
|
|
132
|
+
};
|
|
133
|
+
yield {
|
|
134
|
+
type: "tool-call-end",
|
|
135
|
+
toolCallId,
|
|
136
|
+
finalArgs: tc.function?.arguments ?? {}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (chunk.done === true) {
|
|
140
|
+
finishReason = mapFinishReason(chunk.done_reason);
|
|
141
|
+
usage = mapUsage(chunk);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
yield {
|
|
146
|
+
type: "finish",
|
|
147
|
+
finishReason,
|
|
148
|
+
usage
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function generateOllama(options, providerName, url, req) {
|
|
152
|
+
const body = buildBody(options.model, req, false, options.capabilities?.structuredOutput ?? true);
|
|
153
|
+
const resp = await callJsonHttp({
|
|
154
|
+
providerName,
|
|
155
|
+
url,
|
|
156
|
+
headers: buildHeaders(options),
|
|
157
|
+
body,
|
|
158
|
+
...req.signal !== void 0 ? { signal: req.signal } : {},
|
|
159
|
+
...options.fetchImpl !== void 0 ? { fetchImpl: options.fetchImpl } : {},
|
|
160
|
+
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
161
|
+
});
|
|
162
|
+
let json;
|
|
163
|
+
try {
|
|
164
|
+
json = await resp.json();
|
|
165
|
+
} catch (cause) {
|
|
166
|
+
throw new ProviderStreamParseError(providerName, "response body was not valid JSON", cause);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
usage: mapUsage(json),
|
|
170
|
+
finishReason: mapFinishReason(json.done_reason),
|
|
171
|
+
...typeof json.message?.content === "string" && json.message.content.length > 0 ? { text: json.message.content } : {},
|
|
172
|
+
...Array.isArray(json.message?.tool_calls) && json.message.tool_calls.length > 0 ? { toolCalls: json.message.tool_calls.map((tc) => ({
|
|
173
|
+
toolCallId: tc.id ?? `call_${randomUUID()}`,
|
|
174
|
+
toolName: tc.function?.name ?? "",
|
|
175
|
+
args: tc.function?.arguments ?? {}
|
|
176
|
+
})) } : {}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function buildBody(model, req, stream, structuredOutput) {
|
|
180
|
+
const body = {
|
|
181
|
+
model,
|
|
182
|
+
messages: toOllamaChatMessages(req.systemMessage !== void 0 ? [{
|
|
183
|
+
role: "system",
|
|
184
|
+
content: req.systemMessage
|
|
185
|
+
}, ...req.messages] : req.messages),
|
|
186
|
+
stream
|
|
187
|
+
};
|
|
188
|
+
if (req.temperature !== void 0 || req.maxTokens !== void 0) {
|
|
189
|
+
const optionsBlock = {};
|
|
190
|
+
if (req.temperature !== void 0) optionsBlock.temperature = req.temperature;
|
|
191
|
+
if (req.maxTokens !== void 0) optionsBlock.num_predict = req.maxTokens;
|
|
192
|
+
body.options = optionsBlock;
|
|
193
|
+
}
|
|
194
|
+
if (req.tools !== void 0 && req.tools.length > 0) body.tools = req.tools.map((t) => ({
|
|
195
|
+
type: "function",
|
|
196
|
+
function: {
|
|
197
|
+
name: t.name,
|
|
198
|
+
...t.description !== void 0 ? { description: t.description } : {},
|
|
199
|
+
parameters: t.inputSchema
|
|
200
|
+
}
|
|
201
|
+
}));
|
|
202
|
+
if (structuredOutput && req.outputType?.kind === "structured") body.format = req.outputType.jsonSchema ?? "json";
|
|
203
|
+
if (req.providerOptions !== void 0) Object.assign(body, req.providerOptions);
|
|
204
|
+
return body;
|
|
205
|
+
}
|
|
206
|
+
function buildHeaders(options) {
|
|
207
|
+
return {
|
|
208
|
+
"content-type": "application/json",
|
|
209
|
+
accept: "application/json",
|
|
210
|
+
...options.headers
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function mapFinishReason(value) {
|
|
214
|
+
switch (value) {
|
|
215
|
+
case "stop":
|
|
216
|
+
case "length": return value;
|
|
217
|
+
case "tool_calls": return "tool-calls";
|
|
218
|
+
default: return "stop";
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function mapUsage(chunk) {
|
|
222
|
+
const promptTokens = chunk.prompt_eval_count ?? 0;
|
|
223
|
+
const completionTokens = chunk.eval_count ?? 0;
|
|
224
|
+
return {
|
|
225
|
+
promptTokens,
|
|
226
|
+
completionTokens,
|
|
227
|
+
totalTokens: promptTokens + completionTokens
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function emitTrustWarning(log, classification, baseUrl) {
|
|
231
|
+
if (classification.trust === "public-cleartext") log("warn", `[ollama] allowInsecureTransport=true accepted for ${baseUrl}`, { baseUrl });
|
|
232
|
+
else if (classification.trust === "public-tls") log("warn", `[ollama] public-TLS endpoint; treating as cloud-tier`, { baseUrl });
|
|
233
|
+
else if (classification.trust === "private") log("warn", `[ollama] private-network endpoint detected (${classification.reason})`, {
|
|
234
|
+
baseUrl,
|
|
235
|
+
acceptsSensitivity: classification.acceptsSensitivity
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function defaultLogger(level, message, meta) {
|
|
239
|
+
const fn = level === "warn" ? console.warn : console.info;
|
|
240
|
+
if (meta !== void 0) fn(`[graphorin/provider] ${message}`, meta);
|
|
241
|
+
else fn(`[graphorin/provider] ${message}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
export { DEFAULT_OLLAMA_BASE_URL, ollamaAdapter };
|
|
246
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","names":["DEFAULT_CAPABILITIES: ProviderCapabilities","capabilities: ProviderCapabilities","usage: Usage","finishReason: FinishReason","chunk: OllamaChatChunk","json: OllamaChatChunk","body: Record<string, unknown>","optionsBlock: Record<string, unknown>"],"sources":["../../src/adapters/ollama.ts"],"sourcesContent":["/**\n * Direct adapter for the Ollama HTTP API. The adapter speaks the\n * native Ollama streaming JSON protocol (`POST /api/chat` returning\n * newline-delimited JSON objects). For operators who prefer the\n * OpenAI-compatible variant exposed by recent Ollama releases, the\n * generic {@link openAICompatibleAdapter} is the better choice — both\n * adapters share the same {@link LocalProviderTrust} classifier and\n * {@link LocalProviderInsecureTransportError} startup behaviour.\n *\n * @packageDocumentation\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n FinishReason,\n Provider,\n ProviderCapabilities,\n ProviderEvent,\n ProviderRequest,\n ProviderResponse,\n Sensitivity,\n Usage,\n} from '@graphorin/core';\n\nimport { LocalProviderInsecureTransportError, ProviderStreamParseError } from '../errors/errors.js';\nimport { callJsonHttp, makeStreamStartEvent, toOllamaChatMessages } from '../internal/http.js';\nimport { parseNdJsonStream } from '../internal/sse.js';\nimport { stripTrailingSlashes } from '../internal/url-utils.js';\nimport { applyReasoningPolicy } from '../reasoning/apply-policy.js';\nimport { resolveReasoningRetention } from '../reasoning/retention.js';\nimport {\n classifyLocalProvider,\n type LocalProviderClassification,\n} from '../trust/classify-local-provider.js';\n\n/**\n * Default Ollama base URL.\n *\n * @stable\n */\nexport const DEFAULT_OLLAMA_BASE_URL = 'http://127.0.0.1:11434';\n\n/**\n * Options accepted by {@link ollamaAdapter}.\n *\n * @stable\n */\nexport interface OllamaAdapterOptions {\n readonly model: string;\n readonly baseUrl?: string;\n readonly chatPath?: string;\n readonly headers?: Readonly<Record<string, string>>;\n readonly fetchImpl?: typeof fetch;\n /**\n * Time-to-response budget per request (PS-24). Default\n * `DEFAULT_REQUEST_TIMEOUT_MS` (120s); `0` disables.\n */\n readonly timeoutMs?: number;\n readonly allowInsecureTransport?: boolean;\n readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;\n readonly capabilities?: Partial<ProviderCapabilities>;\n readonly name?: string;\n readonly logger?: (level: 'warn' | 'info', message: string, meta?: object) => void;\n}\n\nconst DEFAULT_CAPABILITIES: ProviderCapabilities = {\n streaming: true,\n toolCalling: true,\n parallelToolCalls: false,\n multimodal: false,\n structuredOutput: true,\n reasoning: false,\n contextWindow: 8_192,\n maxOutput: 4_096,\n reasoningContract: 'optional',\n};\n\n/**\n * Build a Graphorin {@link Provider} backed by Ollama's native HTTP\n * API. The adapter is fail-safe by default: public-cleartext URLs\n * refuse to start with `LocalProviderInsecureTransportError`.\n *\n * @stable\n */\nexport function ollamaAdapter(options: OllamaAdapterOptions): Provider {\n const baseUrl = options.baseUrl ?? DEFAULT_OLLAMA_BASE_URL;\n const classification = classifyLocalProvider(baseUrl);\n if (classification.trust === 'public-cleartext' && options.allowInsecureTransport !== true) {\n throw new LocalProviderInsecureTransportError(baseUrl);\n }\n const log = options.logger ?? defaultLogger;\n emitTrustWarning(log, classification, baseUrl);\n const acceptsSensitivity = options.acceptsSensitivity ?? classification.acceptsSensitivity;\n const providerName = options.name ?? `ollama-${options.model}`;\n const capabilities: ProviderCapabilities = {\n ...DEFAULT_CAPABILITIES,\n ...options.capabilities,\n };\n const chatPath = options.chatPath ?? '/api/chat';\n const url = `${stripTrailingSlashes(baseUrl)}${chatPath}`;\n return {\n name: providerName,\n modelId: options.model,\n capabilities,\n acceptsSensitivity,\n stream(req) {\n return streamOllama(options, providerName, url, applyOllamaPreflight(req, capabilities));\n },\n async generate(req) {\n return generateOllama(options, providerName, url, applyOllamaPreflight(req, capabilities));\n },\n };\n}\n\nfunction applyOllamaPreflight(\n req: ProviderRequest,\n capabilities: ProviderCapabilities,\n): ProviderRequest {\n const retention = resolveReasoningRetention({\n ...(req.reasoningRetention !== undefined ? { requested: req.reasoningRetention } : {}),\n ...(capabilities.reasoningContract !== undefined\n ? { contract: capabilities.reasoningContract }\n : {}),\n });\n if (retention === 'pass-through-all') return req;\n const filtered = applyReasoningPolicy({ messages: req.messages, retention });\n if (filtered === req.messages) return req;\n return { ...req, messages: filtered };\n}\n\nasync function* streamOllama(\n options: OllamaAdapterOptions,\n providerName: string,\n url: string,\n req: ProviderRequest,\n): AsyncIterable<ProviderEvent> {\n const body = buildBody(options.model, req, true, options.capabilities?.structuredOutput ?? true);\n const resp = await callJsonHttp({\n providerName,\n url,\n headers: buildHeaders(options),\n body,\n ...(req.signal !== undefined ? { signal: req.signal } : {}),\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n yield makeStreamStartEvent({ providerName, modelId: options.model });\n let usage: Usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n let finishReason: FinishReason = 'stop';\n for await (const line of parseNdJsonStream(\n resp.body,\n req.signal !== undefined ? { signal: req.signal } : {},\n )) {\n if (req.signal?.aborted) {\n finishReason = 'aborted'; // PS-12: honest abort reason, not 'stop'\n break;\n }\n let chunk: OllamaChatChunk;\n try {\n chunk = JSON.parse(line) as OllamaChatChunk;\n } catch (cause) {\n throw new ProviderStreamParseError(\n providerName,\n `failed to parse ndjson line: ${(cause as Error).message}`,\n cause,\n );\n }\n if (chunk.message?.content !== undefined && chunk.message.content.length > 0) {\n yield { type: 'text-delta', delta: chunk.message.content };\n }\n if (Array.isArray(chunk.message?.tool_calls)) {\n for (const tc of chunk.message.tool_calls) {\n const toolCallId = tc.id ?? `call_${randomUUID()}`;\n const toolName = tc.function?.name ?? '';\n if (toolName.length === 0) continue;\n yield { type: 'tool-call-start', toolCallId, toolName };\n yield {\n type: 'tool-call-end',\n toolCallId,\n finalArgs: tc.function?.arguments ?? {},\n };\n }\n }\n if (chunk.done === true) {\n finishReason = mapFinishReason(chunk.done_reason);\n usage = mapUsage(chunk);\n break;\n }\n }\n yield { type: 'finish', finishReason, usage };\n}\n\nasync function generateOllama(\n options: OllamaAdapterOptions,\n providerName: string,\n url: string,\n req: ProviderRequest,\n): Promise<ProviderResponse> {\n const body = buildBody(options.model, req, false, options.capabilities?.structuredOutput ?? true);\n const resp = await callJsonHttp({\n providerName,\n url,\n headers: buildHeaders(options),\n body,\n ...(req.signal !== undefined ? { signal: req.signal } : {}),\n ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n let json: OllamaChatChunk;\n try {\n json = (await resp.json()) as OllamaChatChunk;\n } catch (cause) {\n throw new ProviderStreamParseError(providerName, 'response body was not valid JSON', cause);\n }\n return {\n usage: mapUsage(json),\n finishReason: mapFinishReason(json.done_reason),\n ...(typeof json.message?.content === 'string' && json.message.content.length > 0\n ? { text: json.message.content }\n : {}),\n ...(Array.isArray(json.message?.tool_calls) && json.message.tool_calls.length > 0\n ? {\n toolCalls: json.message.tool_calls.map((tc) => ({\n toolCallId: tc.id ?? `call_${randomUUID()}`,\n toolName: tc.function?.name ?? '',\n args: tc.function?.arguments ?? {},\n })),\n }\n : {}),\n };\n}\n\nfunction buildBody(\n model: string,\n req: ProviderRequest,\n stream: boolean,\n structuredOutput: boolean,\n): Record<string, unknown> {\n const messages =\n req.systemMessage !== undefined\n ? [{ role: 'system' as const, content: req.systemMessage }, ...req.messages]\n : req.messages;\n const body: Record<string, unknown> = {\n model,\n messages: toOllamaChatMessages(messages),\n stream,\n };\n if (req.temperature !== undefined || req.maxTokens !== undefined) {\n const optionsBlock: Record<string, unknown> = {};\n if (req.temperature !== undefined) optionsBlock.temperature = req.temperature;\n if (req.maxTokens !== undefined) optionsBlock.num_predict = req.maxTokens;\n body.options = optionsBlock;\n }\n if (req.tools !== undefined && req.tools.length > 0) {\n body.tools = req.tools.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n ...(t.description !== undefined ? { description: t.description } : {}),\n parameters: t.inputSchema,\n },\n }));\n }\n // PS-24: Ollama's native structured output — `format` takes a JSON\n // schema object (or 'json' for schema-less JSON mode).\n if (structuredOutput && req.outputType?.kind === 'structured') {\n body.format = req.outputType.jsonSchema ?? 'json';\n }\n if (req.providerOptions !== undefined) {\n Object.assign(body, req.providerOptions);\n }\n return body;\n}\n\nfunction buildHeaders(options: OllamaAdapterOptions): Record<string, string> {\n return {\n 'content-type': 'application/json',\n accept: 'application/json',\n ...options.headers,\n };\n}\n\nfunction mapFinishReason(value: string | null | undefined): FinishReason {\n switch (value) {\n case 'stop':\n case 'length':\n return value;\n case 'tool_calls':\n return 'tool-calls';\n default:\n return 'stop';\n }\n}\n\nfunction mapUsage(chunk: OllamaChatChunk): Usage {\n const promptTokens = chunk.prompt_eval_count ?? 0;\n const completionTokens = chunk.eval_count ?? 0;\n return {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n };\n}\n\nfunction emitTrustWarning(\n log: (level: 'warn' | 'info', message: string, meta?: object) => void,\n classification: LocalProviderClassification,\n baseUrl: string,\n): void {\n if (classification.trust === 'public-cleartext') {\n log('warn', `[ollama] allowInsecureTransport=true accepted for ${baseUrl}`, { baseUrl });\n } else if (classification.trust === 'public-tls') {\n log('warn', `[ollama] public-TLS endpoint; treating as cloud-tier`, { baseUrl });\n } else if (classification.trust === 'private') {\n log('warn', `[ollama] private-network endpoint detected (${classification.reason})`, {\n baseUrl,\n acceptsSensitivity: classification.acceptsSensitivity,\n });\n }\n}\n\nfunction defaultLogger(level: 'warn' | 'info', message: string, meta?: object): void {\n const fn = level === 'warn' ? console.warn : console.info;\n if (meta !== undefined) {\n fn(`[graphorin/provider] ${message}`, meta);\n } else {\n fn(`[graphorin/provider] ${message}`);\n }\n}\n\ninterface OllamaChatChunk {\n readonly model?: string;\n readonly created_at?: string;\n readonly message?: {\n readonly role?: string;\n readonly content?: string;\n readonly tool_calls?: ReadonlyArray<{\n readonly id?: string;\n readonly function?: { readonly name?: string; readonly arguments?: unknown };\n }>;\n };\n readonly done?: boolean;\n readonly done_reason?: string;\n readonly prompt_eval_count?: number;\n readonly eval_count?: number;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Provider, Sensitivity } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/openai-compatible.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options accepted by {@link openAICompatibleAdapter}.
|
|
7
|
+
*
|
|
8
|
+
* @stable
|
|
9
|
+
*/
|
|
10
|
+
interface OpenAICompatibleAdapterOptions {
|
|
11
|
+
/** Model identifier sent in the request body's `model` field. */
|
|
12
|
+
readonly model: string;
|
|
13
|
+
/**
|
|
14
|
+
* Base URL of the OpenAI-compatible server. The classifier inspects
|
|
15
|
+
* the protocol + host to assign a `LocalProviderTrust` value.
|
|
16
|
+
*/
|
|
17
|
+
readonly baseUrl: string;
|
|
18
|
+
/** Optional REST path override. Defaults to `/v1/chat/completions`. */
|
|
19
|
+
readonly chatPath?: string;
|
|
20
|
+
/** Optional bearer-auth API key. */
|
|
21
|
+
readonly apiKey?: string;
|
|
22
|
+
/** Extra headers merged on top of `content-type` + `accept` defaults. */
|
|
23
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
24
|
+
/** Custom `fetch` implementation; useful for tests. */
|
|
25
|
+
readonly fetchImpl?: typeof fetch;
|
|
26
|
+
/**
|
|
27
|
+
* Acknowledge the risk of running over plaintext HTTP against a
|
|
28
|
+
* public host.
|
|
29
|
+
*/
|
|
30
|
+
readonly allowInsecureTransport?: boolean;
|
|
31
|
+
/** Override for the default `acceptsSensitivity` value. */
|
|
32
|
+
readonly acceptsSensitivity?: ReadonlyArray<Sensitivity>;
|
|
33
|
+
/** Provider name attached to spans / log lines. */
|
|
34
|
+
readonly name?: string;
|
|
35
|
+
/** Optional log sink. */
|
|
36
|
+
readonly logger?: (level: 'warn' | 'info', message: string, meta?: object) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build a Graphorin {@link Provider} backed by an OpenAI-compatible
|
|
40
|
+
* HTTP server. The same code path serves LMStudio, LocalAI, vLLM, and
|
|
41
|
+
* any other compatible self-host endpoint.
|
|
42
|
+
*
|
|
43
|
+
* @stable
|
|
44
|
+
*/
|
|
45
|
+
declare function openAICompatibleAdapter(options: OpenAICompatibleAdapterOptions): Provider;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { OpenAICompatibleAdapterOptions, openAICompatibleAdapter };
|
|
48
|
+
//# sourceMappingURL=openai-compatible.d.ts.map
|