@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.
Files changed (201) hide show
  1. package/NOTICE +92 -54
  2. package/dist/client/api/cancel.d.ts +24 -32
  3. package/dist/client/api/cancel.js +58 -31
  4. package/dist/client/api/client-request-id.d.ts +17 -0
  5. package/dist/client/api/client-request-id.js +27 -0
  6. package/dist/client/api/completion-stream.d.ts +1 -1
  7. package/dist/client/api/completion-stream.js +34 -3
  8. package/dist/client/api/diffusion.d.ts +46 -0
  9. package/dist/client/api/diffusion.js +50 -1
  10. package/dist/client/api/download-asset.d.ts +12 -2
  11. package/dist/client/api/download-asset.js +21 -3
  12. package/dist/client/api/embed.d.ts +8 -4
  13. package/dist/client/api/embed.js +14 -1
  14. package/dist/client/api/get-model-info.d.ts +1 -1
  15. package/dist/client/api/index.d.ts +1 -0
  16. package/dist/client/api/index.js +1 -0
  17. package/dist/client/api/load-model.d.ts +12 -4
  18. package/dist/client/api/load-model.js +25 -1
  19. package/dist/client/api/rag.d.ts +9 -3
  20. package/dist/client/api/rag.js +23 -3
  21. package/dist/client/api/transcribe.d.ts +20 -8
  22. package/dist/client/api/transcribe.js +58 -4
  23. package/dist/client/api/unload-model.d.ts +5 -2
  24. package/dist/client/api/unload-model.js +9 -4
  25. package/dist/client/api/upscale.d.ts +45 -0
  26. package/dist/client/api/upscale.js +99 -0
  27. package/dist/client/rpc/expo-rpc-client.js +2 -1
  28. package/dist/client/rpc/node-rpc-client.js +18 -7
  29. package/dist/client/rpc/rpc-client.d.ts +2 -2
  30. package/dist/client/rpc/rpc-client.js +10 -4
  31. package/dist/client/rpc/rpc-error.d.ts +9 -0
  32. package/dist/client/rpc/rpc-error.js +92 -0
  33. package/dist/examples/cancel-by-request-id.d.ts +38 -0
  34. package/dist/examples/cancel-by-request-id.js +103 -0
  35. package/dist/examples/diffusion-esrgan-upscale.d.ts +2 -0
  36. package/dist/examples/diffusion-esrgan-upscale.js +78 -0
  37. package/dist/examples/download-with-cancel.js +10 -10
  38. package/dist/examples/embed-multi-gpu.d.ts +2 -0
  39. package/dist/examples/embed-multi-gpu.js +46 -0
  40. package/dist/examples/llamacpp-multi-gpu.d.ts +2 -0
  41. package/dist/examples/llamacpp-multi-gpu.js +57 -0
  42. package/dist/examples/rag/rag-hyperdb/cancellation.js +20 -17
  43. package/dist/examples/tools/llamacpp-tools-gemma4.d.ts +2 -0
  44. package/dist/examples/tools/llamacpp-tools-gemma4.js +76 -0
  45. package/dist/examples/tools/llamacpp-tools-qwen35.d.ts +2 -0
  46. package/dist/examples/tools/llamacpp-tools-qwen35.js +70 -0
  47. package/dist/examples/transcription/whispercpp-microphone-conversation.d.ts +2 -0
  48. package/dist/examples/transcription/whispercpp-microphone-conversation.js +102 -0
  49. package/dist/examples/tts/supertonic.js +1 -1
  50. package/dist/expo/plugins/withMobileBundle.d.ts +20 -4
  51. package/dist/expo/plugins/withMobileBundle.js +44 -6
  52. package/dist/index.d.ts +5 -2
  53. package/dist/index.js +21 -1
  54. package/dist/models/registry/models.d.ts +186 -318
  55. package/dist/models/registry/models.js +1522 -1667
  56. package/dist/pear/pre.d.ts +3 -0
  57. package/dist/pear/pre.js +3 -0
  58. package/dist/schemas/cancel.d.ts +167 -28
  59. package/dist/schemas/cancel.js +119 -19
  60. package/dist/schemas/common.d.ts +427 -208
  61. package/dist/schemas/common.js +3 -1
  62. package/dist/schemas/completion-event.d.ts +14 -0
  63. package/dist/schemas/completion-event.js +11 -1
  64. package/dist/schemas/completion-stream.d.ts +15 -1
  65. package/dist/schemas/completion-stream.js +25 -7
  66. package/dist/schemas/download-asset.d.ts +15 -9
  67. package/dist/schemas/download-asset.js +17 -6
  68. package/dist/schemas/embed.d.ts +1 -0
  69. package/dist/schemas/embed.js +5 -0
  70. package/dist/schemas/error.d.ts +31 -0
  71. package/dist/schemas/error.js +29 -1
  72. package/dist/schemas/finetune.d.ts +2 -0
  73. package/dist/schemas/finetune.js +5 -0
  74. package/dist/schemas/get-model-info.d.ts +6 -6
  75. package/dist/schemas/llamacpp-config.d.ts +54 -8
  76. package/dist/schemas/llamacpp-config.js +12 -0
  77. package/dist/schemas/load-model.d.ts +1911 -1260
  78. package/dist/schemas/load-model.js +15 -0
  79. package/dist/schemas/model-src-utils.d.ts +14 -14
  80. package/dist/schemas/model-types.d.ts +10 -10
  81. package/dist/schemas/ocr.d.ts +3 -3
  82. package/dist/schemas/plugin.d.ts +40 -1
  83. package/dist/schemas/plugin.js +10 -1
  84. package/dist/schemas/rag.d.ts +9 -0
  85. package/dist/schemas/rag.js +17 -9
  86. package/dist/schemas/registry.d.ts +30 -30
  87. package/dist/schemas/reload-config.d.ts +14 -14
  88. package/dist/schemas/sdcpp-config.d.ts +131 -17
  89. package/dist/schemas/sdcpp-config.js +163 -1
  90. package/dist/schemas/sdk-config.d.ts +649 -271
  91. package/dist/schemas/sdk-errors-client.d.ts +1 -0
  92. package/dist/schemas/sdk-errors-client.js +5 -0
  93. package/dist/schemas/sdk-errors-server.d.ts +5 -0
  94. package/dist/schemas/sdk-errors-server.js +25 -0
  95. package/dist/schemas/text-to-speech.d.ts +78 -78
  96. package/dist/schemas/transcription-config.d.ts +24 -24
  97. package/dist/schemas/transcription.d.ts +56 -2
  98. package/dist/schemas/transcription.js +27 -0
  99. package/dist/schemas/translate.d.ts +2 -0
  100. package/dist/schemas/translate.js +13 -2
  101. package/dist/schemas/translation-config.d.ts +40 -40
  102. package/dist/schemas/unload-model.d.ts +2 -1
  103. package/dist/schemas/unload-model.js +4 -1
  104. package/dist/scripts/run-unit-tests.js +15 -2
  105. package/dist/server/bare/delegate-rpc-client.js +10 -8
  106. package/dist/server/bare/ops/cancel.d.ts +27 -1
  107. package/dist/server/bare/ops/cancel.js +36 -10
  108. package/dist/server/bare/ops/embed.d.ts +3 -3
  109. package/dist/server/bare/ops/embed.js +144 -28
  110. package/dist/server/bare/ops/kv-cache-utils.d.ts +0 -7
  111. package/dist/server/bare/ops/kv-cache-utils.js +8 -47
  112. package/dist/server/bare/ops/transcribe.d.ts +10 -5
  113. package/dist/server/bare/ops/transcribe.js +196 -41
  114. package/dist/server/bare/ops/translate.d.ts +1 -1
  115. package/dist/server/bare/ops/translate.js +197 -88
  116. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +12 -3
  117. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +170 -172
  118. package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +125 -21
  119. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.d.ts +154 -0
  120. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.js +448 -0
  121. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +21 -73
  122. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +18 -101
  123. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +30 -3
  124. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +157 -85
  125. package/dist/server/bare/plugins/llamacpp-completion/transform.d.ts +10 -0
  126. package/dist/server/bare/plugins/llamacpp-completion/transform.js +34 -0
  127. package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +7 -0
  128. package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +10 -1
  129. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +17 -15
  130. package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +5 -1
  131. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +3 -3
  132. package/dist/server/bare/plugins/onnx-ocr/plugin.js +3 -0
  133. package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +39 -39
  134. package/dist/server/bare/plugins/onnx-tts/plugin.js +6 -0
  135. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +29 -21
  136. package/dist/server/bare/plugins/parakeet-transcription/plugin.js +4 -1
  137. package/dist/server/bare/plugins/sdcpp-generation/ops/diffusion.js +8 -0
  138. package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.d.ts +3 -0
  139. package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.js +40 -0
  140. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +91 -16
  141. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +97 -7
  142. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +22 -3
  143. package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +50 -14
  144. package/dist/server/bare/rag-hyperdb/index.d.ts +1 -1
  145. package/dist/server/bare/rag-hyperdb/index.js +1 -1
  146. package/dist/server/bare/rag-hyperdb/rag-operation-manager.d.ts +26 -4
  147. package/dist/server/bare/rag-hyperdb/rag-operation-manager.js +65 -28
  148. package/dist/server/bare/runtime/disposable-scope.d.ts +36 -0
  149. package/dist/server/bare/runtime/disposable-scope.js +69 -0
  150. package/dist/server/bare/runtime/index.d.ts +8 -0
  151. package/dist/server/bare/runtime/index.js +3 -0
  152. package/dist/server/bare/runtime/request-context.d.ts +49 -0
  153. package/dist/server/bare/runtime/request-context.js +1 -0
  154. package/dist/server/bare/runtime/request-id.d.ts +12 -0
  155. package/dist/server/bare/runtime/request-id.js +14 -0
  156. package/dist/server/bare/runtime/request-registry-singleton.d.ts +4 -0
  157. package/dist/server/bare/runtime/request-registry-singleton.js +27 -0
  158. package/dist/server/bare/runtime/request-registry.d.ts +136 -0
  159. package/dist/server/bare/runtime/request-registry.js +297 -0
  160. package/dist/server/bare/runtime/with-request-context.d.ts +22 -0
  161. package/dist/server/bare/runtime/with-request-context.js +53 -0
  162. package/dist/server/bare/types/addon-responses.d.ts +11 -1
  163. package/dist/server/rpc/handler-registry.js +26 -7
  164. package/dist/server/rpc/handlers/cancel-delegated.js +28 -31
  165. package/dist/server/rpc/handlers/cancelHandler.d.ts +30 -1
  166. package/dist/server/rpc/handlers/cancelHandler.js +54 -22
  167. package/dist/server/rpc/handlers/delete-cache.d.ts +9 -0
  168. package/dist/server/rpc/handlers/delete-cache.js +13 -15
  169. package/dist/server/rpc/handlers/download-asset.js +133 -40
  170. package/dist/server/rpc/handlers/index.d.ts +2 -0
  171. package/dist/server/rpc/handlers/index.js +2 -0
  172. package/dist/server/rpc/handlers/load-model/download-manager.d.ts +60 -2
  173. package/dist/server/rpc/handlers/load-model/download-manager.js +141 -8
  174. package/dist/server/rpc/handlers/load-model/handler.js +213 -98
  175. package/dist/server/rpc/handlers/load-model/http.js +3 -3
  176. package/dist/server/rpc/handlers/load-model/hyperdrive.js +1 -1
  177. package/dist/server/rpc/handlers/load-model/registry.js +1 -1
  178. package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +20 -1
  179. package/dist/server/rpc/handlers/load-model/resolve-session.js +6 -5
  180. package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -2
  181. package/dist/server/rpc/handlers/load-model/resolve.js +9 -6
  182. package/dist/server/rpc/handlers/load-model/types.d.ts +24 -0
  183. package/dist/server/rpc/handlers/rag.js +133 -15
  184. package/dist/server/rpc/handlers/upscale-stream.d.ts +3 -0
  185. package/dist/server/rpc/handlers/upscale-stream.js +4 -0
  186. package/dist/server/utils/completion-normalizer.js +8 -0
  187. package/dist/server/utils/tools/dialect.js +4 -0
  188. package/dist/server/utils/tools/parser.js +16 -1
  189. package/dist/server/utils/tools/parsers/gemma4native.d.ts +4 -0
  190. package/dist/server/utils/tools/parsers/gemma4native.js +60 -0
  191. package/dist/server/utils/tools/parsers/qwen35.d.ts +4 -0
  192. package/dist/server/utils/tools/parsers/qwen35.js +120 -0
  193. package/dist/utils/aggregate-events.d.ts +9 -0
  194. package/dist/utils/aggregate-events.js +18 -3
  195. package/dist/utils/decorate-promise.d.ts +34 -0
  196. package/dist/utils/decorate-promise.js +35 -0
  197. package/dist/utils/errors-client.d.ts +3 -0
  198. package/dist/utils/errors-client.js +5 -0
  199. package/dist/utils/errors-server.d.ts +85 -0
  200. package/dist/utils/errors-server.js +97 -0
  201. package/package.json +20 -15
