gavio 0.1.0 → 0.3.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/dist/cjs/config.js +106 -0
- package/dist/cjs/errors.js +29 -1
- package/dist/cjs/gateway.js +88 -0
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/interceptors/audit/index.js +4 -1
- package/dist/cjs/interceptors/audit/interceptor.js +11 -0
- package/dist/cjs/interceptors/audit/record.js +17 -3
- package/dist/cjs/interceptors/audit/trace.js +43 -0
- package/dist/cjs/interceptors/cache/embedding.js +53 -0
- package/dist/cjs/interceptors/cache/index.js +9 -5
- package/dist/cjs/interceptors/cache/interceptor.js +80 -0
- package/dist/cjs/interceptors/cache/vector.js +35 -0
- package/dist/cjs/interceptors/governance/budget.js +45 -0
- package/dist/cjs/interceptors/governance/index.js +10 -0
- package/dist/cjs/interceptors/governance/model-policy.js +18 -0
- package/dist/cjs/interceptors/governance/rate-limit.js +46 -0
- package/dist/cjs/interceptors/guardrails/index.js +11 -0
- package/dist/cjs/interceptors/guardrails/interceptor.js +40 -0
- package/dist/cjs/interceptors/guardrails/validator.js +8 -0
- package/dist/cjs/interceptors/guardrails/validators/regex.js +32 -0
- package/dist/cjs/interceptors/guardrails/validators/schema.js +63 -0
- package/dist/cjs/interceptors/injection.js +62 -0
- package/dist/cjs/interceptors/metrics/index.js +9 -0
- package/dist/cjs/interceptors/metrics/interceptor.js +37 -0
- package/dist/cjs/interceptors/metrics/registry.js +0 -0
- package/dist/cjs/interceptors/quality/index.js +7 -0
- package/dist/cjs/interceptors/quality/risk.js +49 -0
- package/dist/cjs/interceptors/reliability/circuit-breaker.js +82 -0
- package/dist/cjs/interceptors/reliability/index.js +8 -1
- package/dist/cjs/interceptors/reliability/load-balancer.js +38 -0
- package/dist/cjs/interceptors/reliability/stream-buffer.js +28 -0
- package/dist/cjs/pricing.js +5 -1
- package/dist/cjs/providers/azure-openai.js +56 -0
- package/dist/cjs/providers/base.js +9 -0
- package/dist/cjs/providers/gemini.js +73 -0
- package/dist/cjs/providers/index.js +22 -6
- package/dist/cjs/providers/ollama.js +41 -0
- package/dist/cjs/request.js +3 -0
- package/dist/cjs/shim/openai.js +57 -0
- package/dist/cjs/types.js +53 -1
- package/dist/esm/config.d.ts +12 -0
- package/dist/esm/config.js +102 -0
- package/dist/esm/errors.d.ts +17 -0
- package/dist/esm/errors.js +24 -0
- package/dist/esm/gateway.d.ts +18 -1
- package/dist/esm/gateway.js +55 -0
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +2 -2
- package/dist/esm/interceptors/audit/index.d.ts +2 -0
- package/dist/esm/interceptors/audit/index.js +1 -0
- package/dist/esm/interceptors/audit/interceptor.d.ts +2 -0
- package/dist/esm/interceptors/audit/interceptor.js +11 -0
- package/dist/esm/interceptors/audit/record.d.ts +4 -2
- package/dist/esm/interceptors/audit/record.js +18 -4
- package/dist/esm/interceptors/audit/trace.d.ts +19 -0
- package/dist/esm/interceptors/audit/trace.js +39 -0
- package/dist/esm/interceptors/cache/embedding.d.ts +14 -0
- package/dist/esm/interceptors/cache/embedding.js +49 -0
- package/dist/esm/interceptors/cache/index.d.ts +7 -4
- package/dist/esm/interceptors/cache/index.js +4 -4
- package/dist/esm/interceptors/cache/interceptor.d.ts +19 -0
- package/dist/esm/interceptors/cache/interceptor.js +77 -0
- package/dist/esm/interceptors/cache/vector.d.ts +9 -0
- package/dist/esm/interceptors/cache/vector.js +32 -0
- package/dist/esm/interceptors/governance/budget.d.ts +11 -0
- package/dist/esm/interceptors/governance/budget.js +42 -0
- package/dist/esm/interceptors/governance/index.d.ts +7 -0
- package/dist/esm/interceptors/governance/index.js +4 -0
- package/dist/esm/interceptors/governance/model-policy.d.ts +8 -0
- package/dist/esm/interceptors/governance/model-policy.js +15 -0
- package/dist/esm/interceptors/governance/rate-limit.d.ts +9 -0
- package/dist/esm/interceptors/governance/rate-limit.js +43 -0
- package/dist/esm/interceptors/guardrails/index.d.ts +6 -0
- package/dist/esm/interceptors/guardrails/index.js +4 -0
- package/dist/esm/interceptors/guardrails/interceptor.d.ts +15 -0
- package/dist/esm/interceptors/guardrails/interceptor.js +37 -0
- package/dist/esm/interceptors/guardrails/validator.d.ts +11 -0
- package/dist/esm/interceptors/guardrails/validator.js +3 -0
- package/dist/esm/interceptors/guardrails/validators/regex.d.ts +6 -0
- package/dist/esm/interceptors/guardrails/validators/regex.js +28 -0
- package/dist/esm/interceptors/guardrails/validators/schema.d.ts +5 -0
- package/dist/esm/interceptors/guardrails/validators/schema.js +60 -0
- package/dist/esm/interceptors/injection.d.ts +17 -0
- package/dist/esm/interceptors/injection.js +59 -0
- package/dist/esm/interceptors/metrics/index.d.ts +5 -0
- package/dist/esm/interceptors/metrics/index.js +3 -0
- package/dist/esm/interceptors/metrics/interceptor.d.ts +22 -0
- package/dist/esm/interceptors/metrics/interceptor.js +33 -0
- package/dist/esm/interceptors/metrics/registry.d.ts +31 -0
- package/dist/esm/interceptors/metrics/registry.js +0 -0
- package/dist/esm/interceptors/quality/index.d.ts +3 -0
- package/dist/esm/interceptors/quality/index.js +2 -0
- package/dist/esm/interceptors/quality/risk.d.ts +32 -0
- package/dist/esm/interceptors/quality/risk.js +44 -0
- package/dist/esm/interceptors/reliability/circuit-breaker.d.ts +15 -0
- package/dist/esm/interceptors/reliability/circuit-breaker.js +78 -0
- package/dist/esm/interceptors/reliability/index.d.ts +5 -0
- package/dist/esm/interceptors/reliability/index.js +3 -0
- package/dist/esm/interceptors/reliability/load-balancer.d.ts +8 -0
- package/dist/esm/interceptors/reliability/load-balancer.js +35 -0
- package/dist/esm/interceptors/reliability/stream-buffer.d.ts +18 -0
- package/dist/esm/interceptors/reliability/stream-buffer.js +24 -0
- package/dist/esm/pricing.js +5 -1
- package/dist/esm/providers/azure-openai.d.ts +28 -0
- package/dist/esm/providers/azure-openai.js +53 -0
- package/dist/esm/providers/base.d.ts +7 -0
- package/dist/esm/providers/base.js +9 -1
- package/dist/esm/providers/gemini.d.ts +36 -0
- package/dist/esm/providers/gemini.js +69 -0
- package/dist/esm/providers/index.d.ts +7 -1
- package/dist/esm/providers/index.js +18 -5
- package/dist/esm/providers/ollama.d.ts +21 -0
- package/dist/esm/providers/ollama.js +38 -0
- package/dist/esm/request.d.ts +4 -1
- package/dist/esm/request.js +4 -1
- package/dist/esm/shim/openai.d.ts +56 -0
- package/dist/esm/shim/openai.js +53 -0
- package/dist/esm/types.d.ts +54 -0
- package/dist/esm/types.js +50 -0
- package/package.json +41 -2
- package/src/config.ts +125 -0
- package/src/errors.ts +28 -0
- package/src/gateway.ts +62 -1
- package/src/index.ts +4 -2
- package/src/interceptors/audit/index.ts +2 -0
- package/src/interceptors/audit/interceptor.ts +13 -0
- package/src/interceptors/audit/record.ts +18 -4
- package/src/interceptors/audit/trace.ts +47 -0
- package/src/interceptors/cache/embedding.ts +53 -0
- package/src/interceptors/cache/index.ts +7 -4
- package/src/interceptors/cache/interceptor.ts +111 -0
- package/src/interceptors/cache/vector.ts +45 -0
- package/src/interceptors/governance/budget.ts +59 -0
- package/src/interceptors/governance/index.ts +8 -0
- package/src/interceptors/governance/model-policy.ts +25 -0
- package/src/interceptors/governance/rate-limit.ts +63 -0
- package/src/interceptors/guardrails/index.ts +7 -0
- package/src/interceptors/guardrails/interceptor.ts +56 -0
- package/src/interceptors/guardrails/validator.ts +14 -0
- package/src/interceptors/guardrails/validators/regex.ts +29 -0
- package/src/interceptors/guardrails/validators/schema.ts +62 -0
- package/src/interceptors/injection.ts +72 -0
- package/src/interceptors/metrics/index.ts +6 -0
- package/src/interceptors/metrics/interceptor.ts +46 -0
- package/src/interceptors/metrics/registry.ts +0 -0
- package/src/interceptors/quality/index.ts +4 -0
- package/src/interceptors/quality/risk.ts +64 -0
- package/src/interceptors/reliability/circuit-breaker.ts +102 -0
- package/src/interceptors/reliability/index.ts +5 -0
- package/src/interceptors/reliability/load-balancer.ts +56 -0
- package/src/interceptors/reliability/stream-buffer.ts +27 -0
- package/src/pricing.ts +5 -1
- package/src/providers/azure-openai.ts +77 -0
- package/src/providers/base.ts +21 -1
- package/src/providers/gemini.ts +95 -0
- package/src/providers/index.ts +21 -5
- package/src/providers/ollama.ts +61 -0
- package/src/request.ts +6 -2
- package/src/shim/openai.ts +76 -0
- package/src/types.ts +77 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** azureOpenaiAdapter — Azure OpenAI deployment-based chat completions. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.azureOpenaiAdapter = azureOpenaiAdapter;
|
|
5
|
+
const errors_js_1 = require("../errors.js");
|
|
6
|
+
const types_js_1 = require("../types.js");
|
|
7
|
+
const base_js_1 = require("./base.js");
|
|
8
|
+
const http_js_1 = require("./http.js");
|
|
9
|
+
const DEFAULT_API_VERSION = '2024-06-01';
|
|
10
|
+
class AzureOpenAIAdapter extends base_js_1.BaseProviderAdapter {
|
|
11
|
+
apiKey;
|
|
12
|
+
endpoint;
|
|
13
|
+
deployment;
|
|
14
|
+
apiVersion;
|
|
15
|
+
timeoutSeconds;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
super(options.pricing);
|
|
18
|
+
this.apiKey = options.apiKey ?? process.env['AZURE_OPENAI_API_KEY'];
|
|
19
|
+
this.endpoint = (options.endpoint ?? process.env['AZURE_OPENAI_ENDPOINT'] ?? '').replace(/\/+$/, '');
|
|
20
|
+
this.deployment = options.deployment ?? process.env['AZURE_OPENAI_DEPLOYMENT'];
|
|
21
|
+
this.apiVersion = options.apiVersion ?? DEFAULT_API_VERSION;
|
|
22
|
+
this.timeoutSeconds = (options.timeoutMs ?? 30_000) / 1000;
|
|
23
|
+
}
|
|
24
|
+
get providerName() {
|
|
25
|
+
return 'azure_openai';
|
|
26
|
+
}
|
|
27
|
+
url(request) {
|
|
28
|
+
const deployment = this.deployment ?? request.model;
|
|
29
|
+
return `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
|
|
30
|
+
}
|
|
31
|
+
async complete(request) {
|
|
32
|
+
if (!this.apiKey || !this.endpoint) {
|
|
33
|
+
throw new errors_js_1.ConfigurationError('AZURE_OPENAI_API_KEY and AZURE_OPENAI_ENDPOINT must be set');
|
|
34
|
+
}
|
|
35
|
+
const started = performance.now();
|
|
36
|
+
const payload = {
|
|
37
|
+
messages: request.messages,
|
|
38
|
+
temperature: request.temperature,
|
|
39
|
+
max_tokens: request.maxTokens,
|
|
40
|
+
};
|
|
41
|
+
const data = await (0, http_js_1.postJson)(this.url(request), payload, { 'api-key': this.apiKey }, this.timeoutSeconds);
|
|
42
|
+
const choices = data['choices'] ?? [];
|
|
43
|
+
const message = choices[0]?.['message'] ?? {};
|
|
44
|
+
const content = message['content'] ?? '';
|
|
45
|
+
const usageData = data['usage'] ?? {};
|
|
46
|
+
const usage = new types_js_1.TokenUsage(usageData['prompt_tokens'] ?? 0, usageData['completion_tokens'] ?? 0);
|
|
47
|
+
return this.buildResponse(request, content, usage, data['model'] ?? request.model, started);
|
|
48
|
+
}
|
|
49
|
+
async healthCheck() {
|
|
50
|
+
return !!(this.apiKey && this.endpoint);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Factory: build an Azure OpenAI provider adapter. */
|
|
54
|
+
function azureOpenaiAdapter(options = {}) {
|
|
55
|
+
return new AzureOpenAIAdapter(options);
|
|
56
|
+
}
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.BaseProviderAdapter = void 0;
|
|
5
5
|
const pricing_js_1 = require("../pricing.js");
|
|
6
6
|
const response_js_1 = require("../response.js");
|
|
7
|
+
const types_js_1 = require("../types.js");
|
|
7
8
|
/** Base class with a shared pricing provider and response builder. */
|
|
8
9
|
class BaseProviderAdapter {
|
|
9
10
|
pricing;
|
|
@@ -13,6 +14,14 @@ class BaseProviderAdapter {
|
|
|
13
14
|
get reportedModelVersion() {
|
|
14
15
|
return null;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Build a response from a fully buffered stream (F-REL-06). Streamed chunks
|
|
19
|
+
* carry text only, so token usage is estimated from prompt + content.
|
|
20
|
+
*/
|
|
21
|
+
buildStreamResponse(request, content, startedAt) {
|
|
22
|
+
const usage = new types_js_1.TokenUsage((0, pricing_js_1.estimateTokens)(request.promptText()), (0, pricing_js_1.estimateTokens)(content));
|
|
23
|
+
return this.buildResponse(request, content, usage, this.reportedModelVersion ?? request.model, startedAt);
|
|
24
|
+
}
|
|
16
25
|
buildResponse(request, content, usage, modelVersion, startedAt) {
|
|
17
26
|
const latencyMs = Math.floor(performance.now() - startedAt);
|
|
18
27
|
return new response_js_1.GavioResponse({
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** geminiAdapter — Google Generative Language API (generateContent). */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.geminiToContents = geminiToContents;
|
|
5
|
+
exports.geminiAdapter = geminiAdapter;
|
|
6
|
+
const errors_js_1 = require("../errors.js");
|
|
7
|
+
const types_js_1 = require("../types.js");
|
|
8
|
+
const base_js_1 = require("./base.js");
|
|
9
|
+
const http_js_1 = require("./http.js");
|
|
10
|
+
const DEFAULT_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta';
|
|
11
|
+
/** Map Gavio messages to Gemini contents + a system instruction. */
|
|
12
|
+
function geminiToContents(messages) {
|
|
13
|
+
let system = null;
|
|
14
|
+
const contents = [];
|
|
15
|
+
for (const m of messages) {
|
|
16
|
+
const text = m.content;
|
|
17
|
+
if (m.role === 'system') {
|
|
18
|
+
system = system ? `${system}\n${text}` : text;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
contents.push({ role: m.role === 'assistant' ? 'model' : 'user', parts: [{ text }] });
|
|
22
|
+
}
|
|
23
|
+
return { system, contents };
|
|
24
|
+
}
|
|
25
|
+
class GeminiAdapter extends base_js_1.BaseProviderAdapter {
|
|
26
|
+
apiKey;
|
|
27
|
+
baseUrl;
|
|
28
|
+
timeoutSeconds;
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
super(options.pricing);
|
|
31
|
+
this.apiKey =
|
|
32
|
+
options.apiKey ?? process.env['GEMINI_API_KEY'] ?? process.env['GOOGLE_API_KEY'];
|
|
33
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
34
|
+
this.timeoutSeconds = (options.timeoutMs ?? 30_000) / 1000;
|
|
35
|
+
}
|
|
36
|
+
get providerName() {
|
|
37
|
+
return 'gemini';
|
|
38
|
+
}
|
|
39
|
+
payload(request) {
|
|
40
|
+
const { system, contents } = geminiToContents(request.messages);
|
|
41
|
+
const payload = {
|
|
42
|
+
contents,
|
|
43
|
+
generationConfig: {
|
|
44
|
+
temperature: request.temperature,
|
|
45
|
+
maxOutputTokens: request.maxTokens,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
if (system)
|
|
49
|
+
payload['systemInstruction'] = { parts: [{ text: system }] };
|
|
50
|
+
return payload;
|
|
51
|
+
}
|
|
52
|
+
async complete(request) {
|
|
53
|
+
if (!this.apiKey)
|
|
54
|
+
throw new errors_js_1.ConfigurationError('GEMINI_API_KEY not set');
|
|
55
|
+
const started = performance.now();
|
|
56
|
+
const url = `${this.baseUrl}/models/${request.model}:generateContent?key=${this.apiKey}`;
|
|
57
|
+
const data = await (0, http_js_1.postJson)(url, this.payload(request), {}, this.timeoutSeconds);
|
|
58
|
+
const candidates = data['candidates'] ?? [{}];
|
|
59
|
+
const contentObj = candidates[0]?.['content'] ?? {};
|
|
60
|
+
const parts = contentObj['parts'] ?? [];
|
|
61
|
+
const content = parts.map((p) => p.text ?? '').join('');
|
|
62
|
+
const um = data['usageMetadata'] ?? {};
|
|
63
|
+
const usage = new types_js_1.TokenUsage(um['promptTokenCount'] ?? 0, um['candidatesTokenCount'] ?? 0);
|
|
64
|
+
return this.buildResponse(request, content, usage, request.model, started);
|
|
65
|
+
}
|
|
66
|
+
async healthCheck() {
|
|
67
|
+
return !!this.apiKey;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Factory: build a Gemini provider adapter. */
|
|
71
|
+
function geminiAdapter(options = {}) {
|
|
72
|
+
return new GeminiAdapter(options);
|
|
73
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/** Provider adapters and the provider registry. */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.Provider = exports.anthropicAdapter = exports.openaiAdapter = exports.mockProvider = exports.BaseProviderAdapter = void 0;
|
|
4
|
+
exports.Provider = exports.ollamaAdapter = exports.azureOpenaiAdapter = exports.geminiAdapter = exports.anthropicAdapter = exports.openaiAdapter = exports.mockProvider = exports.BaseProviderAdapter = void 0;
|
|
5
5
|
exports.buildAdapter = buildAdapter;
|
|
6
6
|
const errors_js_1 = require("../errors.js");
|
|
7
7
|
const types_js_1 = require("../types.js");
|
|
8
8
|
const anthropic_js_1 = require("./anthropic.js");
|
|
9
|
+
const azure_openai_js_1 = require("./azure-openai.js");
|
|
10
|
+
const gemini_js_1 = require("./gemini.js");
|
|
9
11
|
const mock_js_1 = require("./mock.js");
|
|
12
|
+
const ollama_js_1 = require("./ollama.js");
|
|
10
13
|
const openai_js_1 = require("./openai.js");
|
|
11
14
|
var base_js_1 = require("./base.js");
|
|
12
15
|
Object.defineProperty(exports, "BaseProviderAdapter", { enumerable: true, get: function () { return base_js_1.BaseProviderAdapter; } });
|
|
@@ -16,19 +19,32 @@ var openai_js_2 = require("./openai.js");
|
|
|
16
19
|
Object.defineProperty(exports, "openaiAdapter", { enumerable: true, get: function () { return openai_js_2.openaiAdapter; } });
|
|
17
20
|
var anthropic_js_2 = require("./anthropic.js");
|
|
18
21
|
Object.defineProperty(exports, "anthropicAdapter", { enumerable: true, get: function () { return anthropic_js_2.anthropicAdapter; } });
|
|
22
|
+
var gemini_js_2 = require("./gemini.js");
|
|
23
|
+
Object.defineProperty(exports, "geminiAdapter", { enumerable: true, get: function () { return gemini_js_2.geminiAdapter; } });
|
|
24
|
+
var azure_openai_js_2 = require("./azure-openai.js");
|
|
25
|
+
Object.defineProperty(exports, "azureOpenaiAdapter", { enumerable: true, get: function () { return azure_openai_js_2.azureOpenaiAdapter; } });
|
|
26
|
+
var ollama_js_2 = require("./ollama.js");
|
|
27
|
+
Object.defineProperty(exports, "ollamaAdapter", { enumerable: true, get: function () { return ollama_js_2.ollamaAdapter; } });
|
|
19
28
|
var types_js_2 = require("../types.js");
|
|
20
29
|
Object.defineProperty(exports, "Provider", { enumerable: true, get: function () { return types_js_2.Provider; } });
|
|
21
|
-
/** Instantiate the default adapter for a provider id.
|
|
30
|
+
/** Instantiate the default adapter for a provider id. */
|
|
22
31
|
function buildAdapter(provider, pricing) {
|
|
23
32
|
const p = (0, types_js_1.coerceProvider)(provider);
|
|
33
|
+
const opts = pricing ? { pricing } : {};
|
|
24
34
|
switch (p) {
|
|
25
35
|
case types_js_1.Provider.OPENAI:
|
|
26
|
-
return (0, openai_js_1.openaiAdapter)(
|
|
36
|
+
return (0, openai_js_1.openaiAdapter)(opts);
|
|
27
37
|
case types_js_1.Provider.ANTHROPIC:
|
|
28
|
-
return (0, anthropic_js_1.anthropicAdapter)(
|
|
38
|
+
return (0, anthropic_js_1.anthropicAdapter)(opts);
|
|
39
|
+
case types_js_1.Provider.GEMINI:
|
|
40
|
+
return (0, gemini_js_1.geminiAdapter)(opts);
|
|
41
|
+
case types_js_1.Provider.AZURE_OPENAI:
|
|
42
|
+
return (0, azure_openai_js_1.azureOpenaiAdapter)(opts);
|
|
43
|
+
case types_js_1.Provider.OLLAMA:
|
|
44
|
+
return (0, ollama_js_1.ollamaAdapter)(opts);
|
|
29
45
|
case types_js_1.Provider.MOCK:
|
|
30
|
-
return (0, mock_js_1.mockProvider)(
|
|
46
|
+
return (0, mock_js_1.mockProvider)(opts);
|
|
31
47
|
default:
|
|
32
|
-
throw new errors_js_1.ConfigurationError(`Provider '${p}' is not available
|
|
48
|
+
throw new errors_js_1.ConfigurationError(`Provider '${p}' is not available (v0.3.0 adds bedrock, cohere)`);
|
|
33
49
|
}
|
|
34
50
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** ollamaAdapter — local models via the Ollama chat API. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ollamaAdapter = ollamaAdapter;
|
|
5
|
+
const types_js_1 = require("../types.js");
|
|
6
|
+
const base_js_1 = require("./base.js");
|
|
7
|
+
const http_js_1 = require("./http.js");
|
|
8
|
+
const DEFAULT_BASE_URL = 'http://localhost:11434';
|
|
9
|
+
class OllamaAdapter extends base_js_1.BaseProviderAdapter {
|
|
10
|
+
baseUrl;
|
|
11
|
+
timeoutSeconds;
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
super(options.pricing);
|
|
14
|
+
this.baseUrl = (options.baseUrl ?? process.env['OLLAMA_HOST'] ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
15
|
+
this.timeoutSeconds = (options.timeoutMs ?? 60_000) / 1000;
|
|
16
|
+
}
|
|
17
|
+
get providerName() {
|
|
18
|
+
return 'ollama';
|
|
19
|
+
}
|
|
20
|
+
async complete(request) {
|
|
21
|
+
const started = performance.now();
|
|
22
|
+
const payload = {
|
|
23
|
+
model: request.model,
|
|
24
|
+
messages: request.messages,
|
|
25
|
+
stream: false,
|
|
26
|
+
options: { temperature: request.temperature },
|
|
27
|
+
};
|
|
28
|
+
const data = await (0, http_js_1.postJson)(`${this.baseUrl}/api/chat`, payload, {}, this.timeoutSeconds);
|
|
29
|
+
const message = data['message'] ?? {};
|
|
30
|
+
const content = message['content'] ?? '';
|
|
31
|
+
const usage = new types_js_1.TokenUsage(data['prompt_eval_count'] ?? 0, data['eval_count'] ?? 0);
|
|
32
|
+
return this.buildResponse(request, content, usage, data['model'] ?? request.model, started);
|
|
33
|
+
}
|
|
34
|
+
async healthCheck() {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Factory: build an Ollama provider adapter. */
|
|
39
|
+
function ollamaAdapter(options = {}) {
|
|
40
|
+
return new OllamaAdapter(options);
|
|
41
|
+
}
|
package/dist/cjs/request.js
CHANGED
|
@@ -19,6 +19,7 @@ class GavioRequest {
|
|
|
19
19
|
sessionId;
|
|
20
20
|
options;
|
|
21
21
|
metadata;
|
|
22
|
+
lineage;
|
|
22
23
|
constructor(init) {
|
|
23
24
|
this.messages = init.messages;
|
|
24
25
|
this.model = init.model;
|
|
@@ -29,6 +30,7 @@ class GavioRequest {
|
|
|
29
30
|
this.sessionId = init.sessionId ?? null;
|
|
30
31
|
this.options = init.options ?? {};
|
|
31
32
|
this.metadata = init.metadata ?? {};
|
|
33
|
+
this.lineage = init.lineage != null ? types_js_1.PromptLineage.from(init.lineage) : null;
|
|
32
34
|
}
|
|
33
35
|
get temperature() {
|
|
34
36
|
const t = this.options['temperature'];
|
|
@@ -54,6 +56,7 @@ class GavioRequest {
|
|
|
54
56
|
sessionId: this.sessionId,
|
|
55
57
|
options: { ...this.options },
|
|
56
58
|
metadata: { ...this.metadata },
|
|
59
|
+
lineage: this.lineage,
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
62
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI drop-in shim (F-DX-04) — point existing OpenAI SDK code at Gavio.
|
|
4
|
+
*
|
|
5
|
+
* import { Gateway } from 'gavio'
|
|
6
|
+
* import { GavioOpenAI } from 'gavio/shim/openai'
|
|
7
|
+
*
|
|
8
|
+
* const client = new GavioOpenAI(new Gateway({ provider: 'openai', model: 'gpt-4o' }))
|
|
9
|
+
* const resp = await client.chat.completions.create({
|
|
10
|
+
* model: 'gpt-4o', messages: [{ role: 'user', content: 'hi' }],
|
|
11
|
+
* })
|
|
12
|
+
* console.log(resp.choices[0].message.content)
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.GavioOpenAI = void 0;
|
|
16
|
+
function toCompletion(resp) {
|
|
17
|
+
return {
|
|
18
|
+
id: resp.traceId,
|
|
19
|
+
object: 'chat.completion',
|
|
20
|
+
model: resp.modelVersion || resp.model,
|
|
21
|
+
choices: [
|
|
22
|
+
{ index: 0, message: { role: 'assistant', content: resp.content }, finish_reason: 'stop' },
|
|
23
|
+
],
|
|
24
|
+
usage: {
|
|
25
|
+
prompt_tokens: resp.usage.promptTokens,
|
|
26
|
+
completion_tokens: resp.usage.completionTokens,
|
|
27
|
+
total_tokens: resp.usage.totalTokens,
|
|
28
|
+
},
|
|
29
|
+
gavio: {
|
|
30
|
+
costUsd: resp.costUsd,
|
|
31
|
+
cacheHit: resp.cacheHit,
|
|
32
|
+
interceptorsFired: resp.interceptorsFired,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
class Completions {
|
|
37
|
+
gw;
|
|
38
|
+
constructor(gw) {
|
|
39
|
+
this.gw = gw;
|
|
40
|
+
}
|
|
41
|
+
async create(params) {
|
|
42
|
+
const resp = await this.gw.complete({
|
|
43
|
+
messages: params.messages,
|
|
44
|
+
model: params.model,
|
|
45
|
+
options: { temperature: params.temperature ?? 0.7, maxTokens: params.max_tokens ?? 1024 },
|
|
46
|
+
});
|
|
47
|
+
return toCompletion(resp);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** OpenAI-client-shaped facade over a Gavio Gateway. */
|
|
51
|
+
class GavioOpenAI {
|
|
52
|
+
chat;
|
|
53
|
+
constructor(gateway) {
|
|
54
|
+
this.chat = { completions: new Completions(gateway) };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.GavioOpenAI = GavioOpenAI;
|
package/dist/cjs/types.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/** Shared enums (as string unions / const objects) and utility types. */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.TokenUsage = exports.GuardrailOutcome = exports.Sensitivity = exports.PiiMode = exports.CacheType = exports.Provider = void 0;
|
|
4
|
+
exports.PromptLineage = exports.RagChunk = exports.TokenUsage = exports.GuardrailOutcome = exports.Sensitivity = exports.PiiMode = exports.CacheType = exports.Provider = void 0;
|
|
5
5
|
exports.coerceProvider = coerceProvider;
|
|
6
6
|
/** Supported LLM providers. String-valued for easy config + logging. */
|
|
7
7
|
exports.Provider = {
|
|
@@ -59,3 +59,55 @@ class TokenUsage {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
exports.TokenUsage = TokenUsage;
|
|
62
|
+
/**
|
|
63
|
+
* A single retrieved source that contributed to a prompt. Carries a *reference*
|
|
64
|
+
* to the source — never the retrieved text — so prompt lineage stays within the
|
|
65
|
+
* audit record's metadata-only contract.
|
|
66
|
+
*/
|
|
67
|
+
class RagChunk {
|
|
68
|
+
source;
|
|
69
|
+
chunkId;
|
|
70
|
+
score;
|
|
71
|
+
constructor(init) {
|
|
72
|
+
this.source = init.source;
|
|
73
|
+
this.chunkId = init.chunkId ?? null;
|
|
74
|
+
this.score = init.score ?? null;
|
|
75
|
+
}
|
|
76
|
+
toJSON() {
|
|
77
|
+
return { source: this.source, chunkId: this.chunkId, score: this.score };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.RagChunk = RagChunk;
|
|
81
|
+
/**
|
|
82
|
+
* Provenance for a rendered prompt (F-OBS-04): the template, the variable
|
|
83
|
+
* bindings interpolated into it, and the RAG chunk sources retrieved for it.
|
|
84
|
+
*
|
|
85
|
+
* Attached to a GavioRequest by the caller and copied into the AuditRecord so
|
|
86
|
+
* any prompt can be reconstructed and debugged. RAG chunk text is never stored
|
|
87
|
+
* — only source references (see {@link RagChunk}).
|
|
88
|
+
*/
|
|
89
|
+
class PromptLineage {
|
|
90
|
+
templateId;
|
|
91
|
+
templateVersion;
|
|
92
|
+
variables;
|
|
93
|
+
ragChunks;
|
|
94
|
+
constructor(init = {}) {
|
|
95
|
+
this.templateId = init.templateId ?? null;
|
|
96
|
+
this.templateVersion = init.templateVersion ?? null;
|
|
97
|
+
this.variables = init.variables ?? {};
|
|
98
|
+
this.ragChunks = (init.ragChunks ?? []).map((c) => c instanceof RagChunk ? c : new RagChunk(c));
|
|
99
|
+
}
|
|
100
|
+
/** Coerce a PromptLineage instance or plain init object into a PromptLineage. */
|
|
101
|
+
static from(value) {
|
|
102
|
+
return value instanceof PromptLineage ? value : new PromptLineage(value);
|
|
103
|
+
}
|
|
104
|
+
toJSON() {
|
|
105
|
+
return {
|
|
106
|
+
templateId: this.templateId,
|
|
107
|
+
templateVersion: this.templateVersion,
|
|
108
|
+
variables: this.variables,
|
|
109
|
+
ragChunks: this.ragChunks.map((c) => c.toJSON()),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.PromptLineage = PromptLineage;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loader (F-DX-05) — build a Gateway from an object or a JSON file.
|
|
3
|
+
*
|
|
4
|
+
* const gw = await Gateway.fromConfig('gateway.json')
|
|
5
|
+
*
|
|
6
|
+
* JSON is supported out of the box; string values expand ${ENV_VAR}.
|
|
7
|
+
*/
|
|
8
|
+
import { Gateway } from './gateway.js';
|
|
9
|
+
type Cfg = Record<string, unknown>;
|
|
10
|
+
export declare function loadConfig(path: string): Cfg;
|
|
11
|
+
export declare function buildFromConfig(config: Cfg): Gateway;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loader (F-DX-05) — build a Gateway from an object or a JSON file.
|
|
3
|
+
*
|
|
4
|
+
* const gw = await Gateway.fromConfig('gateway.json')
|
|
5
|
+
*
|
|
6
|
+
* JSON is supported out of the box; string values expand ${ENV_VAR}.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
import { ConfigurationError } from './errors.js';
|
|
10
|
+
import { Gateway } from './gateway.js';
|
|
11
|
+
import { auditInterceptor } from './interceptors/audit/index.js';
|
|
12
|
+
import { hashingEmbedder, semanticCache } from './interceptors/cache/index.js';
|
|
13
|
+
import { costControl, modelPolicy, rateLimiter } from './interceptors/governance/index.js';
|
|
14
|
+
import { promptInjectionGuard } from './interceptors/injection.js';
|
|
15
|
+
import { piiGuard } from './interceptors/pii/index.js';
|
|
16
|
+
import { retryInterceptor, timeoutPolicy } from './interceptors/reliability/index.js';
|
|
17
|
+
export function loadConfig(path) {
|
|
18
|
+
const text = readFileSync(path, 'utf8');
|
|
19
|
+
if (!path.endsWith('.json')) {
|
|
20
|
+
throw new ConfigurationError('JS config loader supports JSON only (use .json)');
|
|
21
|
+
}
|
|
22
|
+
return expand(JSON.parse(text));
|
|
23
|
+
}
|
|
24
|
+
function expand(obj) {
|
|
25
|
+
if (Array.isArray(obj))
|
|
26
|
+
return obj.map(expand);
|
|
27
|
+
if (obj && typeof obj === 'object') {
|
|
28
|
+
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, expand(v)]));
|
|
29
|
+
}
|
|
30
|
+
if (typeof obj === 'string') {
|
|
31
|
+
return obj.replace(/\$\{(\w+)\}/g, (_, v) => process.env[v] ?? '');
|
|
32
|
+
}
|
|
33
|
+
return obj;
|
|
34
|
+
}
|
|
35
|
+
export function buildFromConfig(config) {
|
|
36
|
+
const gatewayOptions = {};
|
|
37
|
+
if (config['provider'])
|
|
38
|
+
gatewayOptions['provider'] = config['provider'];
|
|
39
|
+
if (config['model'])
|
|
40
|
+
gatewayOptions['model'] = config['model'];
|
|
41
|
+
if (config['devMode'] ?? config['dev_mode'])
|
|
42
|
+
gatewayOptions['devMode'] = true;
|
|
43
|
+
if (config['dryRun'] ?? config['dry_run'])
|
|
44
|
+
gatewayOptions['dryRun'] = true;
|
|
45
|
+
let gw = new Gateway(gatewayOptions);
|
|
46
|
+
const ic = config['interceptors'] ?? {};
|
|
47
|
+
const cfg = (name) => {
|
|
48
|
+
const entry = ic[name];
|
|
49
|
+
return entry && entry['enabled'] !== false ? entry : null;
|
|
50
|
+
};
|
|
51
|
+
let c;
|
|
52
|
+
if ((c = cfg('audit'))) {
|
|
53
|
+
gw = gw.use(auditInterceptor({
|
|
54
|
+
sink: c['sink'] ?? 'stdout',
|
|
55
|
+
hashChain: Boolean(c['hashChain'] ?? c['hash_chain']),
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
if ((c = cfg('prompt_injection'))) {
|
|
59
|
+
gw = gw.use(promptInjectionGuard({ action: c['action'] ?? 'block' }));
|
|
60
|
+
}
|
|
61
|
+
if ((c = cfg('pii_guard'))) {
|
|
62
|
+
gw = gw.use(piiGuard({
|
|
63
|
+
sensitivity: c['sensitivity'] ?? 'strict',
|
|
64
|
+
mode: c['mode'] ?? 'redact',
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
if ((c = cfg('cost_control'))) {
|
|
68
|
+
gw = gw.use(costControl({
|
|
69
|
+
hardCapUsd: Number(c['hardCapUsd'] ?? c['hard_cap_usd']),
|
|
70
|
+
softCapUsd: (c['softCapUsd'] ?? c['soft_cap_usd']),
|
|
71
|
+
scope: c['scope'] ?? 'global',
|
|
72
|
+
window: c['window'] ?? 'day',
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
if ((c = cfg('rate_limiter'))) {
|
|
76
|
+
gw = gw.use(rateLimiter({
|
|
77
|
+
maxRequestsPerMinute: (c['maxRequestsPerMinute'] ?? c['max_requests_per_minute']),
|
|
78
|
+
maxTokensPerMinute: (c['maxTokensPerMinute'] ?? c['max_tokens_per_minute']),
|
|
79
|
+
scope: c['scope'] ?? 'global',
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
if ((c = cfg('model_policy'))) {
|
|
83
|
+
gw = gw.use(modelPolicy({ roles: c['roles'] ?? {} }));
|
|
84
|
+
}
|
|
85
|
+
if ((c = cfg('semantic_cache'))) {
|
|
86
|
+
const embedder = (c['enableSemantic'] ?? c['enable_semantic']) ? hashingEmbedder() : undefined;
|
|
87
|
+
gw = gw.use(semanticCache({
|
|
88
|
+
embedder,
|
|
89
|
+
similarityThreshold: Number(c['similarityThreshold'] ?? c['similarity_threshold'] ?? 0.95),
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
if ((c = cfg('timeout'))) {
|
|
93
|
+
gw = gw.use(timeoutPolicy({ timeoutSeconds: Number(c['timeoutSeconds'] ?? c['timeout_seconds'] ?? 30) }));
|
|
94
|
+
}
|
|
95
|
+
if ((c = cfg('retry'))) {
|
|
96
|
+
gw = gw.use(retryInterceptor({
|
|
97
|
+
maxAttempts: Number(c['maxAttempts'] ?? c['max_attempts'] ?? 3),
|
|
98
|
+
baseDelayMs: Number(c['baseDelayMs'] ?? c['base_delay_ms'] ?? 500),
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
return gw;
|
|
102
|
+
}
|
package/dist/esm/errors.d.ts
CHANGED
|
@@ -31,6 +31,23 @@ export declare class PiiBlockedError extends GavioError {
|
|
|
31
31
|
/** A hard budget cap was exceeded. Never swallow this — surface to user. */
|
|
32
32
|
export declare class BudgetExceededError extends GavioError {
|
|
33
33
|
}
|
|
34
|
+
/** The circuit breaker is open; the call was rejected without hitting the provider. */
|
|
35
|
+
export declare class CircuitOpenError extends ProviderUnavailableError {
|
|
36
|
+
}
|
|
37
|
+
/** A local rate limit (requests/tokens per minute) was exceeded. */
|
|
38
|
+
export declare class RateLimitExceededError extends GavioError {
|
|
39
|
+
}
|
|
40
|
+
/** The caller's role is not permitted to use the requested model (RBAC). */
|
|
41
|
+
export declare class ModelNotAllowedError extends GavioError {
|
|
42
|
+
readonly role: string;
|
|
43
|
+
readonly model: string;
|
|
44
|
+
constructor(role: string, model: string);
|
|
45
|
+
}
|
|
34
46
|
/** Output failed a guardrail validator with onFailure='error'. */
|
|
35
47
|
export declare class GuardrailViolationError extends GavioError {
|
|
36
48
|
}
|
|
49
|
+
/** A prompt-injection attempt was detected and the guard is in block mode. */
|
|
50
|
+
export declare class PromptInjectionError extends GavioError {
|
|
51
|
+
readonly patterns: string[];
|
|
52
|
+
constructor(patterns: string[]);
|
|
53
|
+
}
|
package/dist/esm/errors.js
CHANGED
|
@@ -39,6 +39,30 @@ export class PiiBlockedError extends GavioError {
|
|
|
39
39
|
/** A hard budget cap was exceeded. Never swallow this — surface to user. */
|
|
40
40
|
export class BudgetExceededError extends GavioError {
|
|
41
41
|
}
|
|
42
|
+
/** The circuit breaker is open; the call was rejected without hitting the provider. */
|
|
43
|
+
export class CircuitOpenError extends ProviderUnavailableError {
|
|
44
|
+
}
|
|
45
|
+
/** A local rate limit (requests/tokens per minute) was exceeded. */
|
|
46
|
+
export class RateLimitExceededError extends GavioError {
|
|
47
|
+
}
|
|
48
|
+
/** The caller's role is not permitted to use the requested model (RBAC). */
|
|
49
|
+
export class ModelNotAllowedError extends GavioError {
|
|
50
|
+
role;
|
|
51
|
+
model;
|
|
52
|
+
constructor(role, model) {
|
|
53
|
+
super(`role ${JSON.stringify(role)} may not use model ${JSON.stringify(model)}`);
|
|
54
|
+
this.role = role;
|
|
55
|
+
this.model = model;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
42
58
|
/** Output failed a guardrail validator with onFailure='error'. */
|
|
43
59
|
export class GuardrailViolationError extends GavioError {
|
|
44
60
|
}
|
|
61
|
+
/** A prompt-injection attempt was detected and the guard is in block mode. */
|
|
62
|
+
export class PromptInjectionError extends GavioError {
|
|
63
|
+
patterns;
|
|
64
|
+
constructor(patterns) {
|
|
65
|
+
super(`prompt injection detected: ${patterns.join(', ')}`);
|
|
66
|
+
this.patterns = patterns;
|
|
67
|
+
}
|
|
68
|
+
}
|
package/dist/esm/gateway.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { PricingProvider } from './pricing.js';
|
|
|
4
4
|
import type { ProviderAdapter } from './providers/base.js';
|
|
5
5
|
import type { GavioResponse } from './response.js';
|
|
6
6
|
import { Provider } from './types.js';
|
|
7
|
-
import type { Message } from './types.js';
|
|
7
|
+
import type { Message, PromptLineage, PromptLineageInit } from './types.js';
|
|
8
8
|
export interface GatewayOptions {
|
|
9
9
|
provider?: Provider | string;
|
|
10
10
|
model?: string;
|
|
@@ -22,6 +22,8 @@ export interface CompleteOptions {
|
|
|
22
22
|
metadata?: Record<string, unknown>;
|
|
23
23
|
/** Provider sampling options (temperature, maxTokens, etc.). */
|
|
24
24
|
options?: Record<string, unknown>;
|
|
25
|
+
/** Prompt provenance (F-OBS-04): template, variables, and RAG chunk sources. */
|
|
26
|
+
lineage?: PromptLineage | PromptLineageInit | null;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Routes a request through the interceptor pipeline to a provider.
|
|
@@ -39,6 +41,11 @@ export declare class Gateway {
|
|
|
39
41
|
private readonly pricing;
|
|
40
42
|
private readonly interceptors;
|
|
41
43
|
constructor(options?: GatewayOptions);
|
|
44
|
+
/**
|
|
45
|
+
* Build a Gateway from a config object or a JSON file path (F-DX-05).
|
|
46
|
+
* Async so the config module loads lazily (avoids a circular import).
|
|
47
|
+
*/
|
|
48
|
+
static fromConfig(config: string | Record<string, unknown>): Promise<Gateway>;
|
|
42
49
|
/** Register an interceptor or executor policy. First-registered = outermost. */
|
|
43
50
|
use(interceptor: Interceptor): this;
|
|
44
51
|
/** Supply a provider adapter explicitly (overrides `provider`). */
|
|
@@ -46,6 +53,16 @@ export declare class Gateway {
|
|
|
46
53
|
get model(): string;
|
|
47
54
|
get providerName(): string;
|
|
48
55
|
complete(opts: CompleteOptions): Promise<GavioResponse>;
|
|
56
|
+
/**
|
|
57
|
+
* Stream a completion, buffering the provider stream (F-REL-06).
|
|
58
|
+
*
|
|
59
|
+
* The provider stream is buffered in full so the post-interceptor pipeline
|
|
60
|
+
* (guardrails, PII restore, audit) runs on the complete response before any
|
|
61
|
+
* chunk reaches the caller. Pre/post interceptors run via the chain; executor
|
|
62
|
+
* policies (retry, circuit breaker, cache) are not applied to the streaming
|
|
63
|
+
* path.
|
|
64
|
+
*/
|
|
65
|
+
stream(opts: CompleteOptions): AsyncGenerator<string>;
|
|
49
66
|
healthCheck(): Promise<boolean>;
|
|
50
67
|
private buildPipeline;
|
|
51
68
|
private wrapPolicy;
|