@gmickel/gno 1.45.1 → 2.0.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 +1 -1
- package/THIRD_PARTY_NOTICES.md +46 -0
- package/assets/skill/SKILL.md +7 -6
- package/assets/skill/cli-reference.md +14 -6
- package/assets/skill/mcp-reference.md +4 -1
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +32 -33
- package/bunfig.toml +2 -0
- package/package.json +40 -26
- package/spec/cli.md +30 -11
- package/spec/db/schema.sql +146 -1
- package/spec/mcp.md +26 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +2 -0
- package/src/cli/commands/ask.ts +6 -1
- package/src/cli/commands/daemon.ts +21 -8
- package/src/cli/commands/embed.ts +77 -41
- package/src/cli/commands/mcp/install.ts +20 -0
- package/src/cli/commands/mcp/paths.ts +25 -0
- package/src/cli/commands/mcp/status.ts +6 -0
- package/src/cli/detach.ts +3 -2
- package/src/cli/program.ts +6 -0
- package/src/config/types.ts +3 -3
- package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
- package/src/converters/adapters/officeparser/adapter.ts +1 -2
- package/src/converters/versions.ts +6 -8
- package/src/core/context-evidence.ts +8 -4
- package/src/core/job-manager.ts +95 -13
- package/src/core/network-boundary-inventory.ts +10 -0
- package/src/core/shutdown-budget.ts +45 -0
- package/src/embed/backlog.ts +107 -4
- package/src/embed/batch.ts +42 -2
- package/src/embed/fingerprint.ts +16 -0
- package/src/embed/retry.ts +113 -5
- package/src/embed/variant-backlog.ts +105 -0
- package/src/embed/variant-plan.ts +62 -0
- package/src/embed/variant-retry.ts +113 -0
- package/src/ingestion/graph-reconciliation.ts +327 -0
- package/src/ingestion/sync.ts +9 -272
- package/src/llm/http-inference.ts +6 -0
- package/src/llm/httpEmbedding.ts +37 -6
- package/src/llm/httpGeneration.ts +18 -3
- package/src/llm/httpRerank.ts +23 -5
- package/src/llm/inference-cancellation.ts +168 -0
- package/src/llm/inference-scope.ts +202 -0
- package/src/llm/lazy-ports.ts +115 -0
- package/src/llm/native-worker/client.ts +541 -0
- package/src/llm/native-worker/dispatcher.ts +228 -0
- package/src/llm/native-worker/embedding-identity.ts +33 -0
- package/src/llm/native-worker/entry.ts +173 -0
- package/src/llm/native-worker/errors.ts +32 -0
- package/src/llm/native-worker/evaluation.ts +16 -0
- package/src/llm/native-worker/owned-exit.ts +108 -0
- package/src/llm/native-worker/owner.ts +141 -0
- package/src/llm/native-worker/ports.ts +317 -0
- package/src/llm/native-worker/protocol.ts +442 -0
- package/src/llm/native-worker/runtime-config.ts +92 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
- package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
- package/src/llm/nodeLlamaCpp/generation.ts +34 -5
- package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
- package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
- package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
- package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
- package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
- package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
- package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
- package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
- package/src/llm/types.ts +35 -5
- package/src/mcp/context.ts +27 -0
- package/src/mcp/http-transport.ts +12 -10
- package/src/mcp/server.ts +3 -0
- package/src/mcp/tool-profile.ts +30 -8
- package/src/mcp/tools/context.ts +8 -11
- package/src/mcp/tools/embed.ts +1 -1
- package/src/mcp/tools/index-cmd.ts +1 -1
- package/src/mcp/tools/index.ts +10 -8
- package/src/mcp/tools/query.ts +14 -30
- package/src/mcp/tools/vsearch.ts +1 -1
- package/src/pipeline/answer.ts +23 -3
- package/src/pipeline/claim-verifier.ts +6 -0
- package/src/pipeline/expansion.ts +43 -40
- package/src/pipeline/explain.ts +6 -2
- package/src/pipeline/filters.ts +63 -0
- package/src/pipeline/fusion.ts +29 -9
- package/src/pipeline/graph-retrieval.ts +29 -9
- package/src/pipeline/hybrid.ts +198 -55
- package/src/pipeline/hydration.ts +161 -0
- package/src/pipeline/owner-fusion.ts +87 -0
- package/src/pipeline/rerank.ts +35 -11
- package/src/pipeline/search.ts +13 -2
- package/src/pipeline/types.ts +5 -3
- package/src/pipeline/vsearch.ts +87 -7
- package/src/sdk/client.ts +47 -3
- package/src/sdk/embed.ts +63 -39
- package/src/serve/background-runtime.ts +1 -1
- package/src/serve/context.ts +41 -56
- package/src/serve/embed-scheduler.ts +58 -35
- package/src/serve/public/components/IndexingProgress.tsx +46 -60
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/shiki-language-ids.ts +14 -0
- package/src/serve/resident-admission.ts +36 -36
- package/src/serve/resident-background-work.ts +20 -2
- package/src/serve/resident-request.ts +11 -5
- package/src/serve/resident-runtime.ts +97 -61
- package/src/serve/resident-shutdown.ts +153 -0
- package/src/serve/routes/api.ts +3 -1
- package/src/serve/server.ts +47 -26
- package/src/store/migrations/028-vector-variants.ts +54 -0
- package/src/store/migrations/029-graph-reference-state.ts +77 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +251 -183
- package/src/store/sqlite/eligibility.ts +174 -0
- package/src/store/sqlite/graph-edge-application.ts +66 -0
- package/src/store/sqlite/graph-reference-state.ts +194 -0
- package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
- package/src/store/types.ts +80 -12
- package/src/store/vector/eligibility.ts +36 -0
- package/src/store/vector/freshness.ts +33 -6
- package/src/store/vector/lazy.ts +81 -0
- package/src/store/vector/sqlite-vec.ts +106 -54
- package/src/store/vector/stats.ts +14 -3
- package/src/store/vector/types.ts +35 -2
- package/src/store/vector/variant-search.ts +192 -0
- package/src/store/vector/variants.ts +451 -0
- package/vendor/converters/markitdown-ts/LICENSE +21 -0
- package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
- package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
- package/vendor/converters/markitdown-ts/package.json +77 -0
- package/vendor/converters/officeparser/LICENSE +21 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
- package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
- package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
- package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
- package/vendor/converters/officeparser/dist/cli.js +381 -0
- package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
- package/vendor/converters/officeparser/dist/defaults.js +218 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
- package/vendor/converters/officeparser/dist/index.d.ts +60 -0
- package/vendor/converters/officeparser/dist/index.js +72 -0
- package/vendor/converters/officeparser/dist/index.mjs +18 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
- package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
- package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
- package/vendor/converters/officeparser/dist/types.js +107 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
- package/vendor/converters/officeparser/package.json +147 -0
- package/vendor/converters/upstream-manifest.json +124 -0
- package/vendor/dependency-fixes/README.md +77 -0
- package/vendor/dependency-fixes/vendor-converters.py +83 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-627emwpj.js +0 -75
- /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
package/src/llm/httpEmbedding.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import type { HttpInferenceOptions } from "./http-inference";
|
|
2
|
+
import type { InferenceOptions } from "./types";
|
|
1
3
|
/**
|
|
2
4
|
* HTTP-based embedding port implementation.
|
|
3
5
|
* Calls OpenAI-compatible embedding endpoints.
|
|
4
6
|
*
|
|
5
7
|
* @module src/llm/httpEmbedding
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
import type { HttpInferenceOptions } from "./http-inference";
|
|
9
9
|
import type { EmbeddingPort, LlmResult } from "./types";
|
|
10
10
|
|
|
11
11
|
import { EgressDeniedError } from "../core/egress-enforcement";
|
|
12
12
|
import { egressDeniedInferenceError, inferenceFailedError } from "./errors";
|
|
13
13
|
import { requestHttpInference } from "./http-inference";
|
|
14
|
+
import { runHttpInference } from "./inference-scope";
|
|
14
15
|
|
|
15
16
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
17
|
// Types
|
|
@@ -58,20 +59,35 @@ export class HttpEmbedding implements EmbeddingPort {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
async init(): Promise<LlmResult<void>> {
|
|
62
|
+
async init(options?: InferenceOptions): Promise<LlmResult<void>> {
|
|
62
63
|
// Test connection with a simple embedding
|
|
63
|
-
const result = await this.embed("test");
|
|
64
|
+
const result = await this.embed("test", options);
|
|
64
65
|
if (!result.ok) {
|
|
65
66
|
return result;
|
|
66
67
|
}
|
|
67
68
|
return { ok: true, value: undefined };
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
async embed(
|
|
71
|
+
async embed(
|
|
72
|
+
text: string,
|
|
73
|
+
options?: InferenceOptions
|
|
74
|
+
): Promise<LlmResult<number[]>> {
|
|
75
|
+
return runHttpInference(
|
|
76
|
+
options,
|
|
77
|
+
(operational) => this.embedRequest(text, operational),
|
|
78
|
+
this.requestOptions.inferenceTimeout
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private async embedRequest(
|
|
83
|
+
text: string,
|
|
84
|
+
options: InferenceOptions
|
|
85
|
+
): Promise<LlmResult<number[]>> {
|
|
71
86
|
try {
|
|
72
87
|
const response = await requestHttpInference(
|
|
73
88
|
this.apiUrl,
|
|
74
89
|
{
|
|
90
|
+
signal: options.signal,
|
|
75
91
|
method: "POST",
|
|
76
92
|
headers: {
|
|
77
93
|
"Content-Type": "application/json",
|
|
@@ -128,11 +144,26 @@ export class HttpEmbedding implements EmbeddingPort {
|
|
|
128
144
|
}
|
|
129
145
|
}
|
|
130
146
|
|
|
131
|
-
async embedBatch(
|
|
147
|
+
async embedBatch(
|
|
148
|
+
texts: string[],
|
|
149
|
+
options?: InferenceOptions
|
|
150
|
+
): Promise<LlmResult<number[][]>> {
|
|
151
|
+
return runHttpInference(
|
|
152
|
+
options,
|
|
153
|
+
(operational) => this.embedBatchRequest(texts, operational),
|
|
154
|
+
this.requestOptions.inferenceTimeout
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private async embedBatchRequest(
|
|
159
|
+
texts: string[],
|
|
160
|
+
options: InferenceOptions
|
|
161
|
+
): Promise<LlmResult<number[][]>> {
|
|
132
162
|
try {
|
|
133
163
|
const response = await requestHttpInference(
|
|
134
164
|
this.apiUrl,
|
|
135
165
|
{
|
|
166
|
+
signal: options.signal,
|
|
136
167
|
method: "POST",
|
|
137
168
|
headers: {
|
|
138
169
|
"Content-Type": "application/json",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import type { HttpInferenceOptions } from "./http-inference";
|
|
2
|
+
import type { InferenceOptions } from "./types";
|
|
1
3
|
/**
|
|
2
4
|
* HTTP-based generation port implementation.
|
|
3
5
|
* Calls OpenAI-compatible chat completion endpoints.
|
|
4
6
|
*
|
|
5
7
|
* @module src/llm/httpGeneration
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
import type { HttpInferenceOptions } from "./http-inference";
|
|
9
9
|
import type { GenerationPort, GenParams, LlmResult } from "./types";
|
|
10
10
|
|
|
11
11
|
import { EgressDeniedError } from "../core/egress-enforcement";
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
structuredOutputUnavailableError,
|
|
16
16
|
} from "./errors";
|
|
17
17
|
import { requestHttpInference } from "./http-inference";
|
|
18
|
+
import { runHttpInference } from "./inference-scope";
|
|
18
19
|
|
|
19
20
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
21
|
// Types
|
|
@@ -71,7 +72,20 @@ export class HttpGeneration implements GenerationPort {
|
|
|
71
72
|
|
|
72
73
|
async generate(
|
|
73
74
|
prompt: string,
|
|
74
|
-
params?: GenParams
|
|
75
|
+
params?: GenParams,
|
|
76
|
+
options?: InferenceOptions
|
|
77
|
+
): Promise<LlmResult<string>> {
|
|
78
|
+
return runHttpInference(
|
|
79
|
+
options,
|
|
80
|
+
(operational) => this.generateRequest(prompt, params, operational),
|
|
81
|
+
this.requestOptions.inferenceTimeout
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async generateRequest(
|
|
86
|
+
prompt: string,
|
|
87
|
+
params: GenParams | undefined,
|
|
88
|
+
options: InferenceOptions
|
|
75
89
|
): Promise<LlmResult<string>> {
|
|
76
90
|
if (params?.jsonSchema) {
|
|
77
91
|
return {
|
|
@@ -83,6 +97,7 @@ export class HttpGeneration implements GenerationPort {
|
|
|
83
97
|
const response = await requestHttpInference(
|
|
84
98
|
this.apiUrl,
|
|
85
99
|
{
|
|
100
|
+
signal: options.signal,
|
|
86
101
|
method: "POST",
|
|
87
102
|
headers: {
|
|
88
103
|
"Content-Type": "application/json",
|
package/src/llm/httpRerank.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import type { HttpInferenceOptions } from "./http-inference";
|
|
2
|
+
import type { InferenceOptions } from "./types";
|
|
1
3
|
/**
|
|
2
4
|
* HTTP-based rerank port implementation.
|
|
3
5
|
* Calls OpenAI-compatible completions endpoints for reranking.
|
|
4
6
|
*
|
|
5
7
|
* @module src/llm/httpRerank
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
import type { HttpInferenceOptions } from "./http-inference";
|
|
9
9
|
import type { LlmResult, RerankPort, RerankScore } from "./types";
|
|
10
10
|
|
|
11
11
|
import { EgressDeniedError } from "../core/egress-enforcement";
|
|
12
12
|
import { egressDeniedInferenceError, inferenceFailedError } from "./errors";
|
|
13
13
|
import { requestHttpInference } from "./http-inference";
|
|
14
|
+
import { runHttpInference } from "./inference-scope";
|
|
14
15
|
|
|
15
16
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
17
|
// Types
|
|
@@ -63,7 +64,20 @@ export class HttpRerank implements RerankPort {
|
|
|
63
64
|
|
|
64
65
|
async rerank(
|
|
65
66
|
query: string,
|
|
66
|
-
documents: string[]
|
|
67
|
+
documents: string[],
|
|
68
|
+
options?: InferenceOptions
|
|
69
|
+
): Promise<LlmResult<RerankScore[]>> {
|
|
70
|
+
return runHttpInference(
|
|
71
|
+
options,
|
|
72
|
+
(operational) => this.rerankRequest(query, documents, operational),
|
|
73
|
+
this.requestOptions.inferenceTimeout
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private async rerankRequest(
|
|
78
|
+
query: string,
|
|
79
|
+
documents: string[],
|
|
80
|
+
options: InferenceOptions
|
|
67
81
|
): Promise<LlmResult<RerankScore[]>> {
|
|
68
82
|
if (documents.length === 0) {
|
|
69
83
|
return { ok: true, value: [] };
|
|
@@ -74,7 +88,7 @@ export class HttpRerank implements RerankPort {
|
|
|
74
88
|
const prompts = documents.map((doc) => this.buildPrompt(query, doc));
|
|
75
89
|
|
|
76
90
|
// Score all documents in a single batch request
|
|
77
|
-
const scoresResult = await this.scoreBatch(prompts);
|
|
91
|
+
const scoresResult = await this.scoreBatch(prompts, options);
|
|
78
92
|
|
|
79
93
|
if (!scoresResult.ok) {
|
|
80
94
|
return { ok: false, error: scoresResult.error };
|
|
@@ -112,11 +126,15 @@ export class HttpRerank implements RerankPort {
|
|
|
112
126
|
return `<Instruct>: ${this.instruction}\n<Query>: ${query}\n<Document>: ${document}\n<Score>:`;
|
|
113
127
|
}
|
|
114
128
|
|
|
115
|
-
private async scoreBatch(
|
|
129
|
+
private async scoreBatch(
|
|
130
|
+
prompts: string[],
|
|
131
|
+
options: InferenceOptions
|
|
132
|
+
): Promise<LlmResult<number[]>> {
|
|
116
133
|
try {
|
|
117
134
|
const response = await requestHttpInference(
|
|
118
135
|
this.apiUrl,
|
|
119
136
|
{
|
|
137
|
+
signal: options.signal,
|
|
120
138
|
method: "POST",
|
|
121
139
|
headers: {
|
|
122
140
|
"Content-Type": "application/json",
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Internal lifetime contract shared by inference owners. Cancellation settles
|
|
2
|
+
* the caller once; only native settlement releases active ownership. Wiring the
|
|
3
|
+
* signal into a backend is the owner's responsibility, not proof of interruption.
|
|
4
|
+
*/
|
|
5
|
+
import type { LlmError } from "./errors";
|
|
6
|
+
import type { InferenceOptions, LlmResult } from "./types";
|
|
7
|
+
|
|
8
|
+
import { llmError } from "./errors";
|
|
9
|
+
|
|
10
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
11
|
+
export type InferencePhase =
|
|
12
|
+
| "queued"
|
|
13
|
+
| "native-active"
|
|
14
|
+
| "response-pending"
|
|
15
|
+
| "settled";
|
|
16
|
+
|
|
17
|
+
/** Stable structural discriminator; do not inspect human-readable messages. */
|
|
18
|
+
export function isInferenceCancellation(error: LlmError): boolean {
|
|
19
|
+
return (
|
|
20
|
+
error.code === "INFERENCE_FAILED" &&
|
|
21
|
+
typeof error.cause === "object" &&
|
|
22
|
+
error.cause !== null &&
|
|
23
|
+
"name" in error.cause &&
|
|
24
|
+
error.cause.name === "AbortError"
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class InferenceSettlement<T> {
|
|
29
|
+
private state: InferencePhase = "queued";
|
|
30
|
+
private delivered = false;
|
|
31
|
+
private executionStarted = false;
|
|
32
|
+
private executionDeadline?: number;
|
|
33
|
+
private result?: LlmResult<T>;
|
|
34
|
+
private deadlineTimer?: ReturnType<typeof setTimeout>;
|
|
35
|
+
private executionTimer?: ReturnType<typeof setTimeout>;
|
|
36
|
+
private readonly controller = new AbortController();
|
|
37
|
+
private readonly delivery = Promise.withResolvers<LlmResult<T>>();
|
|
38
|
+
readonly completion = this.delivery.promise;
|
|
39
|
+
readonly signal = this.controller.signal;
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
private readonly options: InferenceOptions = {},
|
|
43
|
+
private readonly inferenceTimeout = 30_000
|
|
44
|
+
) {
|
|
45
|
+
if (
|
|
46
|
+
!Number.isInteger(inferenceTimeout) ||
|
|
47
|
+
inferenceTimeout < 1 ||
|
|
48
|
+
inferenceTimeout > MAX_TIMER_MS
|
|
49
|
+
)
|
|
50
|
+
throw new RangeError("Invalid inference timeout");
|
|
51
|
+
if (
|
|
52
|
+
options.deadlineAt !== undefined &&
|
|
53
|
+
(!Number.isSafeInteger(options.deadlineAt) || options.deadlineAt < 0)
|
|
54
|
+
)
|
|
55
|
+
throw new RangeError("Invalid inference deadline");
|
|
56
|
+
options.signal?.addEventListener("abort", this.onAbort, { once: true });
|
|
57
|
+
if (options.signal?.aborted) this.cancel("abort");
|
|
58
|
+
this.checkDeadline();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get phase(): InferencePhase {
|
|
62
|
+
return this.state;
|
|
63
|
+
}
|
|
64
|
+
get ownsNative(): boolean {
|
|
65
|
+
return this.state === "native-active";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Claim before starting model/context load, including noncooperative creation. */
|
|
69
|
+
startNative(): boolean {
|
|
70
|
+
this.checkDeadline();
|
|
71
|
+
if (this.state !== "queued" || this.delivered) return false;
|
|
72
|
+
this.state = "native-active";
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Called immediately before evaluation, after loading. Never resets a timer. */
|
|
77
|
+
startExecution(): boolean {
|
|
78
|
+
this.checkDeadline();
|
|
79
|
+
if (!this.ownsNative || this.delivered || this.executionStarted)
|
|
80
|
+
return false;
|
|
81
|
+
this.executionStarted = true;
|
|
82
|
+
this.executionDeadline = performance.now() + this.inferenceTimeout;
|
|
83
|
+
this.executionTimer = setTimeout(
|
|
84
|
+
() => this.cancel("timeout"),
|
|
85
|
+
this.inferenceTimeout
|
|
86
|
+
);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Call only after the native promise settles or owned-child exit is confirmed.
|
|
91
|
+
* A cancellation acknowledgement alone is insufficient to release the lease.
|
|
92
|
+
*/
|
|
93
|
+
nativeSettled(result: LlmResult<T>): void {
|
|
94
|
+
if (!this.ownsNative) return;
|
|
95
|
+
this.checkDeadline();
|
|
96
|
+
clearTimeout(this.executionTimer);
|
|
97
|
+
this.executionDeadline = undefined;
|
|
98
|
+
this.result = result;
|
|
99
|
+
this.state = this.delivered ? "settled" : "response-pending";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Keep caller deadline/abort live through response validation and publication. */
|
|
103
|
+
publish(): boolean {
|
|
104
|
+
this.checkDeadline();
|
|
105
|
+
if (this.state !== "response-pending" || this.delivered || !this.result)
|
|
106
|
+
return false;
|
|
107
|
+
this.deliver(this.result);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Fail caller delivery while retaining native ownership until exit/settlement. */
|
|
112
|
+
fail(error: LlmError): void {
|
|
113
|
+
if (!this.delivered) this.deliver({ ok: false, error });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
cancel(reason: "abort" | "timeout"): void {
|
|
117
|
+
if (this.delivered) return;
|
|
118
|
+
const cause = new DOMException(
|
|
119
|
+
reason === "abort"
|
|
120
|
+
? "Inference cancelled"
|
|
121
|
+
: "Inference deadline exceeded",
|
|
122
|
+
reason === "abort" ? "AbortError" : "TimeoutError"
|
|
123
|
+
);
|
|
124
|
+
// Settle first: synchronous abort listeners cannot publish a late success.
|
|
125
|
+
this.deliver({
|
|
126
|
+
ok: false,
|
|
127
|
+
error: llmError(reason === "abort" ? "INFERENCE_FAILED" : "TIMEOUT", {
|
|
128
|
+
message: cause.message,
|
|
129
|
+
retryable: false,
|
|
130
|
+
cause,
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
this.controller.abort(cause);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private readonly onAbort = (): void => {
|
|
137
|
+
this.cancel("abort");
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
private checkDeadline(): void {
|
|
141
|
+
clearTimeout(this.deadlineTimer);
|
|
142
|
+
if (this.delivered) return;
|
|
143
|
+
if (
|
|
144
|
+
this.executionDeadline !== undefined &&
|
|
145
|
+
performance.now() >= this.executionDeadline
|
|
146
|
+
) {
|
|
147
|
+
this.cancel("timeout");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (this.options.deadlineAt === undefined) return;
|
|
151
|
+
const remaining = this.options.deadlineAt - Date.now();
|
|
152
|
+
if (remaining <= 0) this.cancel("timeout");
|
|
153
|
+
else
|
|
154
|
+
this.deadlineTimer = setTimeout(
|
|
155
|
+
() => this.checkDeadline(),
|
|
156
|
+
Math.min(remaining, MAX_TIMER_MS)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private deliver(result: LlmResult<T>): void {
|
|
161
|
+
this.delivered = true;
|
|
162
|
+
if (!this.ownsNative) this.state = "settled";
|
|
163
|
+
clearTimeout(this.deadlineTimer);
|
|
164
|
+
clearTimeout(this.executionTimer);
|
|
165
|
+
this.options.signal?.removeEventListener("abort", this.onAbort);
|
|
166
|
+
this.delivery.resolve(result);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Bun has no native async-context API; AsyncLocalStorage isolates concurrent callers.
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
|
|
4
|
+
import type { InferenceOptions, LlmResult } from "./types";
|
|
5
|
+
|
|
6
|
+
import { InferenceSettlement } from "./inference-cancellation";
|
|
7
|
+
|
|
8
|
+
interface RequestInferenceScope extends InferenceOptions {
|
|
9
|
+
parent?: RequestInferenceScope;
|
|
10
|
+
failure?: DOMException;
|
|
11
|
+
controller?: AbortController;
|
|
12
|
+
}
|
|
13
|
+
const scope = new AsyncLocalStorage<RequestInferenceScope>();
|
|
14
|
+
// Internal scheduling class, separate from public inference options/model inputs.
|
|
15
|
+
const background = new AsyncLocalStorage<boolean>();
|
|
16
|
+
|
|
17
|
+
export function isBackgroundInference(): boolean {
|
|
18
|
+
return background.getStore() === true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function withBackgroundInference<T>(
|
|
22
|
+
operation: () => Promise<T>
|
|
23
|
+
): Promise<T> {
|
|
24
|
+
return background.run(true, operation);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function recordInferenceTimeout(): void {
|
|
28
|
+
let current = scope.getStore();
|
|
29
|
+
while (current) {
|
|
30
|
+
current.failure = new DOMException(
|
|
31
|
+
"Inference deadline exceeded",
|
|
32
|
+
"TimeoutError"
|
|
33
|
+
);
|
|
34
|
+
current.controller?.abort(current.failure);
|
|
35
|
+
current = current.parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Operational metadata only: never serialized with model inputs. */
|
|
40
|
+
export function inferenceOptions(
|
|
41
|
+
options: InferenceOptions = {}
|
|
42
|
+
): InferenceOptions {
|
|
43
|
+
if (
|
|
44
|
+
options.deadlineAt !== undefined &&
|
|
45
|
+
(!Number.isSafeInteger(options.deadlineAt) || options.deadlineAt < 0)
|
|
46
|
+
)
|
|
47
|
+
throw new RangeError("Invalid inference deadline");
|
|
48
|
+
const parent = scope.getStore();
|
|
49
|
+
const signals = [
|
|
50
|
+
parent?.failure ? AbortSignal.abort(parent.failure) : parent?.signal,
|
|
51
|
+
options.signal,
|
|
52
|
+
].filter((signal): signal is AbortSignal => signal !== undefined);
|
|
53
|
+
const deadlines = [parent?.deadlineAt, options.deadlineAt].filter(
|
|
54
|
+
(deadline): deadline is number => deadline !== undefined
|
|
55
|
+
);
|
|
56
|
+
return {
|
|
57
|
+
signal: signals.length > 1 ? AbortSignal.any(signals) : signals[0],
|
|
58
|
+
deadlineAt: deadlines.length ? Math.min(...deadlines) : undefined,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function assertInferenceActive(options: InferenceOptions = {}): void {
|
|
63
|
+
if (scope.getStore()?.failure) throw scope.getStore()!.failure;
|
|
64
|
+
const current = inferenceOptions(options);
|
|
65
|
+
if (current.signal?.aborted)
|
|
66
|
+
throw new DOMException("Inference cancelled", "AbortError");
|
|
67
|
+
if (current.deadlineAt !== undefined && Date.now() >= current.deadlineAt)
|
|
68
|
+
throw new DOMException("Inference deadline exceeded", "TimeoutError");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function withInferenceScope<T>(
|
|
72
|
+
options: InferenceOptions,
|
|
73
|
+
operation: () => Promise<T>
|
|
74
|
+
): Promise<T> {
|
|
75
|
+
const inherited = inferenceOptions(options);
|
|
76
|
+
const controller = new AbortController();
|
|
77
|
+
return scope.run(
|
|
78
|
+
{
|
|
79
|
+
...inherited,
|
|
80
|
+
signal: inherited.signal
|
|
81
|
+
? AbortSignal.any([inherited.signal, controller.signal])
|
|
82
|
+
: controller.signal,
|
|
83
|
+
controller,
|
|
84
|
+
parent: scope.getStore(),
|
|
85
|
+
},
|
|
86
|
+
async () => {
|
|
87
|
+
assertInferenceActive();
|
|
88
|
+
const result = await operation();
|
|
89
|
+
assertInferenceActive();
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** HTTP operations own their fetch/body until settlement; abort reaches fetch. */
|
|
96
|
+
export function runHttpInference<T>(
|
|
97
|
+
options: InferenceOptions | undefined,
|
|
98
|
+
operation: (options: InferenceOptions) => Promise<LlmResult<T>>,
|
|
99
|
+
inferenceTimeout = 30_000
|
|
100
|
+
): Promise<LlmResult<T>> {
|
|
101
|
+
const settlement = new InferenceSettlement<T>(
|
|
102
|
+
inferenceOptions(options),
|
|
103
|
+
inferenceTimeout
|
|
104
|
+
);
|
|
105
|
+
if (settlement.startNative()) {
|
|
106
|
+
settlement.startExecution();
|
|
107
|
+
void operation({ signal: settlement.signal }).then(
|
|
108
|
+
(result) => {
|
|
109
|
+
settlement.nativeSettled(result);
|
|
110
|
+
settlement.publish();
|
|
111
|
+
},
|
|
112
|
+
(cause: unknown) => {
|
|
113
|
+
settlement.nativeSettled({
|
|
114
|
+
ok: false,
|
|
115
|
+
error: {
|
|
116
|
+
code: "INFERENCE_FAILED",
|
|
117
|
+
message: "HTTP inference failed",
|
|
118
|
+
retryable: false,
|
|
119
|
+
cause,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
settlement.publish();
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return settlement.completion.then((result) => {
|
|
127
|
+
if (!result.ok && result.error.code === "TIMEOUT") recordInferenceTimeout();
|
|
128
|
+
return result;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Never convert cancellation or timeout into retrieval fallback. */
|
|
133
|
+
export function assertInferenceResult<T>(result: LlmResult<T>): void {
|
|
134
|
+
assertInferenceActive();
|
|
135
|
+
if (
|
|
136
|
+
!result.ok &&
|
|
137
|
+
(result.error.code === "TIMEOUT" ||
|
|
138
|
+
(typeof result.error.cause === "object" &&
|
|
139
|
+
result.error.cause !== null &&
|
|
140
|
+
"name" in result.error.cause &&
|
|
141
|
+
result.error.cause.name === "AbortError"))
|
|
142
|
+
)
|
|
143
|
+
throw new DOMException(
|
|
144
|
+
result.error.message,
|
|
145
|
+
result.error.code === "TIMEOUT" ? "TimeoutError" : "AbortError"
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Owned cleanup must not inherit an expired caller, or block its delivery. */
|
|
150
|
+
export function finishInferenceCleanup(
|
|
151
|
+
operation: () => Promise<void>
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
const cancelled =
|
|
154
|
+
scope.getStore()?.failure ||
|
|
155
|
+
scope.getStore()?.signal?.aborted ||
|
|
156
|
+
(scope.getStore()?.deadlineAt !== undefined &&
|
|
157
|
+
Date.now() >= scope.getStore()!.deadlineAt!);
|
|
158
|
+
if (!cancelled) return operation();
|
|
159
|
+
void scope.run({}, operation).catch(() => {});
|
|
160
|
+
return Promise.resolve();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Accepted jobs own their lifetime independently of their initiating request. */
|
|
164
|
+
export function withOwnedInferenceScope<T>(
|
|
165
|
+
options: InferenceOptions,
|
|
166
|
+
operation: () => Promise<T>
|
|
167
|
+
): Promise<T> {
|
|
168
|
+
return scope.run({}, () => withInferenceScope(options, operation));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** A cancelled queued reader releases only its eventual grant, never another caller's. */
|
|
172
|
+
export async function acquireInferencePermit(
|
|
173
|
+
acquire: () => Promise<() => void>
|
|
174
|
+
): Promise<() => void> {
|
|
175
|
+
const lifetime = new InferenceSettlement<() => void>(inferenceOptions());
|
|
176
|
+
if (lifetime.startNative())
|
|
177
|
+
void acquire().then(
|
|
178
|
+
(release) => {
|
|
179
|
+
lifetime.nativeSettled({ ok: true, value: release });
|
|
180
|
+
if (!lifetime.publish()) release();
|
|
181
|
+
},
|
|
182
|
+
(cause: unknown) => {
|
|
183
|
+
lifetime.nativeSettled({
|
|
184
|
+
ok: false,
|
|
185
|
+
error: {
|
|
186
|
+
code: "INFERENCE_FAILED",
|
|
187
|
+
message: "Request admission failed",
|
|
188
|
+
retryable: false,
|
|
189
|
+
cause,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
lifetime.publish();
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
const result = await lifetime.completion;
|
|
196
|
+
if (!result.ok)
|
|
197
|
+
throw new DOMException(
|
|
198
|
+
result.error.message,
|
|
199
|
+
result.error.code === "TIMEOUT" ? "TimeoutError" : "AbortError"
|
|
200
|
+
);
|
|
201
|
+
return result.value;
|
|
202
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** Defer model resolution/download until an actual inference operation. */
|
|
2
|
+
import type {
|
|
3
|
+
EmbeddingPort,
|
|
4
|
+
GenerationPort,
|
|
5
|
+
LlmResult,
|
|
6
|
+
RerankPort,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
import { inferenceFailedError } from "./errors";
|
|
10
|
+
import { isHttpGenUri } from "./httpGeneration";
|
|
11
|
+
|
|
12
|
+
function lazyOwner<T extends { dispose(): Promise<void> }>(
|
|
13
|
+
modelUri: string,
|
|
14
|
+
create: () => Promise<LlmResult<T>>
|
|
15
|
+
) {
|
|
16
|
+
let current: T | undefined;
|
|
17
|
+
let pending: Promise<LlmResult<T>> | undefined;
|
|
18
|
+
let disposed = false;
|
|
19
|
+
const closed = (): LlmResult<T> => ({
|
|
20
|
+
ok: false,
|
|
21
|
+
error: inferenceFailedError(modelUri, new Error("Port is disposed")),
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
peek: () => current,
|
|
25
|
+
get(): Promise<LlmResult<T>> {
|
|
26
|
+
if (disposed) return Promise.resolve(closed());
|
|
27
|
+
if (current) return Promise.resolve({ ok: true, value: current });
|
|
28
|
+
pending ??= create()
|
|
29
|
+
.then(async (result) => {
|
|
30
|
+
if (disposed) {
|
|
31
|
+
if (result.ok) await result.value.dispose();
|
|
32
|
+
return closed();
|
|
33
|
+
}
|
|
34
|
+
if (result.ok) current = result.value;
|
|
35
|
+
return result;
|
|
36
|
+
})
|
|
37
|
+
.finally(() => {
|
|
38
|
+
pending = undefined;
|
|
39
|
+
});
|
|
40
|
+
return pending;
|
|
41
|
+
},
|
|
42
|
+
async dispose(): Promise<void> {
|
|
43
|
+
if (disposed) return;
|
|
44
|
+
disposed = true;
|
|
45
|
+
await pending;
|
|
46
|
+
const owned = current;
|
|
47
|
+
current = undefined;
|
|
48
|
+
await owned?.dispose();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function lazyEmbeddingPort(
|
|
54
|
+
modelUri: string,
|
|
55
|
+
create: () => Promise<LlmResult<EmbeddingPort>>
|
|
56
|
+
): EmbeddingPort {
|
|
57
|
+
const owner = lazyOwner(modelUri, create);
|
|
58
|
+
return {
|
|
59
|
+
modelUri,
|
|
60
|
+
async init() {
|
|
61
|
+
const port = await owner.get();
|
|
62
|
+
return port.ok ? port.value.init() : port;
|
|
63
|
+
},
|
|
64
|
+
async embed(text) {
|
|
65
|
+
const port = await owner.get();
|
|
66
|
+
return port.ok ? port.value.embed(text) : port;
|
|
67
|
+
},
|
|
68
|
+
async embedBatch(texts) {
|
|
69
|
+
const port = await owner.get();
|
|
70
|
+
return port.ok ? port.value.embedBatch(texts) : port;
|
|
71
|
+
},
|
|
72
|
+
dimensions() {
|
|
73
|
+
const port = owner.peek();
|
|
74
|
+
if (!port)
|
|
75
|
+
throw new Error(
|
|
76
|
+
"Call init() or embed() first to initialize dimensions"
|
|
77
|
+
);
|
|
78
|
+
return port.dimensions();
|
|
79
|
+
},
|
|
80
|
+
getIdentity: () => owner.peek()?.getIdentity?.(),
|
|
81
|
+
dispose: () => owner.dispose(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function lazyGenerationPort(
|
|
86
|
+
modelUri: string,
|
|
87
|
+
create: () => Promise<LlmResult<GenerationPort>>
|
|
88
|
+
): GenerationPort {
|
|
89
|
+
const owner = lazyOwner(modelUri, create);
|
|
90
|
+
return {
|
|
91
|
+
modelUri,
|
|
92
|
+
// These are the fixed native/HTTP adapter contracts; no probing required.
|
|
93
|
+
structuredOutput: isHttpGenUri(modelUri) ? "none" : "json_schema",
|
|
94
|
+
async generate(prompt, params) {
|
|
95
|
+
const port = await owner.get();
|
|
96
|
+
return port.ok ? port.value.generate(prompt, params) : port;
|
|
97
|
+
},
|
|
98
|
+
dispose: () => owner.dispose(),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function lazyRerankPort(
|
|
103
|
+
modelUri: string,
|
|
104
|
+
create: () => Promise<LlmResult<RerankPort>>
|
|
105
|
+
): RerankPort {
|
|
106
|
+
const owner = lazyOwner(modelUri, create);
|
|
107
|
+
return {
|
|
108
|
+
modelUri,
|
|
109
|
+
async rerank(query, documents) {
|
|
110
|
+
const port = await owner.get();
|
|
111
|
+
return port.ok ? port.value.rerank(query, documents) : port;
|
|
112
|
+
},
|
|
113
|
+
dispose: () => owner.dispose(),
|
|
114
|
+
};
|
|
115
|
+
}
|