@@ -1,5 +1,6 @@
1
1
  import { type ModelProgressUpdate } from "../../../../schemas/index";
2
2
  import type { ResolveResult, DownloadHooks } from "./types";
3
- export declare function resolveModelPath(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean, hooks?: DownloadHooks): Promise<string>;
4
- export declare function resolveModelPathWithStats(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean, hooks?: DownloadHooks): Promise<ResolveResult>;
3
+ import type { AbortSignal } from "bare-abort-controller";
4
+ export declare function resolveModelPath(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean, signal?: AbortSignal, hooks?: DownloadHooks): Promise<string>;
5
+ export declare function resolveModelPathWithStats(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean, signal?: AbortSignal, hooks?: DownloadHooks): Promise<ResolveResult>;
5
6
  //# sourceMappingURL=resolve.d.ts.map
@@ -7,7 +7,7 @@ import { downloadModelFromHttp } from "./http.js";
7
7
  import { downloadModelFromHyperdrive } from "./hyperdrive.js";
8
8
  import { downloadModelFromRegistry } from "./registry.js";
9
9
  import { downloadModelFromHttpWithStats, downloadModelFromHyperdriveWithStats, downloadModelFromRegistryWithStats, } from "./download-stats.js";
10
- import { ModelLoadFailedError, ModelNotFoundError, SeedingNotSupportedError, } from "../../../../utils/errors-server.js";
10
+ import { InferenceCancelledError, ModelLoadFailedError, ModelNotFoundError, SeedingNotSupportedError, } from "../../../../utils/errors-server.js";
11
11
  import { validateAndJoinPath } from "../../../utils/path-security.js";
