@qvac/sdk 0.10.1 → 0.11.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/NOTICE +92 -54
- package/dist/client/api/cancel.d.ts +24 -32
- package/dist/client/api/cancel.js +58 -31
- package/dist/client/api/client-request-id.d.ts +17 -0
- package/dist/client/api/client-request-id.js +27 -0
- package/dist/client/api/completion-stream.d.ts +1 -1
- package/dist/client/api/completion-stream.js +34 -3
- package/dist/client/api/diffusion.d.ts +46 -0
- package/dist/client/api/diffusion.js +50 -1
- package/dist/client/api/download-asset.d.ts +12 -2
- package/dist/client/api/download-asset.js +21 -3
- package/dist/client/api/embed.d.ts +8 -4
- package/dist/client/api/embed.js +14 -1
- package/dist/client/api/get-model-info.d.ts +1 -1
- package/dist/client/api/index.d.ts +1 -0
- package/dist/client/api/index.js +1 -0
- package/dist/client/api/load-model.d.ts +12 -4
- package/dist/client/api/load-model.js +25 -1
- package/dist/client/api/rag.d.ts +9 -3
- package/dist/client/api/rag.js +23 -3
- package/dist/client/api/transcribe.d.ts +20 -8
- package/dist/client/api/transcribe.js +58 -4
- package/dist/client/api/unload-model.d.ts +5 -2
- package/dist/client/api/unload-model.js +9 -4
- package/dist/client/api/upscale.d.ts +45 -0
- package/dist/client/api/upscale.js +99 -0
- package/dist/client/rpc/expo-rpc-client.js +2 -1
- package/dist/client/rpc/node-rpc-client.js +18 -7
- package/dist/client/rpc/rpc-client.d.ts +2 -2
- package/dist/client/rpc/rpc-client.js +10 -4
- package/dist/client/rpc/rpc-error.d.ts +9 -0
- package/dist/client/rpc/rpc-error.js +92 -0
- package/dist/examples/cancel-by-request-id.d.ts +38 -0
- package/dist/examples/cancel-by-request-id.js +103 -0
- package/dist/examples/diffusion-esrgan-upscale.d.ts +2 -0
- package/dist/examples/diffusion-esrgan-upscale.js +78 -0
- package/dist/examples/download-with-cancel.js +10 -10
- package/dist/examples/embed-multi-gpu.d.ts +2 -0
- package/dist/examples/embed-multi-gpu.js +46 -0
- package/dist/examples/llamacpp-multi-gpu.d.ts +2 -0
- package/dist/examples/llamacpp-multi-gpu.js +57 -0
- package/dist/examples/rag/rag-hyperdb/cancellation.js +20 -17
- package/dist/examples/tools/llamacpp-tools-gemma4.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-gemma4.js +76 -0
- package/dist/examples/tools/llamacpp-tools-qwen35.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-qwen35.js +70 -0
- package/dist/examples/transcription/whispercpp-microphone-conversation.d.ts +2 -0
- package/dist/examples/transcription/whispercpp-microphone-conversation.js +102 -0
- package/dist/examples/tts/supertonic.js +1 -1
- package/dist/expo/plugins/withMobileBundle.d.ts +20 -4
- package/dist/expo/plugins/withMobileBundle.js +44 -6
- package/dist/index.d.ts +5 -2
- package/dist/index.js +21 -1
- package/dist/models/registry/models.d.ts +186 -318
- package/dist/models/registry/models.js +1522 -1667
- package/dist/pear/pre.d.ts +3 -0
- package/dist/pear/pre.js +3 -0
- package/dist/schemas/cancel.d.ts +167 -28
- package/dist/schemas/cancel.js +119 -19
- package/dist/schemas/common.d.ts +427 -208
- package/dist/schemas/common.js +3 -1
- package/dist/schemas/completion-event.d.ts +14 -0
- package/dist/schemas/completion-event.js +11 -1
- package/dist/schemas/completion-stream.d.ts +15 -1
- package/dist/schemas/completion-stream.js +25 -7
- package/dist/schemas/download-asset.d.ts +15 -9
- package/dist/schemas/download-asset.js +17 -6
- package/dist/schemas/embed.d.ts +1 -0
- package/dist/schemas/embed.js +5 -0
- package/dist/schemas/error.d.ts +31 -0
- package/dist/schemas/error.js +29 -1
- package/dist/schemas/finetune.d.ts +2 -0
- package/dist/schemas/finetune.js +5 -0
- package/dist/schemas/get-model-info.d.ts +6 -6
- package/dist/schemas/llamacpp-config.d.ts +54 -8
- package/dist/schemas/llamacpp-config.js +12 -0
- package/dist/schemas/load-model.d.ts +1911 -1260
- package/dist/schemas/load-model.js +15 -0
- package/dist/schemas/model-src-utils.d.ts +14 -14
- package/dist/schemas/model-types.d.ts +10 -10
- package/dist/schemas/ocr.d.ts +3 -3
- package/dist/schemas/plugin.d.ts +40 -1
- package/dist/schemas/plugin.js +10 -1
- package/dist/schemas/rag.d.ts +9 -0
- package/dist/schemas/rag.js +17 -9
- package/dist/schemas/registry.d.ts +30 -30
- package/dist/schemas/reload-config.d.ts +14 -14
- package/dist/schemas/sdcpp-config.d.ts +131 -17
- package/dist/schemas/sdcpp-config.js +163 -1
- package/dist/schemas/sdk-config.d.ts +649 -271
- package/dist/schemas/sdk-errors-client.d.ts +1 -0
- package/dist/schemas/sdk-errors-client.js +5 -0
- package/dist/schemas/sdk-errors-server.d.ts +5 -0
- package/dist/schemas/sdk-errors-server.js +25 -0
- package/dist/schemas/text-to-speech.d.ts +78 -78
- package/dist/schemas/transcription-config.d.ts +24 -24
- package/dist/schemas/transcription.d.ts +56 -2
- package/dist/schemas/transcription.js +27 -0
- package/dist/schemas/translate.d.ts +2 -0
- package/dist/schemas/translate.js +13 -2
- package/dist/schemas/translation-config.d.ts +40 -40
- package/dist/schemas/unload-model.d.ts +2 -1
- package/dist/schemas/unload-model.js +4 -1
- package/dist/scripts/run-unit-tests.js +15 -2
- package/dist/server/bare/delegate-rpc-client.js +10 -8
- package/dist/server/bare/ops/cancel.d.ts +27 -1
- package/dist/server/bare/ops/cancel.js +36 -10
- package/dist/server/bare/ops/embed.d.ts +3 -3
- package/dist/server/bare/ops/embed.js +144 -28
- package/dist/server/bare/ops/kv-cache-utils.d.ts +0 -7
- package/dist/server/bare/ops/kv-cache-utils.js +8 -47
- package/dist/server/bare/ops/transcribe.d.ts +10 -5
- package/dist/server/bare/ops/transcribe.js +196 -41
- package/dist/server/bare/ops/translate.d.ts +1 -1
- package/dist/server/bare/ops/translate.js +197 -88
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +12 -3
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +170 -172
- package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +125 -21
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.d.ts +154 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.js +448 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +21 -73
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +18 -101
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +30 -3
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +157 -85
- package/dist/server/bare/plugins/llamacpp-completion/transform.d.ts +10 -0
- package/dist/server/bare/plugins/llamacpp-completion/transform.js +34 -0
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +7 -0
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +10 -1
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +17 -15
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +5 -1
- package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +3 -3
- package/dist/server/bare/plugins/onnx-ocr/plugin.js +3 -0
- package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +39 -39
- package/dist/server/bare/plugins/onnx-tts/plugin.js +6 -0
- package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +29 -21
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +4 -1
- package/dist/server/bare/plugins/sdcpp-generation/ops/diffusion.js +8 -0
- package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.d.ts +3 -0
- package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.js +40 -0
- package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +91 -16
- package/dist/server/bare/plugins/sdcpp-generation/plugin.js +97 -7
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +22 -3
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +50 -14
- package/dist/server/bare/rag-hyperdb/index.d.ts +1 -1
- package/dist/server/bare/rag-hyperdb/index.js +1 -1
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.d.ts +26 -4
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.js +65 -28
- package/dist/server/bare/runtime/disposable-scope.d.ts +36 -0
- package/dist/server/bare/runtime/disposable-scope.js +69 -0
- package/dist/server/bare/runtime/index.d.ts +8 -0
- package/dist/server/bare/runtime/index.js +3 -0
- package/dist/server/bare/runtime/request-context.d.ts +49 -0
- package/dist/server/bare/runtime/request-context.js +1 -0
- package/dist/server/bare/runtime/request-id.d.ts +12 -0
- package/dist/server/bare/runtime/request-id.js +14 -0
- package/dist/server/bare/runtime/request-registry-singleton.d.ts +4 -0
- package/dist/server/bare/runtime/request-registry-singleton.js +27 -0
- package/dist/server/bare/runtime/request-registry.d.ts +136 -0
- package/dist/server/bare/runtime/request-registry.js +297 -0
- package/dist/server/bare/runtime/with-request-context.d.ts +22 -0
- package/dist/server/bare/runtime/with-request-context.js +53 -0
- package/dist/server/bare/types/addon-responses.d.ts +11 -1
- package/dist/server/rpc/handler-registry.js +26 -7
- package/dist/server/rpc/handlers/cancel-delegated.js +28 -31
- package/dist/server/rpc/handlers/cancelHandler.d.ts +30 -1
- package/dist/server/rpc/handlers/cancelHandler.js +54 -22
- package/dist/server/rpc/handlers/delete-cache.d.ts +9 -0
- package/dist/server/rpc/handlers/delete-cache.js +13 -15
- package/dist/server/rpc/handlers/download-asset.js +133 -40
- package/dist/server/rpc/handlers/index.d.ts +2 -0
- package/dist/server/rpc/handlers/index.js +2 -0
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +60 -2
- package/dist/server/rpc/handlers/load-model/download-manager.js +141 -8
- package/dist/server/rpc/handlers/load-model/handler.js +213 -98
- package/dist/server/rpc/handlers/load-model/http.js +3 -3
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +1 -1
- package/dist/server/rpc/handlers/load-model/registry.js +1 -1
- package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +20 -1
- package/dist/server/rpc/handlers/load-model/resolve-session.js +6 -5
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -2
- package/dist/server/rpc/handlers/load-model/resolve.js +9 -6
- package/dist/server/rpc/handlers/load-model/types.d.ts +24 -0
- package/dist/server/rpc/handlers/rag.js +133 -15
- package/dist/server/rpc/handlers/upscale-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/upscale-stream.js +4 -0
- package/dist/server/utils/completion-normalizer.js +8 -0
- package/dist/server/utils/tools/dialect.js +4 -0
- package/dist/server/utils/tools/parser.js +16 -1
- package/dist/server/utils/tools/parsers/gemma4native.d.ts +4 -0
- package/dist/server/utils/tools/parsers/gemma4native.js +60 -0
- package/dist/server/utils/tools/parsers/qwen35.d.ts +4 -0
- package/dist/server/utils/tools/parsers/qwen35.js +120 -0
- package/dist/utils/aggregate-events.d.ts +9 -0
- package/dist/utils/aggregate-events.js +18 -3
- package/dist/utils/decorate-promise.d.ts +34 -0
- package/dist/utils/decorate-promise.js +35 -0
- package/dist/utils/errors-client.d.ts +3 -0
- package/dist/utils/errors-client.js +5 -0
- package/dist/utils/errors-server.d.ts +85 -0
- package/dist/utils/errors-server.js +97 -0
- package/package.json +20 -15
|
@@ -1,73 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pure
|
|
3
|
-
* `completion-stream.ts
|
|
2
|
+
* Pure decision helper for kv-cache history slicing used by
|
|
3
|
+
* `completion-stream.ts` (via the slice computed from
|
|
4
|
+
* `TurnHandle.savedCount`).
|
|
4
5
|
*
|
|
5
6
|
* This module intentionally has **no** `bare-*` imports so it can be
|
|
6
|
-
* exercised directly from unit tests running under `bun` without
|
|
7
|
-
* in the Bare runtime (which is not available in that
|
|
8
|
-
*
|
|
9
|
-
* `completion-stream.ts` and consume the state exported here.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Number of chat messages the kv-cache file on disk is known to cover, keyed
|
|
13
|
-
* by cache path. Written after a successful completion records a save, read
|
|
14
|
-
* by `prepareMessagesForCache` to slice the history on the next turn so a
|
|
15
|
-
* consumer can stage multiple messages between completions (e.g. an
|
|
16
|
-
* `[assistant, user]` recovery sequence) without resending the whole history.
|
|
17
|
-
*
|
|
18
|
-
* INVARIANT: an entry is only present if the corresponding kv-cache file is
|
|
19
|
-
* considered trustworthy. On any turn where the SDK cannot prove the saved
|
|
20
|
-
* count reflects the on-disk state (cancellation mid-decode, zero-token
|
|
21
|
-
* reply, cache file missing after a save attempt), the entry MUST be
|
|
22
|
-
* deleted; a stale entry causes the next turn to slice its history down to
|
|
23
|
-
* an empty payload and the model returns zero tokens.
|
|
24
|
-
*
|
|
25
|
-
* Mode notes:
|
|
26
|
-
* - Static-mode turns are the only readers of this map. `clearStaleCount`
|
|
27
|
-
* in `decideCachedHistorySlice` exists so a stale-but-non-zero entry
|
|
28
|
-
* can be detected and dropped on the next read.
|
|
29
|
-
* - Dynamic-mode turns do NOT consume this map — the addon trims tools
|
|
30
|
-
* and the chain output from the kv-cache after each round, so the
|
|
31
|
-
* SDK falls back to role-based dispatch in `prepareMessagesForCache`.
|
|
32
|
-
* Writes still happen on dynamic-mode turns, but the recorded count
|
|
33
|
-
* reflects the messages the SDK shipped, not the (possibly trimmed)
|
|
34
|
-
* on-disk cache shape. The map is internally consistent within a
|
|
35
|
-
* single mode; a `kvCache` key should not be reused across modes.
|
|
36
|
-
*/
|
|
37
|
-
export declare const cachedMessageCounts: Map<string, number>;
|
|
38
|
-
/**
|
|
39
|
-
* Clear bookkeeping entries. With no argument, clears the whole map. With a
|
|
40
|
-
* `prefix`, removes any entry whose path is equal to it OR sits beneath it
|
|
41
|
-
* as a directory (i.e. `key.startsWith(prefix + sep)`).
|
|
7
|
+
* exercised directly from unit tests running under `bun` without
|
|
8
|
+
* pulling in the Bare runtime (which is not available in that
|
|
9
|
+
* environment).
|
|
42
10
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* injects the real separator for in-process use.
|
|
49
|
-
*/
|
|
50
|
-
export declare function clearCachedMessageCounts(prefix?: string, sep?: string): void;
|
|
51
|
-
/**
|
|
52
|
-
* Called from `server/bare/ops/cancel.ts` right before `addon.cancel()` so
|
|
53
|
-
* that the in-flight `completion()` for this model can detect that its
|
|
54
|
-
* current turn is being cancelled and skip poisoning `cachedMessageCounts`
|
|
55
|
-
* with a `history.length + 1` entry that does not correspond to a real
|
|
56
|
-
* assistant reply.
|
|
57
|
-
*/
|
|
58
|
-
export declare function noteCancelRequested(modelId: string): void;
|
|
59
|
-
export declare function snapshotCancelCount(modelId: string): number;
|
|
60
|
-
/** Test-only. */
|
|
61
|
-
export declare function _resetCancelCountersForTest(): void;
|
|
62
|
-
/**
|
|
63
|
-
* A completion's `savedCount` should only be recorded when the turn ran to
|
|
64
|
-
* completion AND produced at least one token. Any other outcome —
|
|
65
|
-
* cancelled mid-decode, legitimate zero-token reply, or an early EOS — must
|
|
66
|
-
* clear the entry instead, because there is no guarantee that the kv-cache
|
|
67
|
-
* file on disk matches the `history.length + 1` boundary the SDK would
|
|
68
|
-
* otherwise record.
|
|
11
|
+
* Cancel detection flows through the per-request `AbortSignal` from
|
|
12
|
+
* `RequestRegistry`; the `cachedMessageCounts` map lives in
|
|
13
|
+
* `kv-cache-session.ts`, which owns all three KV-cache bookkeeping
|
|
14
|
+
* layers (saved counts, init flags, on-disk files). Only the pure
|
|
15
|
+
* slice-decision helper remains here.
|
|
69
16
|
*/
|
|
70
|
-
export declare function shouldRecordSavedCount(wasCancelled: boolean, producedTokens: boolean): boolean;
|
|
71
17
|
export interface HistoryMessage {
|
|
72
18
|
role: string;
|
|
73
19
|
content: string;
|
|
@@ -80,8 +26,9 @@ export interface HistorySliceDecision {
|
|
|
80
26
|
messages: HistoryMessage[];
|
|
81
27
|
/**
|
|
82
28
|
* True when the decision path proves the current `savedCount` is stale
|
|
83
|
-
* and the caller should
|
|
84
|
-
*
|
|
29
|
+
* and the caller should drop the cached entry (via
|
|
30
|
+
* `KvCacheSession.dropStaleSavedCount(turn)`) to avoid propagating the
|
|
31
|
+
* bad count to the next turn.
|
|
85
32
|
*/
|
|
86
33
|
clearStaleCount: boolean;
|
|
87
34
|
}
|
|
@@ -89,13 +36,14 @@ export interface HistorySliceDecision {
|
|
|
89
36
|
* Pure slice decision for `prepareMessagesForCache`.
|
|
90
37
|
*
|
|
91
38
|
* Mirrors the shape of the logic in `completion-stream.ts` but without
|
|
92
|
-
* calling `transformMessages` (which depends on `bare-fs` for
|
|
93
|
-
* probing). Kept here so the decision can be unit-tested in
|
|
39
|
+
* calling `transformMessages` (which depends on `bare-fs` for
|
|
40
|
+
* attachment probing). Kept here so the decision can be unit-tested in
|
|
41
|
+
* isolation.
|
|
94
42
|
*
|
|
95
|
-
* The key regression guard: when a non-zero `savedCount` would slice
|
|
96
|
-
* history down to an empty array, it is treated as stale — the
|
|
97
|
-
* falls back to sending the system-stripped full history rather
|
|
98
|
-
* handing the model an empty payload.
|
|
43
|
+
* The key regression guard: when a non-zero `savedCount` would slice
|
|
44
|
+
* the history down to an empty array, it is treated as stale — the
|
|
45
|
+
* caller falls back to sending the system-stripped full history rather
|
|
46
|
+
* than handing the model an empty payload.
|
|
99
47
|
*/
|
|
100
48
|
export declare function decideCachedHistorySlice(savedCount: number, cacheExists: boolean, history: HistoryMessage[]): HistorySliceDecision;
|
|
101
49
|
//# sourceMappingURL=kv-cache-state.d.ts.map
|
|
@@ -1,114 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pure
|
|
3
|
-
* `completion-stream.ts
|
|
2
|
+
* Pure decision helper for kv-cache history slicing used by
|
|
3
|
+
* `completion-stream.ts` (via the slice computed from
|
|
4
|
+
* `TurnHandle.savedCount`).
|
|
4
5
|
*
|
|
5
6
|
* This module intentionally has **no** `bare-*` imports so it can be
|
|
6
|
-
* exercised directly from unit tests running under `bun` without
|
|
7
|
-
* in the Bare runtime (which is not available in that
|
|
8
|
-
*
|
|
9
|
-
* `completion-stream.ts` and consume the state exported here.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Number of chat messages the kv-cache file on disk is known to cover, keyed
|
|
13
|
-
* by cache path. Written after a successful completion records a save, read
|
|
14
|
-
* by `prepareMessagesForCache` to slice the history on the next turn so a
|
|
15
|
-
* consumer can stage multiple messages between completions (e.g. an
|
|
16
|
-
* `[assistant, user]` recovery sequence) without resending the whole history.
|
|
17
|
-
*
|
|
18
|
-
* INVARIANT: an entry is only present if the corresponding kv-cache file is
|
|
19
|
-
* considered trustworthy. On any turn where the SDK cannot prove the saved
|
|
20
|
-
* count reflects the on-disk state (cancellation mid-decode, zero-token
|
|
21
|
-
* reply, cache file missing after a save attempt), the entry MUST be
|
|
22
|
-
* deleted; a stale entry causes the next turn to slice its history down to
|
|
23
|
-
* an empty payload and the model returns zero tokens.
|
|
24
|
-
*
|
|
25
|
-
* Mode notes:
|
|
26
|
-
* - Static-mode turns are the only readers of this map. `clearStaleCount`
|
|
27
|
-
* in `decideCachedHistorySlice` exists so a stale-but-non-zero entry
|
|
28
|
-
* can be detected and dropped on the next read.
|
|
29
|
-
* - Dynamic-mode turns do NOT consume this map — the addon trims tools
|
|
30
|
-
* and the chain output from the kv-cache after each round, so the
|
|
31
|
-
* SDK falls back to role-based dispatch in `prepareMessagesForCache`.
|
|
32
|
-
* Writes still happen on dynamic-mode turns, but the recorded count
|
|
33
|
-
* reflects the messages the SDK shipped, not the (possibly trimmed)
|
|
34
|
-
* on-disk cache shape. The map is internally consistent within a
|
|
35
|
-
* single mode; a `kvCache` key should not be reused across modes.
|
|
36
|
-
*/
|
|
37
|
-
export const cachedMessageCounts = new Map();
|
|
38
|
-
/**
|
|
39
|
-
* Monotonic counter of cancel requests per model. `completion()` snapshots
|
|
40
|
-
* the value before running the model and compares afterward to decide
|
|
41
|
-
* whether the turn was cancelled mid-decode. A counter (not a boolean) is
|
|
42
|
-
* used deliberately: a cancel that lands near a turn boundary cannot bleed
|
|
43
|
-
* into the next turn because we always compare snapshots, not values.
|
|
44
|
-
*/
|
|
45
|
-
const modelCancelCounters = new Map();
|
|
46
|
-
/**
|
|
47
|
-
* Clear bookkeeping entries. With no argument, clears the whole map. With a
|
|
48
|
-
* `prefix`, removes any entry whose path is equal to it OR sits beneath it
|
|
49
|
-
* as a directory (i.e. `key.startsWith(prefix + sep)`).
|
|
7
|
+
* exercised directly from unit tests running under `bun` without
|
|
8
|
+
* pulling in the Bare runtime (which is not available in that
|
|
9
|
+
* environment).
|
|
50
10
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* injects the real separator for in-process use.
|
|
11
|
+
* Cancel detection flows through the per-request `AbortSignal` from
|
|
12
|
+
* `RequestRegistry`; the `cachedMessageCounts` map lives in
|
|
13
|
+
* `kv-cache-session.ts`, which owns all three KV-cache bookkeeping
|
|
14
|
+
* layers (saved counts, init flags, on-disk files). Only the pure
|
|
15
|
+
* slice-decision helper remains here.
|
|
57
16
|
*/
|
|
58
|
-
export function clearCachedMessageCounts(prefix, sep = "/") {
|
|
59
|
-
if (!prefix) {
|
|
60
|
-
cachedMessageCounts.clear();
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
for (const key of cachedMessageCounts.keys()) {
|
|
64
|
-
if (key === prefix) {
|
|
65
|
-
cachedMessageCounts.delete(key);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (!key.startsWith(prefix + sep))
|
|
69
|
-
continue;
|
|
70
|
-
cachedMessageCounts.delete(key);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Called from `server/bare/ops/cancel.ts` right before `addon.cancel()` so
|
|
75
|
-
* that the in-flight `completion()` for this model can detect that its
|
|
76
|
-
* current turn is being cancelled and skip poisoning `cachedMessageCounts`
|
|
77
|
-
* with a `history.length + 1` entry that does not correspond to a real
|
|
78
|
-
* assistant reply.
|
|
79
|
-
*/
|
|
80
|
-
export function noteCancelRequested(modelId) {
|
|
81
|
-
modelCancelCounters.set(modelId, (modelCancelCounters.get(modelId) ?? 0) + 1);
|
|
82
|
-
}
|
|
83
|
-
export function snapshotCancelCount(modelId) {
|
|
84
|
-
return modelCancelCounters.get(modelId) ?? 0;
|
|
85
|
-
}
|
|
86
|
-
/** Test-only. */
|
|
87
|
-
export function _resetCancelCountersForTest() {
|
|
88
|
-
modelCancelCounters.clear();
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* A completion's `savedCount` should only be recorded when the turn ran to
|
|
92
|
-
* completion AND produced at least one token. Any other outcome —
|
|
93
|
-
* cancelled mid-decode, legitimate zero-token reply, or an early EOS — must
|
|
94
|
-
* clear the entry instead, because there is no guarantee that the kv-cache
|
|
95
|
-
* file on disk matches the `history.length + 1` boundary the SDK would
|
|
96
|
-
* otherwise record.
|
|
97
|
-
*/
|
|
98
|
-
export function shouldRecordSavedCount(wasCancelled, producedTokens) {
|
|
99
|
-
return !wasCancelled && producedTokens;
|
|
100
|
-
}
|
|
101
17
|
/**
|
|
102
18
|
* Pure slice decision for `prepareMessagesForCache`.
|
|
103
19
|
*
|
|
104
20
|
* Mirrors the shape of the logic in `completion-stream.ts` but without
|
|
105
|
-
* calling `transformMessages` (which depends on `bare-fs` for
|
|
106
|
-
* probing). Kept here so the decision can be unit-tested in
|
|
21
|
+
* calling `transformMessages` (which depends on `bare-fs` for
|
|
22
|
+
* attachment probing). Kept here so the decision can be unit-tested in
|
|
23
|
+
* isolation.
|
|
107
24
|
*
|
|
108
|
-
* The key regression guard: when a non-zero `savedCount` would slice
|
|
109
|
-
* history down to an empty array, it is treated as stale — the
|
|
110
|
-
* falls back to sending the system-stripped full history rather
|
|
111
|
-
* handing the model an empty payload.
|
|
25
|
+
* The key regression guard: when a non-zero `savedCount` would slice
|
|
26
|
+
* the history down to an empty array, it is treated as stale — the
|
|
27
|
+
* caller falls back to sending the system-stripped full history rather
|
|
28
|
+
* than handing the model an empty payload.
|
|
112
29
|
*/
|
|
113
30
|
export function decideCachedHistorySlice(savedCount, cacheExists, history) {
|
|
114
31
|
if (!cacheExists || history.length === 0) {
|
|
@@ -28,7 +28,18 @@ export declare const llmPlugin: {
|
|
|
28
28
|
}>>;
|
|
29
29
|
"cache-type-k": import("zod").ZodOptional<import("zod").ZodString>;
|
|
30
30
|
"cache-type-v": import("zod").ZodOptional<import("zod").ZodString>;
|
|
31
|
+
"main-gpu": import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodNumber, import("zod").ZodEnum<{
|
|
32
|
+
integrated: "integrated";
|
|
33
|
+
dedicated: "dedicated";
|
|
34
|
+
}>]>>;
|
|
35
|
+
"split-mode": import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
36
|
+
none: "none";
|
|
37
|
+
layer: "layer";
|
|
38
|
+
row: "row";
|
|
39
|
+
}>>;
|
|
40
|
+
"tensor-split": import("zod").ZodOptional<import("zod").ZodString>;
|
|
31
41
|
openclCacheDir: import("zod").ZodOptional<import("zod").ZodString>;
|
|
42
|
+
reasoning_budget: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodLiteral<-1>, import("zod").ZodLiteral<0>]>>;
|
|
32
43
|
projectionModelSrc: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
|
|
33
44
|
src: import("zod").ZodString;
|
|
34
45
|
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
@@ -42,6 +53,9 @@ export declare const llmPlugin: {
|
|
|
42
53
|
sha256Checksum: import("zod").ZodOptional<import("zod").ZodString>;
|
|
43
54
|
addon: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodEnum<{
|
|
44
55
|
embeddings: "embeddings";
|
|
56
|
+
diffusion: "diffusion";
|
|
57
|
+
tts: "tts";
|
|
58
|
+
ocr: "ocr";
|
|
45
59
|
"llamacpp-completion": "llamacpp-completion";
|
|
46
60
|
"whispercpp-transcription": "whispercpp-transcription";
|
|
47
61
|
"llamacpp-embedding": "llamacpp-embedding";
|
|
@@ -54,9 +68,6 @@ export declare const llmPlugin: {
|
|
|
54
68
|
whisper: "whisper";
|
|
55
69
|
nmt: "nmt";
|
|
56
70
|
parakeet: "parakeet";
|
|
57
|
-
tts: "tts";
|
|
58
|
-
ocr: "ocr";
|
|
59
|
-
diffusion: "diffusion";
|
|
60
71
|
}>, import("zod").ZodLiteral<"vad">]>>;
|
|
61
72
|
}, import("zod/v4/core").$strip>]>>;
|
|
62
73
|
}, import("zod/v4/core").$strip>;
|
|
@@ -83,7 +94,11 @@ export declare const llmPlugin: {
|
|
|
83
94
|
toolsMode?: "static" | "dynamic" | undefined;
|
|
84
95
|
"cache-type-k"?: string | undefined;
|
|
85
96
|
"cache-type-v"?: string | undefined;
|
|
97
|
+
"main-gpu"?: number | "integrated" | "dedicated" | undefined;
|
|
98
|
+
"split-mode"?: "none" | "layer" | "row" | undefined;
|
|
99
|
+
"tensor-split"?: string | undefined;
|
|
86
100
|
openclCacheDir?: string | undefined;
|
|
101
|
+
reasoning_budget?: 0 | -1 | undefined;
|
|
87
102
|
};
|
|
88
103
|
artifacts?: never;
|
|
89
104
|
} | {
|
|
@@ -109,7 +124,11 @@ export declare const llmPlugin: {
|
|
|
109
124
|
toolsMode?: "static" | "dynamic" | undefined;
|
|
110
125
|
"cache-type-k"?: string | undefined;
|
|
111
126
|
"cache-type-v"?: string | undefined;
|
|
127
|
+
"main-gpu"?: number | "integrated" | "dedicated" | undefined;
|
|
128
|
+
"split-mode"?: "none" | "layer" | "row" | undefined;
|
|
129
|
+
"tensor-split"?: string | undefined;
|
|
112
130
|
openclCacheDir?: string | undefined;
|
|
131
|
+
reasoning_budget?: 0 | -1 | undefined;
|
|
113
132
|
};
|
|
114
133
|
artifacts: {
|
|
115
134
|
projectionModelPath: string;
|
|
@@ -158,6 +177,7 @@ export declare const llmPlugin: {
|
|
|
158
177
|
frequency_penalty: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
159
178
|
presence_penalty: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
160
179
|
repeat_penalty: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
180
|
+
reasoning_budget: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodLiteral<-1>, import("zod").ZodLiteral<0>]>>;
|
|
161
181
|
}, import("zod/v4/core").$strict>>;
|
|
162
182
|
captureThinking: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
163
183
|
emitRawDeltas: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
@@ -166,6 +186,8 @@ export declare const llmPlugin: {
|
|
|
166
186
|
pythonic: "pythonic";
|
|
167
187
|
json: "json";
|
|
168
188
|
harmony: "harmony";
|
|
189
|
+
qwen35: "qwen35";
|
|
190
|
+
gemma4: "gemma4";
|
|
169
191
|
}>>;
|
|
170
192
|
responseFormat: import("zod").ZodOptional<import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
171
193
|
type: import("zod").ZodLiteral<"text">;
|
|
@@ -180,6 +202,7 @@ export declare const llmPlugin: {
|
|
|
180
202
|
strict: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
181
203
|
}, import("zod/v4/core").$strict>;
|
|
182
204
|
}, import("zod/v4/core").$strict>], "type">>;
|
|
205
|
+
requestId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
183
206
|
type: import("zod").ZodLiteral<"completionStream">;
|
|
184
207
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
185
208
|
type: import("zod").ZodLiteral<"completionStream">;
|
|
@@ -244,6 +267,7 @@ export declare const llmPlugin: {
|
|
|
244
267
|
type: import("zod").ZodLiteral<"completionDone">;
|
|
245
268
|
seq: import("zod").ZodNumber;
|
|
246
269
|
stopReason: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
270
|
+
cancelled: "cancelled";
|
|
247
271
|
eos: "eos";
|
|
248
272
|
length: "length";
|
|
249
273
|
stopSequence: "stopSequence";
|
|
@@ -315,6 +339,7 @@ export declare const llmPlugin: {
|
|
|
315
339
|
resume: "resume";
|
|
316
340
|
}>>;
|
|
317
341
|
withProgress: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
342
|
+
requestId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
318
343
|
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
319
344
|
modelId: import("zod").ZodString;
|
|
320
345
|
options: import("zod").ZodObject<{
|
|
@@ -412,6 +437,7 @@ export declare const llmPlugin: {
|
|
|
412
437
|
nmt: "nmt";
|
|
413
438
|
}>;
|
|
414
439
|
type: import("zod").ZodLiteral<"translate">;
|
|
440
|
+
requestId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
415
441
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
416
442
|
modelId: import("zod").ZodString;
|
|
417
443
|
text: import("zod").ZodString;
|
|
@@ -424,6 +450,7 @@ export declare const llmPlugin: {
|
|
|
424
450
|
to: import("zod").ZodString;
|
|
425
451
|
context: import("zod").ZodOptional<import("zod").ZodString>;
|
|
426
452
|
type: import("zod").ZodLiteral<"translate">;
|
|
453
|
+
requestId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
427
454
|
}, import("zod/v4/core").$strip>]>, import("zod").ZodObject<{
|
|
428
455
|
type: import("zod").ZodLiteral<"translate">;
|
|
429
456
|
token: import("zod").ZodString;
|
|
@@ -1,41 +1,71 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
1
53
|
import LlmLlamacpp from "@qvac/llm-llamacpp";
|
|
2
54
|
import llmAddonLogging from "@qvac/llm-llamacpp/addonLogging.js";
|
|
3
|
-
import { definePlugin, defineHandler, finetuneRequestSchema, completionStreamRequestSchema, completionStreamResponseSchema, finetuneResponseSchema, translateRequestSchema, translateResponseSchema, ModelType, llmConfigBaseSchema, ADDON_LLM,
|
|
55
|
+
import { definePlugin, defineHandler, finetuneRequestSchema, completionStreamRequestSchema, completionStreamResponseSchema, finetuneResponseSchema, translateRequestSchema, translateResponseSchema, ModelType, llmConfigBaseSchema, ADDON_LLM, } from "../../../../schemas/index.js";
|
|
4
56
|
import { createStreamLogger, registerAddonLogger } from "../../../../logging/index.js";
|
|
5
57
|
import { expandGGUFIntoShards } from "../../../utils/index.js";
|
|
6
58
|
import { completion } from "./ops/completion-stream.js";
|
|
7
59
|
import { finetune } from "./ops/finetune.js";
|
|
8
60
|
import { translate } from "../../ops/translate.js";
|
|
61
|
+
import { transformLlmConfig } from "./transform.js";
|
|
9
62
|
import { attachModelExecutionMs } from "../../../../profiling/model-execution.js";
|
|
10
63
|
import { getModelConfig } from "../../registry/model-registry.js";
|
|
11
64
|
import { createCompletionNormalizer } from "../../../utils/completion-normalizer.js";
|
|
12
65
|
import { detectToolDialect } from "../../../utils/tool-integration.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
: key === "stop_sequences"
|
|
17
|
-
? Array.isArray(v)
|
|
18
|
-
? v.join(", ")
|
|
19
|
-
: v
|
|
20
|
-
: typeof v === "number" || typeof v === "boolean"
|
|
21
|
-
? String(v)
|
|
22
|
-
: v).replace(/"([a-z][A-Za-z]*)":/g, (_, key) => `"${key.replace(/[A-Z]/g, (l) => `_${l.toLowerCase()}`)}":`));
|
|
23
|
-
if ("stop_sequences" in transformed) {
|
|
24
|
-
transformed["reverse_prompt"] = transformed["stop_sequences"];
|
|
25
|
-
delete transformed["stop_sequences"];
|
|
26
|
-
}
|
|
27
|
-
if ("opencl_cache_dir" in transformed) {
|
|
28
|
-
transformed["openclCacheDir"] = transformed["opencl_cache_dir"];
|
|
29
|
-
delete transformed["opencl_cache_dir"];
|
|
30
|
-
}
|
|
31
|
-
if ("tools_mode" in transformed) {
|
|
32
|
-
if (transformed["tools_mode"] === TOOLS_MODE.dynamic) {
|
|
33
|
-
transformed["tools_compact"] = "true";
|
|
34
|
-
}
|
|
35
|
-
delete transformed["tools_mode"];
|
|
36
|
-
}
|
|
37
|
-
return transformed;
|
|
38
|
-
}
|
|
66
|
+
import { getRequestRegistry, withRequestContext, } from "../../runtime/index.js";
|
|
67
|
+
import { generateServerRequestId } from "../../runtime/request-id.js";
|
|
68
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
39
69
|
function createLlmModel(modelId, modelPath, llmConfig, projectionModelPath) {
|
|
40
70
|
const logger = createStreamLogger(modelId, ModelType.llamacppCompletion);
|
|
41
71
|
registerAddonLogger(modelId, ModelType.llamacppCompletion, logger);
|
|
@@ -78,71 +108,104 @@ export const llmPlugin = definePlugin({
|
|
|
78
108
|
requestSchema: completionStreamRequestSchema,
|
|
79
109
|
responseSchema: completionStreamResponseSchema,
|
|
80
110
|
streaming: true,
|
|
111
|
+
cancel: { scope: "model", hard: true },
|
|
81
112
|
handler: async function* (request) {
|
|
82
|
-
const
|
|
83
|
-
role,
|
|
84
|
-
content,
|
|
85
|
-
attachments: attachments ?? [],
|
|
86
|
-
}));
|
|
87
|
-
const modelCfg = getModelConfig(request.modelId);
|
|
88
|
-
const toolsActive = (request.tools?.length ?? 0) > 0 &&
|
|
89
|
-
modelCfg.tools === true;
|
|
90
|
-
const capabilities = {
|
|
91
|
-
toolCalling: toolsActive ? "textParse" : "none",
|
|
92
|
-
thinkingFraming: request.captureThinking ? "thinkTags" : "none",
|
|
93
|
-
};
|
|
94
|
-
// Dialect runs regardless of tool availability — thinking/content
|
|
95
|
-
// stripping is needed even on plain completions.
|
|
96
|
-
const dialect = request.toolDialect ?? detectToolDialect(request.modelId);
|
|
97
|
-
const normalizer = createCompletionNormalizer({
|
|
98
|
-
capabilities,
|
|
99
|
-
tools: request.tools ?? [],
|
|
100
|
-
captureThinking: request.captureThinking ?? false,
|
|
101
|
-
emitRawDeltas: request.emitRawDeltas ?? false,
|
|
102
|
-
toolDialect: dialect,
|
|
103
|
-
});
|
|
104
|
-
const stream = completion({
|
|
105
|
-
history: filteredHistory,
|
|
106
|
-
modelId: request.modelId,
|
|
107
|
-
kvCache: request.kvCache,
|
|
108
|
-
...(toolsActive && request.tools && { tools: request.tools }),
|
|
109
|
-
...(request.generationParams && { generationParams: request.generationParams }),
|
|
110
|
-
...(toolsActive && { toolDialect: dialect }),
|
|
111
|
-
...(request.responseFormat && { responseFormat: request.responseFormat }),
|
|
112
|
-
});
|
|
113
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
113
114
|
try {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
const filteredHistory = request.history.map(({ role, content, attachments }) => ({
|
|
116
|
+
role,
|
|
117
|
+
content,
|
|
118
|
+
attachments: attachments ?? [],
|
|
119
|
+
}));
|
|
120
|
+
const modelCfg = getModelConfig(request.modelId);
|
|
121
|
+
const toolsActive = (request.tools?.length ?? 0) > 0 &&
|
|
122
|
+
modelCfg.tools === true;
|
|
123
|
+
const capabilities = {
|
|
124
|
+
toolCalling: toolsActive ? "textParse" : "none",
|
|
125
|
+
thinkingFraming: request.captureThinking ? "thinkTags" : "none",
|
|
126
|
+
};
|
|
127
|
+
// Dialect runs regardless of tool availability — thinking/content
|
|
128
|
+
// stripping is needed even on plain completions.
|
|
129
|
+
const dialect = request.toolDialect ?? detectToolDialect(request.modelId);
|
|
130
|
+
const normalizer = createCompletionNormalizer({
|
|
131
|
+
capabilities,
|
|
132
|
+
tools: request.tools ?? [],
|
|
133
|
+
captureThinking: request.captureThinking ?? false,
|
|
134
|
+
emitRawDeltas: request.emitRawDeltas ?? false,
|
|
135
|
+
toolDialect: dialect,
|
|
136
|
+
});
|
|
137
|
+
// Open a request-scoped lifecycle. The registry is the single
|
|
138
|
+
// source of truth for "is this turn cancelled?" — we plumb the
|
|
139
|
+
// signal into `completion()` and expose `requestId` so the
|
|
140
|
+
// client can target this run with `cancel({ requestId })`.
|
|
141
|
+
// Falls back to a server-generated id if the client (e.g. an
|
|
142
|
+
// older release) didn't send one.
|
|
143
|
+
const ctx = __addDisposableResource(env_1, getRequestRegistry().begin({
|
|
144
|
+
requestId: request.requestId ?? generateServerRequestId(),
|
|
145
|
+
kind: "completion",
|
|
146
|
+
modelId: request.modelId,
|
|
147
|
+
}), true);
|
|
148
|
+
const requestLogger = withRequestContext(getServerLogger(), ctx);
|
|
149
|
+
const stream = completion({
|
|
150
|
+
history: filteredHistory,
|
|
151
|
+
modelId: request.modelId,
|
|
152
|
+
kvCache: request.kvCache,
|
|
153
|
+
...(toolsActive && request.tools && { tools: request.tools }),
|
|
154
|
+
...(request.generationParams && { generationParams: request.generationParams }),
|
|
155
|
+
...(toolsActive && { toolDialect: dialect }),
|
|
156
|
+
...(request.responseFormat && { responseFormat: request.responseFormat }),
|
|
157
|
+
}, { signal: ctx.signal, scope: ctx.scope, logger: requestLogger });
|
|
158
|
+
try {
|
|
159
|
+
const batchedEvents = [];
|
|
160
|
+
let result = await stream.next();
|
|
161
|
+
while (!result.done) {
|
|
162
|
+
const events = normalizer.push(result.value.token);
|
|
163
|
+
if (request.stream) {
|
|
164
|
+
yield {
|
|
165
|
+
type: "completionStream",
|
|
166
|
+
events,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
batchedEvents.push(...events);
|
|
171
|
+
}
|
|
172
|
+
result = await stream.next();
|
|
123
173
|
}
|
|
124
|
-
|
|
125
|
-
|
|
174
|
+
const { modelExecutionMs, stats, toolCalls } = result.value;
|
|
175
|
+
// `stopReason: "cancelled"` rides the success-done path: the
|
|
176
|
+
// events stream ends normally, the cancellation is observable
|
|
177
|
+
// via the last event's `stopReason`, and the client-side
|
|
178
|
+
// `CompletionRun` aggregates (`final` / `text` / `toolCalls` /
|
|
179
|
+
// `stats`) reject with `InferenceCancelledError` carrying the
|
|
180
|
+
// partial state.
|
|
181
|
+
const cancelled = ctx.signal.aborted;
|
|
182
|
+
const terminalEvents = normalizer.finish({
|
|
183
|
+
...(stats && { stats }),
|
|
184
|
+
...(toolCalls.length > 0 && { toolCalls }),
|
|
185
|
+
...(cancelled && { stopReason: "cancelled" }),
|
|
186
|
+
});
|
|
187
|
+
if (!request.stream) {
|
|
188
|
+
batchedEvents.push(...terminalEvents);
|
|
126
189
|
}
|
|
127
|
-
|
|
190
|
+
const finalEvents = request.stream ? terminalEvents : batchedEvents;
|
|
191
|
+
yield attachModelExecutionMs({
|
|
192
|
+
type: "completionStream",
|
|
193
|
+
done: true,
|
|
194
|
+
events: finalEvents,
|
|
195
|
+
}, modelExecutionMs);
|
|
128
196
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...(stats && { stats }),
|
|
132
|
-
...(toolCalls.length > 0 && { toolCalls }),
|
|
133
|
-
});
|
|
134
|
-
if (!request.stream) {
|
|
135
|
-
batchedEvents.push(...terminalEvents);
|
|
197
|
+
finally {
|
|
198
|
+
await stream.return?.(undefined);
|
|
136
199
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
events: finalEvents,
|
|
142
|
-
}, modelExecutionMs);
|
|
200
|
+
}
|
|
201
|
+
catch (e_1) {
|
|
202
|
+
env_1.error = e_1;
|
|
203
|
+
env_1.hasError = true;
|
|
143
204
|
}
|
|
144
205
|
finally {
|
|
145
|
-
|
|
206
|
+
const result_1 = __disposeResources(env_1);
|
|
207
|
+
if (result_1)
|
|
208
|
+
await result_1;
|
|
146
209
|
}
|
|
147
210
|
},
|
|
148
211
|
}),
|
|
@@ -150,6 +213,14 @@ export const llmPlugin = definePlugin({
|
|
|
150
213
|
requestSchema: finetuneRequestSchema,
|
|
151
214
|
responseSchema: finetuneResponseSchema,
|
|
152
215
|
streaming: false,
|
|
216
|
+
// Reality matches addon: llama.cpp exposes `model.cancel()` for
|
|
217
|
+
// the running finetune job, so we flip from `scope: "none"` to
|
|
218
|
+
// `{ scope: "model", hard: true }`. The `startFinetune` op
|
|
219
|
+
// forwards the registry's abort signal to that call; the broad
|
|
220
|
+
// `cancel({ modelId, kind: "finetune" })` and legacy
|
|
221
|
+
// `cancelFinetune(modelId)` paths both flow through the
|
|
222
|
+
// registry.
|
|
223
|
+
cancel: { scope: "model", hard: true },
|
|
153
224
|
handler: function (request) {
|
|
154
225
|
return finetune(request);
|
|
155
226
|
},
|
|
@@ -158,8 +229,9 @@ export const llmPlugin = definePlugin({
|
|
|
158
229
|
requestSchema: translateRequestSchema,
|
|
159
230
|
responseSchema: translateResponseSchema,
|
|
160
231
|
streaming: true,
|
|
232
|
+
cancel: { scope: "model", hard: true },
|
|
161
233
|
handler: async function* (request) {
|
|
162
|
-
const stream = translate(request);
|
|
234
|
+
const stream = translate(request, request.requestId);
|
|
163
235
|
try {
|
|
164
236
|
let result = await stream.next();
|
|
165
237
|
while (!result.done) {
|