12
12
  import { getServerLogger } from "../../../../logging/index.js";
13
13
  import { modelInputToSrcSchema } from "../../../../schemas/index.js";
@@ -74,7 +74,10 @@ function buildResult(pathOrResult, sourceType) {
74
74
  }
75
75
  return { path: pathOrResult, sourceType };
76
76
  }
77
- async function resolveModelPathCore(modelSrc, progressCallback, seed, mode, hooks) {
77
+ async function resolveModelPathCore(modelSrc, progressCallback, seed, mode, signal, hooks) {
78
+ if (signal?.aborted) {
79
+ throw new InferenceCancelledError(hooks?.requestBinding?.requestId ?? "unknown");
80
+ }
78
81
  const srcString = modelInputToSrcSchema.parse(modelSrc);
79
82
  // Parse hyperdrive URLs if present
80
83
  let hyperdriveKey;
@@ -137,10 +140,10 @@ async function resolveModelPathCore(modelSrc, progressCallback, seed, mode, hook
137
140
  }
138
141
  return { path: resolvedPath, sourceType: "filesystem" };
139
142
  }
140
- export async function resolveModelPath(modelSrc, progressCallback, seed, hooks) {
141
- const result = await resolveModelPathCore(modelSrc, progressCallback, seed, "base", hooks);
143
+ export async function resolveModelPath(modelSrc, progressCallback, seed, signal, hooks) {
144
+ const result = await resolveModelPathCore(modelSrc, progressCallback, seed, "base", signal, hooks);
142
145
  return result.path;
143
146
  }
144
- export async function resolveModelPathWithStats(modelSrc, progressCallback, seed, hooks) {
145
- return resolveModelPathCore(modelSrc, progressCallback, seed, "stats", hooks);
147
+ export async function resolveModelPathWithStats(modelSrc, progressCallback, seed, signal, hooks) {
148
+ return resolveModelPathCore(modelSrc, progressCallback, seed, "stats", signal, hooks);
146
149
  }
@@ -1,4 +1,6 @@
1
1
  import type { SourceType } from "../../../../schemas/index";
2
+ import type { AbortSignal } from "bare-abort-controller";
3
+ import type { DisposableScope } from "../../../bare/runtime/disposable-scope";
2
4
  export interface DownloadStats {
3
5
  downloadTimeMs?: number;
4
6
  totalBytesDownloaded?: number;
@@ -16,12 +18,34 @@ export interface DownloadResult {
16
18
  path: string;
17
19
  stats?: DownloadStats;
18
20
  }
21
+ /**
22
+ * Internal request binding threaded through `DownloadHooks` so the
23
+ * download manager's `startOrJoinDownload` can register a per-subscriber
24
+ * cancel hook against the caller's `RequestContext`. The binding's
25
+ * fields mirror the registry context's surface area: `signal` is wired
26
+ * to a subscriber-removing listener, `scope` registers the idempotent
27
+ * cleanup, and `requestId` lets `cancelTransfer` (legacy entry point)
28
+ * route cancels through `registry.cancel(...)` rather than reaching
29
+ * into the transfer directly.
30
+ */
31
+ export interface DownloadRequestBinding {
32
+ signal: AbortSignal;
33
+ scope: DisposableScope;
34
+ requestId: string;
35
+ }
19
36
  export interface DownloadHooks {
20
37
  onDownloadKey?: (key: string) => void;
21
38
  markCacheHit?: () => void;
22
39
  markCacheMiss?: () => void;
23
40
  markSharedTransfer?: () => void;
24
41
  addChecksumValidationTimeMs?: (durationMs: number) => void;
42
+ /**
43
+ * When set, `startOrJoinDownload` attaches a per-subscriber cancel
44
+ * listener bound to this request. `registry.cancel({ requestId })`
45
+ * aborts only this subscriber; the transfer keeps running for siblings
46
+ * joined on the same `downloadKey` until the last subscriber leaves.
47
+ */
48
+ requestBinding?: DownloadRequestBinding;
25
49
  }
26
50
  export interface LoadModelProfilingMeta {
27
51
  sourceType?: string;
@@ -1,4 +1,59 @@
1
- import { chunk, ingest, reindex, saveEmbeddings, search, deleteEmbeddings, listWorkspaces, closeWorkspace, deleteWorkspace, DEFAULT_WORKSPACE, registerRagOperation, unregisterRagOperation, } from "../../bare/rag-hyperdb/index.js";
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
+ });
53
+ import { chunk, ingest, reindex, saveEmbeddings, search, deleteEmbeddings, listWorkspaces, closeWorkspace, deleteWorkspace, DEFAULT_WORKSPACE, getActiveRagRequest, setActiveRagRequest, clearActiveRagRequest, } from "../../bare/rag-hyperdb/index.js";
54
+ import { getRequestRegistry, withRequestContext, } from "../../bare/runtime/index.js";
55
+ import { generateServerRequestId } from "../../bare/runtime/request-id.js";
56
+ import { getServerLogger } from "../../../logging/index.js";
2
57
  import { profileReplyHandler, registerOperationMetrics, } from "../profiling/index.js";
3
58
  registerOperationMetrics({
4
59
  op: "rag",
@@ -20,8 +75,7 @@ registerOperationMetrics({
20
75
  return Object.keys(gauges).length > 0 ? gauges : undefined;
21
76
  },
22
77
  });
23
- function createHandlerOptions(operation, workspace, onProgress) {
24
- const signal = registerRagOperation(workspace, operation);
78
+ function createHandlerOptions(operation, workspace, signal, onProgress) {
25
79
  const options = { signal };
26
80
  if (onProgress) {
27
81
  options.onProgress = (stage, current, total) => onProgress({
@@ -42,6 +96,37 @@ function omitOnProgress(obj) {
42
96
  void withProgress;
43
97
  return rest;
44
98
  }
99
+ /**
100
+ * Begin a registry-tracked RAG context with workspace-level pre-emption.
101
+ *
102
+ * Workspace-level admission lives in the dispatcher rather than as a
103
+ * registry policy primitive (it's a dispatch concern, not a registry
104
+ * `kind` admission rule). The sequence is **cancel-prior → begin-new**:
105
+ * if another RAG operation is already running on the same workspace,
106
+ * cancel it first, then begin the new context. Reversing the order
107
+ * would cancel the just-installed context.
108
+ *
109
+ * The workspace → requestId map is updated after `begin(...)` succeeds
110
+ * and cleared on scope unwind via `scope.defer(...)`, with a
111
+ * "still mine?" guard so an older op's deferred cleanup cannot stomp
112
+ * a newer op's mapping.
113
+ */
114
+ function beginRagContext(workspace, requestId) {
115
+ const registry = getRequestRegistry();
116
+ const prev = getActiveRagRequest(workspace);
117
+ if (prev !== undefined && prev !== requestId) {
118
+ registry.cancel({ requestId: prev, reason: "rag-workspace-preempt" });
119
+ }
120
+ const ctx = registry.begin({
121
+ requestId,
122
+ kind: "rag",
123
+ });
124
+ setActiveRagRequest(workspace, requestId);
125
+ ctx.scope.defer(() => {
126
+ clearActiveRagRequest(workspace, requestId);
127
+ });
128
+ return ctx;
129
+ }
45
130
  export async function handleRag(request, onProgress) {
46
131
  return profileReplyHandler({ op: "rag", request }, async () => handleRagInternal(request, onProgress));
47
132
  }
@@ -57,10 +142,15 @@ async function handleRagInternal(request, onProgress) {
57
142
  };
58
143
  }
59
144
  case "ingest": {
60
- const workspace = request.workspace ?? DEFAULT_WORKSPACE;
61
- const handlerOptions = createHandlerOptions("ingest", workspace, onProgress);
62
- const params = omitOnProgress(request);
145
+ const env_1 = { stack: [], error: void 0, hasError: false };
63
146
  try {
147
+ const workspace = request.workspace ?? DEFAULT_WORKSPACE;
148
+ const requestId = request.requestId ?? generateServerRequestId();
149
+ const ctx = __addDisposableResource(env_1, beginRagContext(workspace, requestId), true);
150
+ const log = withRequestContext(getServerLogger(), ctx);
151
+ log.debug("ingest start");
152
+ const handlerOptions = createHandlerOptions("ingest", workspace, ctx.signal, onProgress);
153
+ const params = omitOnProgress(request);
64
154
  const result = await ingest(params, handlerOptions);
65
155
  return {
66
156
  type: "rag",
@@ -70,15 +160,26 @@ async function handleRagInternal(request, onProgress) {
70
160
  droppedIndices: result.droppedIndices,
71
161
  };
72
162
  }
163
+ catch (e_1) {
164
+ env_1.error = e_1;
165
+ env_1.hasError = true;
166
+ }
73
167
  finally {
74
- unregisterRagOperation(workspace);
168
+ const result_1 = __disposeResources(env_1);
169
+ if (result_1)
170
+ await result_1;
75
171
  }
76
172
  }
77
173
  case "saveEmbeddings": {
78
- const workspace = request.workspace ?? DEFAULT_WORKSPACE;
79
- const handlerOptions = createHandlerOptions("saveEmbeddings", workspace, onProgress);
80
- const params = omitOnProgress(request);
174
+ const env_2 = { stack: [], error: void 0, hasError: false };
81
175
  try {
176
+ const workspace = request.workspace ?? DEFAULT_WORKSPACE;
177
+ const requestId = request.requestId ?? generateServerRequestId();
178
+ const ctx = __addDisposableResource(env_2, beginRagContext(workspace, requestId), true);
179
+ const log = withRequestContext(getServerLogger(), ctx);
180
+ log.debug("saveEmbeddings start");
181
+ const handlerOptions = createHandlerOptions("saveEmbeddings", workspace, ctx.signal, onProgress);
182
+ const params = omitOnProgress(request);
82
183
  const processed = await saveEmbeddings(params, handlerOptions);
83
184
  return {
84
185
  type: "rag",
@@ -87,8 +188,14 @@ async function handleRagInternal(request, onProgress) {
87
188
  processed,
88
189
  };
89
190
  }
191
+ catch (e_2) {
192
+ env_2.error = e_2;
193
+ env_2.hasError = true;
194
+ }
90
195
  finally {
91
- unregisterRagOperation(workspace);
196
+ const result_2 = __disposeResources(env_2);
197
+ if (result_2)
198
+ await result_2;
92
199
  }
93
200
  }
94
201
  case "search": {
@@ -109,10 +216,15 @@ async function handleRagInternal(request, onProgress) {
109
216
  };
110
217
  }
111
218
  case "reindex": {
112
- const workspace = request.workspace ?? DEFAULT_WORKSPACE;
113
- const handlerOptions = createHandlerOptions("reindex", workspace, onProgress);
114
- const params = omitOnProgress(request);
219
+ const env_3 = { stack: [], error: void 0, hasError: false };
115
220
  try {
221
+ const workspace = request.workspace ?? DEFAULT_WORKSPACE;
222
+ const requestId = request.requestId ?? generateServerRequestId();
223
+ const ctx = __addDisposableResource(env_3, beginRagContext(workspace, requestId), true);
224
+ const log = withRequestContext(getServerLogger(), ctx);
225
+ log.debug("reindex start");
226
+ const handlerOptions = createHandlerOptions("reindex", workspace, ctx.signal, onProgress);
227
+ const params = omitOnProgress(request);
116
228
  const result = await reindex(params, handlerOptions);
117
229
  return {
118
230
  type: "rag",
@@ -121,8 +233,14 @@ async function handleRagInternal(request, onProgress) {
121
233
  result,
122
234
  };
123
235
  }
236
+ catch (e_3) {
237
+ env_3.error = e_3;
238
+ env_3.hasError = true;
239
+ }
124
240
  finally {
125
- unregisterRagOperation(workspace);
241
+ const result_3 = __disposeResources(env_3);
242
+ if (result_3)
243
+ await result_3;
126
244
  }
127
245
  }
128
246
  case "listWorkspaces": {
@@ -0,0 +1,3 @@
1
+ import type { UpscaleStreamRequest, UpscaleStreamResponse } from "../../../schemas/sdcpp-config";
2
+ export declare function handleUpscaleStream(request: UpscaleStreamRequest): AsyncGenerator<UpscaleStreamResponse>;
3
+ //# sourceMappingURL=upscale-stream.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { dispatchPluginStream } from "./plugin-dispatch.js";
2
+ export async function* handleUpscaleStream(request) {
3
+ yield* dispatchPluginStream(request.modelId, "upscaleStream", request);
4
+ }
@@ -34,6 +34,14 @@ const DIALECT_SPECS = {
34
34
  "<|return|>",
35
35
  ],
36
36
  },
37
+ qwen35: {
38
+ // Same <tool_call>…</tool_call> framing as hermes; inner content is XML.
39
+ toolFrames: [{ open: "<tool_call>", close: "</tool_call>" }],
40
+ },
41
+ gemma4: {
42
+ toolFrames: [{ open: "<|tool_call>", close: "<tool_call|>" }],
43
+ thinkingFrames: [{ open: "<|channel>thought", close: "<channel|>" }],
44
+ },
37
45
  };
38
46
  // Capture-gated reasoning marker — the generic `<think>...</think>`
39
47
  // convention used by reasoning-tuned models. When the gate is off the
@@ -6,6 +6,10 @@
6
6
  export function detectToolDialectFromName(name, path) {
7
7
  const basename = path.toLowerCase().split(/[/\\]/).pop() ?? "";
8
8
  const tag = `${(name ?? "").toLowerCase()}|${basename}`;
9
+ if (/qwen3[._-]?[56](?![a-z0-9])/.test(tag))
10
+ return "qwen35";
11
+ if (/gemma[-_]?4(?=[^a-z0-9]|$)/.test(tag))
12
+ return "gemma4";
9
13
  if (/gpt[_-]?oss/.test(tag))
10
14
  return "harmony";
11
15
  if (/lfm[_-]?\d/.test(tag))
@@ -3,6 +3,8 @@ import { parseGemmaFormat, parseGenericFormat, parseLlamacppFormat, } from "./pa
3
3
  import { parseHermesFormat } from "./parsers/hermes.js";
4
4
  import { parsePythonicFormat } from "./parsers/pythonic.js";
5
5
  import { parseHarmonyFormat } from "./parsers/harmony.js";
6
+ import { parseQwen35Format } from "./parsers/qwen35.js";
7
+ import { parseGemma4NativeFormat } from "./parsers/gemma4native.js";
6
8
  function pickFormatParsers(dialect) {
7
9
  switch (dialect) {
8
10
  case "pythonic":
@@ -15,13 +17,26 @@ function pickFormatParsers(dialect) {
15
17
  return [parseGemmaFormat, parseLlamacppFormat];
16
18
  case "harmony":
17
19
  return [parseHarmonyFormat];
20
+ case "qwen35":
21
+ // Hermes fallback: Qwen3.5 templates sometimes emit OpenAI-style JSON
22
+ // when the native XML format fails; Hermes chain recovers those.
23
+ return [parseQwen35Format, parseHermesFormat];
24
+ case "gemma4":
25
+ // No JSON fallback: Gemma4 emits only its native channel-thought dialect
26
+ // and never falls back to JSON-envelope formats.
27
+ return [parseGemma4NativeFormat];
18
28
  default:
19
- // Harmony first: `to=functions.` is uniquely Harmony and can't
29
+ // Gemma4 first: `<|tool_call>` is uniquely distinctive and can't
20
30
  // false-match other dialects.
31
+ // Harmony next: `to=functions.` is also uniquely Harmony.
32
+ // Qwen35 before Hermes: defers to Hermes when JSON is inside <tool_call>,
33
+ // so the XML path is recovered without breaking Hermes-JSON payloads.
21
34
  // Pythonic last: its bare `[name(...)]` form can match payloads that
22
35
  // look like other dialects.
23
36
  return [
37
+ parseGemma4NativeFormat,
24
38
  parseHarmonyFormat,
39
+ parseQwen35Format,
25
40
  parseHermesFormat,
26
41
  parseGemmaFormat,
27
42
  parseLlamacppFormat,
@@ -0,0 +1,4 @@
1
+ import type { Tool } from "../../../../schemas/index";
2
+ import { type ParserResult } from "../shared";
3
+ export declare function parseGemma4NativeFormat(text: string, tools: Tool[]): ParserResult;
4
+ //# sourceMappingURL=gemma4native.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { generateStableToolCallId, validateToolArguments, } from "../shared.js";
2
+ // Transliterates Gemma 4's JS-literal argument body to valid JSON so it can
3
+ // be parsed with JSON.parse. The body uses:
4
+ // - <|"|>...<|"|> instead of "..." for string values
5
+ // - bare (unquoted) object keys
6
+ // Strategy: split by <|"|> tokens so structural parts (even indices) and
7
+ // string value parts (odd indices) are processed separately, preventing
8
+ // the key-quoting regex from matching `, key:` patterns inside string values.
9
+ function gemmaArgsToJson(argsRaw) {
10
+ const parts = ("{" + argsRaw + "}").split(/<\|"\|>/);
11
+ return parts
12
+ .map((part, i) => i % 2 === 0
13
+ ? part.replace(/([{,]\s*)([A-Za-z_][\w-]*)\s*:/g, '$1"$2":')
14
+ : '"' + part.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/[\x00-\x1f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`) + '"')
15
+ .join("");
16
+ }
17
+ // Parses Gemma 4's native tool-call dialect:
18
+ // <|tool_call>call:NAME{key:<|"|>val<|"|>,key2:bareNum,...}<tool_call|>
19
+ // Keys are bare identifiers; string values are wrapped in <|"|>...<|"|>;
20
+ // numbers/booleans are bare literals; nested objects/arrays use JS-literal
21
+ // syntax throughout. Transliterates to JSON then parses.
22
+ export function parseGemma4NativeFormat(text, tools) {
23
+ const toolCalls = [];
24
+ const errors = [];
25
+ if (!text.includes("<|tool_call>")) {
26
+ return { matched: false, toolCalls, errors };
27
+ }
28
+ const callRegex = /<\|tool_call>call:([A-Za-z_][\w-]*)\{([\s\S]*?)\}<tool_call\|>/g;
29
+ const matches = Array.from(text.matchAll(callRegex));
30
+ if (matches.length === 0)
31
+ return { matched: false, toolCalls, errors };
32
+ for (const match of matches) {
33
+ const name = match[1];
34
+ const argsRaw = match[2];
35
+ let args;
36
+ try {
37
+ args = JSON.parse(gemmaArgsToJson(argsRaw));
38
+ }
39
+ catch (err) {
40
+ errors.push({
41
+ code: "PARSE_ERROR",
42
+ message: `Failed to parse Gemma 4 tool call arguments: ${err instanceof Error ? err.message : String(err)}`,
43
+ raw: match[0],
44
+ });
45
+ continue;
46
+ }
47
+ const validation = validateToolArguments(name, args, tools);
48
+ if (!validation.isValid && validation.error) {
49
+ errors.push({ ...validation.error, raw: match[0] });
50
+ continue;
51
+ }
52
+ toolCalls.push({
53
+ id: generateStableToolCallId(name, args),
54
+ name,
55
+ arguments: args,
56
+ raw: match[0],
57
+ });
58
+ }
59
+ return { matched: true, toolCalls, errors };
60
+ }
@@ -0,0 +1,4 @@
1
+ import type { Tool } from "../../../../schemas/index";
2
+ import { type ParserResult } from "../shared";
3
+ export declare function parseQwen35Format(text: string, tools: Tool[]): ParserResult;
4
+ //# sourceMappingURL=qwen35.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { generateStableToolCallId, validateToolArguments, } from "../shared.js";
2
+ // Coerce raw parameter text to the type declared in the tool's JSON schema.
3
+ // String values are raw (not JSON-quoted); arrays/objects are valid JSON.
4
+ function coerceParamValue(raw, schema) {
5
+ const trimmed = raw.trim();
6
+ if (!schema?.type)
7
+ return trimmed;
8
+ switch (schema.type) {
9
+ case "number": {
10
+ if (trimmed.length === 0)
11
+ throw new Error(`invalid numeric value: ""`);
12
+ const n = Number(trimmed);
13
+ if (Number.isNaN(n))
14
+ throw new Error(`invalid numeric value: "${trimmed}"`);
15
+ return n;
16
+ }
17
+ case "integer": {
18
+ if (trimmed.length === 0)
19
+ throw new Error(`invalid integer value: ""`);
20
+ const n = Number(trimmed);
21
+ if (Number.isNaN(n) || !Number.isInteger(n))
22
+ throw new Error(`invalid integer value: "${trimmed}"`);
23
+ return n;
24
+ }
25
+ case "boolean":
26
+ if (trimmed === "true")
27
+ return true;
28
+ if (trimmed === "false")
29
+ return false;
30
+ throw new Error(`invalid boolean value: "${trimmed}"`);
31
+ case "array":
32
+ case "object":
33
+ return JSON.parse(trimmed);
34
+ default:
35
+ return trimmed;
36
+ }
37
+ }
38
+ // Parses Qwen3.5/3.6 Pythonic-XML tool-call format:
39
+ // <tool_call>
40
+ // <function=NAME>
41
+ // <parameter=KEY>VALUE</parameter>
42
+ // </function>
43
+ // </tool_call>
44
+ // String parameter values are raw text (not JSON-quoted); arrays/objects
45
+ // are JSON. Type coercion uses the tool schema; unknown params pass through.
46
+ export function parseQwen35Format(text, tools) {
47
+ const toolCalls = [];
48
+ const errors = [];
49
+ if (!text.includes("<tool_call>")) {
50
+ return { matched: false, toolCalls, errors };
51
+ }
52
+ const outerRegex = /<tool_call>([\s\S]*?)<\/tool_call>/g;
53
+ const outerMatches = Array.from(text.matchAll(outerRegex));
54
+ if (outerMatches.length === 0)
55
+ return { matched: false, toolCalls, errors };
56
+ // If no match contains XML function syntax, check if this is JSON format
57
+ // (defer to hermes) or just malformed content (surface as PARSE_ERROR).
58
+ if (!outerMatches.some((m) => m[1].includes("<function="))) {
59
+ const looksLikeJson = outerMatches.some((m) => {
60
+ const inner = m[1].trim();
61
+ return inner.startsWith("{") || inner.startsWith("[");
62
+ });
63
+ if (looksLikeJson)
64
+ return { matched: false, toolCalls, errors };
65
+ return {
66
+ matched: true,
67
+ toolCalls,
68
+ errors: outerMatches.map((m) => ({
69
+ code: "PARSE_ERROR",
70
+ message: "Qwen3.5 tool call missing <function=NAME>...</function>",
71
+ raw: m[1].trim(),
72
+ })),
73
+ };
74
+ }
75
+ for (const outerMatch of outerMatches) {
76
+ const inner = outerMatch[1].trim();
77
+ const fnMatch = /<function=([^>\s]+)\s*>([\s\S]*?)<\/function>/i.exec(inner);
78
+ if (!fnMatch) {
79
+ errors.push({
80
+ code: "PARSE_ERROR",
81
+ message: "Qwen3.5 tool call missing <function=NAME>...</function>",
82
+ raw: inner,
83
+ });
84
+ continue;
85
+ }
86
+ const name = fnMatch[1].trim();
87
+ const paramsBlock = fnMatch[2];
88
+ const tool = tools.find((t) => t.name === name);
89
+ const schemaProperties = tool?.parameters?.properties ?? {};
90
+ const args = {};
91
+ let parseError;
92
+ try {
93
+ const paramRegex = /<parameter=([^>\s]+)\s*>([\s\S]*?)<\/parameter>/gi;
94
+ let pm;
95
+ while ((pm = paramRegex.exec(paramsBlock)) !== null) {
96
+ const paramName = pm[1].trim();
97
+ args[paramName] = coerceParamValue(pm[2], schemaProperties[paramName]);
98
+ }
99
+ }
100
+ catch (err) {
101
+ parseError = err instanceof Error ? err.message : String(err);
102
+ }
103
+ if (parseError !== undefined) {
104
+ errors.push({ code: "PARSE_ERROR", message: parseError, raw: inner });
105
+ continue;
106
+ }
107
+ const validation = validateToolArguments(name, args, tools);
108
+ if (!validation.isValid && validation.error) {
109
+ errors.push({ ...validation.error, raw: inner });
110
+ continue;
111
+ }
112
+ toolCalls.push({
113
+ id: generateStableToolCallId(name, args),
114
+ name,
115
+ arguments: args,
116
+ raw: inner,
117
+ });
118
+ }
119
+ return { matched: true, toolCalls, errors };
120
+ }
@@ -7,10 +7,19 @@ export type AggregatedEvents = {
7
7
  toolCalls: ToolCall[];
8
8
  rawFullText: string | undefined;
9
9
  error: CompletionError | undefined;
10
+ /**
11
+ * True when the terminal `completionDone` carried
12
+ * `stopReason: "cancelled"`. The client wrapper rejects the
13
+ * promise-aggregates (`final` / `text` / `toolCalls` / `stats`) with
14
+ * `InferenceCancelledError` carrying the partial state when this is
15
+ * set; the `events` stream itself still ends normally.
16
+ */
17
+ cancelled: boolean;
10
18
  };
11
19
  export declare function aggregateEvents(events: CompletionEvent[]): AggregatedEvents;
12
20
  export declare function buildFinalFromEvents(events: CompletionEvent[], handlers: ToolHandlerMap): {
13
21
  final: CompletionFinal;
14
22
  error: CompletionError | undefined;
23
+ cancelled: boolean;
15
24
  };
16
25
  //# sourceMappingURL=aggregate-events.d.ts.map
@@ -6,6 +6,7 @@ export function aggregateEvents(events) {
6
6
  let stats;
7
7
  let rawFullText;
8
8
  let error;
9
+ let cancelled = false;
9
10
  const toolCalls = [];
10
11
  for (const event of events) {
11
12
  if (event.type === "contentDelta") {
@@ -24,15 +25,29 @@ export function aggregateEvents(events) {
24
25
  if ("raw" in event && event.raw) {
25
26
  rawFullText = event.raw.fullText;
26
27
  }
28
+ // Error wins over cancelled if a wire event ever carries both
29
+ // signals: a mid-stream addon failure makes the partial state
30
+ // unsafe to expose, regardless of why the loop exited.
27
31
  if (event.stopReason === "error" && "error" in event) {
28
32
  error = event.error;
29
33
  }
34
+ else if (event.stopReason === "cancelled") {
35
+ cancelled = true;
36
+ }
30
37
  }
31
38
  }
32
- return { contentText, thinkingText, stats, toolCalls, rawFullText, error };
39
+ return {
40
+ contentText,
41
+ thinkingText,
42
+ stats,
43
+ toolCalls,
44
+ rawFullText,
45
+ error,
46
+ cancelled,
47
+ };
33
48
  }
34
49
  export function buildFinalFromEvents(events, handlers) {
35
- const { contentText, thinkingText, stats, toolCalls, rawFullText, error } = aggregateEvents(events);
50
+ const { contentText, thinkingText, stats, toolCalls, rawFullText, error, cancelled, } = aggregateEvents(events);
36
51
  const attachedToolCalls = attachHandlersToToolCalls(toolCalls, handlers);
37
52
  const fullText = rawFullText ?? contentText;
38
53
  const cacheableAssistantContent = attachedToolCalls.length === 0
@@ -48,5 +63,5 @@ export function buildFinalFromEvents(events, handlers) {
48
63
  cacheableAssistantContent,
49
64
  }),
50
65
  };
51
- return { final, error };
66
+ return { final, error, cancelled };
52
67
  }