@qvac/sdk 0.1.1 → 0.2.0-dev.1760804157.f3c48d2

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 (43) hide show
  1. package/README.md +3 -4
  2. package/dist/client/api/completion-stream.d.ts +19 -4
  3. package/dist/client/api/completion-stream.js +19 -4
  4. package/dist/client/api/delete-cache.d.ts +29 -0
  5. package/dist/client/api/delete-cache.js +47 -0
  6. package/dist/client/api/index.d.ts +1 -0
  7. package/dist/client/api/index.js +1 -0
  8. package/dist/client/rpc/bare-client.d.ts +5 -0
  9. package/dist/examples/kv-cache-cleanup.d.ts +2 -0
  10. package/dist/examples/kv-cache-cleanup.js +88 -0
  11. package/dist/examples/kv-cache-custom-key.d.ts +2 -0
  12. package/dist/examples/kv-cache-custom-key.js +87 -0
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/schemas/common.d.ts +18 -6
  16. package/dist/schemas/common.js +3 -0
  17. package/dist/schemas/completion-stream.d.ts +5 -3
  18. package/dist/schemas/completion-stream.js +3 -2
  19. package/dist/schemas/delete-cache.d.ts +17 -0
  20. package/dist/schemas/delete-cache.js +17 -0
  21. package/dist/schemas/index.d.ts +1 -0
  22. package/dist/schemas/index.js +1 -0
  23. package/dist/schemas/llamacpp-config.d.ts +1 -1
  24. package/dist/schemas/llamacpp-config.js +1 -1
  25. package/dist/schemas/load-model.d.ts +6 -6
  26. package/dist/server/bare/addons/llamacpp/handlers/completion-stream.js +110 -54
  27. package/dist/server/bare/addons/llamacpp/kv-cache-utils.d.ts +13 -4
  28. package/dist/server/bare/addons/llamacpp/kv-cache-utils.js +70 -7
  29. package/dist/server/bare/addons/load-model.js +1 -1
  30. package/dist/server/bare/registry/model-registry.d.ts +7 -1
  31. package/dist/server/bare/registry/model-registry.js +9 -0
  32. package/dist/server/rpc/handle-request.js +11 -0
  33. package/dist/server/rpc/handlers/delete-cache.d.ts +3 -0
  34. package/dist/server/rpc/handlers/delete-cache.js +29 -0
  35. package/package.json +2 -2
  36. package/dist/models/hyperdrive/validation.d.ts +0 -6
  37. package/dist/models/hyperdrive/validation.js +0 -12
  38. package/dist/server/bare/utilities/audio/decoder.d.ts +0 -4
  39. package/dist/server/bare/utilities/audio/decoder.js +0 -38
  40. package/dist/server/bare/utilities/index.d.ts +0 -2
  41. package/dist/server/bare/utilities/index.js +0 -1
  42. package/dist/server/rpc/handlers/load-model/cache.d.ts +0 -2
  43. package/dist/server/rpc/handlers/load-model/cache.js +0 -15
@@ -14,7 +14,7 @@ export declare const llmConfigSchema: z.ZodObject<{
14
14
  lora: z.ZodOptional<z.ZodString>;
15
15
  device: z.ZodDefault<z.ZodString>;
16
16
  predict: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<-2>, z.ZodNumber]>>;
17
- system_prompt: z.ZodOptional<z.ZodString>;
17
+ system_prompt: z.ZodDefault<z.ZodString>;
18
18
  no_mmap: z.ZodOptional<z.ZodBoolean>;
19
19
  verbosity: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<0>, z.ZodLiteral<1>]>>;
20
20
  presence_penalty: z.ZodOptional<z.ZodNumber>;
@@ -25,7 +25,7 @@ export const llmConfigSchema = z.object({
25
25
  z.number().int().min(1), // positive integer: fixed token count
26
26
  ])
27
27
  .optional(),
28
- system_prompt: z.string().optional(),
28
+ system_prompt: z.string().default("You are a helpful assistant."),
29
29
  no_mmap: z.boolean().optional(),
30
30
  verbosity: verbositySchema.optional(),
31
31
  presence_penalty: z.number().optional(),
@@ -12,7 +12,7 @@ export declare const loadModelOptionsSchema: z.ZodPipe<z.ZodUnion<readonly [z.Zo
12
12
  lora: z.ZodOptional<z.ZodOptional<z.ZodString>>;
13
13
  device: z.ZodOptional<z.ZodDefault<z.ZodString>>;
14
14
  predict: z.ZodOptional<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<-2>, z.ZodNumber]>>>;
15
- system_prompt: z.ZodOptional<z.ZodOptional<z.ZodString>>;
15
+ system_prompt: z.ZodOptional<z.ZodDefault<z.ZodString>>;
16
16
  no_mmap: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
17
17
  verbosity: z.ZodOptional<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<0>, z.ZodLiteral<1>]>>>;
18
18
  presence_penalty: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
@@ -363,7 +363,7 @@ export declare const loadLlmModelRequestSchema: z.ZodObject<{
363
363
  lora: z.ZodOptional<z.ZodString>;
364
364
  device: z.ZodDefault<z.ZodString>;
365
365
  predict: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<-2>, z.ZodNumber]>>;
366
- system_prompt: z.ZodOptional<z.ZodString>;
366
+ system_prompt: z.ZodDefault<z.ZodString>;
367
367
  no_mmap: z.ZodOptional<z.ZodBoolean>;
368
368
  verbosity: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<0>, z.ZodLiteral<1>]>>;
369
369
  presence_penalty: z.ZodOptional<z.ZodNumber>;
@@ -543,7 +543,7 @@ export declare const loadModelRequestSchema: z.ZodPipe<z.ZodDiscriminatedUnion<[
543
543
  lora: z.ZodOptional<z.ZodString>;
544
544
  device: z.ZodDefault<z.ZodString>;
545
545
  predict: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<-2>, z.ZodNumber]>>;
546
- system_prompt: z.ZodOptional<z.ZodString>;
546
+ system_prompt: z.ZodDefault<z.ZodString>;
547
547
  no_mmap: z.ZodOptional<z.ZodBoolean>;
548
548
  verbosity: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<0>, z.ZodLiteral<1>]>>;
549
549
  presence_penalty: z.ZodOptional<z.ZodNumber>;
@@ -704,13 +704,13 @@ export declare const loadModelRequestSchema: z.ZodPipe<z.ZodDiscriminatedUnion<[
704
704
  ctx_size: number;
705
705
  gpu_layers: number;
706
706
  device: string;
707
+ system_prompt: string;
707
708
  temp?: number | undefined;
708
709
  top_p?: number | undefined;
709
710
  top_k?: number | undefined;
710
711
  seed?: number | undefined;
711
712
  lora?: string | undefined;
712
713
  predict?: number | undefined;
713
- system_prompt?: string | undefined;
714
714
  no_mmap?: boolean | undefined;
715
715
  verbosity?: 0 | 1 | -1 | undefined;
716
716
  presence_penalty?: number | undefined;
@@ -801,13 +801,13 @@ export declare const loadModelRequestSchema: z.ZodPipe<z.ZodDiscriminatedUnion<[
801
801
  ctx_size: number;
802
802
  gpu_layers: number;
803
803
  device: string;
804
+ system_prompt: string;
804
805
  temp?: number | undefined;
805
806
  top_p?: number | undefined;
806
807
  top_k?: number | undefined;
807
808
  seed?: number | undefined;
808
809
  lora?: string | undefined;
809
810
  predict?: number | undefined;
810
- system_prompt?: string | undefined;
811
811
  no_mmap?: boolean | undefined;
812
812
  verbosity?: 0 | 1 | -1 | undefined;
813
813
  presence_penalty?: number | undefined;
@@ -925,7 +925,7 @@ export declare const loadModelServerParamsSchema: z.ZodObject<{
925
925
  lora: z.ZodOptional<z.ZodOptional<z.ZodString>>;
926
926
  device: z.ZodOptional<z.ZodDefault<z.ZodString>>;
927
927
  predict: z.ZodOptional<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<-2>, z.ZodNumber]>>>;
928
- system_prompt: z.ZodOptional<z.ZodOptional<z.ZodString>>;
928
+ system_prompt: z.ZodOptional<z.ZodDefault<z.ZodString>>;
929
929
  no_mmap: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
930
930
  verbosity: z.ZodOptional<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<-1>, z.ZodLiteral<0>, z.ZodLiteral<1>]>>>;
931
931
  presence_penalty: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
@@ -1,65 +1,121 @@
1
1
  import { completionParamsSchema, } from "../../../../../schemas/index.js";
2
- import { getModel } from "../../../registry/model-registry.js";
3
- import { findMatchingCache, getCurrentCacheInfo, renameCacheFile, } from "../kv-cache-utils";
4
- export async function* completion(params) {
5
- const { history, modelId, kvCache } = completionParamsSchema.parse(params);
6
- const transformedHistory = [];
7
- for (const message of history) {
8
- if (message.attachments && message.attachments.length > 0) {
9
- for (const attachment of message.attachments) {
10
- transformedHistory.push({
11
- role: message.role,
12
- content: attachment.path,
13
- type: "media",
14
- });
15
- }
2
+ import { getModel, getModelConfig, } from "../../../registry/model-registry.js";
3
+ import { findMatchingCache, getCurrentCacheInfo, renameCacheFile, getCacheFilePath, extractSystemPrompt, generateConfigHash, customCacheExists, } from "../kv-cache-utils";
4
+ function transformMessage(message) {
5
+ const transformed = [];
6
+ if (message.attachments && message.attachments.length > 0) {
7
+ for (const attachment of message.attachments) {
8
+ transformed.push({
9
+ role: message.role,
10
+ content: attachment.path,
11
+ type: "media",
12
+ });
16
13
  }
17
- transformedHistory.push({
18
- role: message.role,
19
- content: message.content,
20
- });
21
14
  }
22
- const model = getModel(modelId);
23
- if (kvCache) {
24
- const cacheMessages = history.map((msg) => ({
25
- role: msg.role,
26
- content: msg.content,
27
- attachments: msg.attachments ?? undefined,
28
- }));
29
- const existingCache = await findMatchingCache(cacheMessages);
30
- const currentCacheInfo = getCurrentCacheInfo(cacheMessages);
31
- const cachePathToUse = existingCache !== null
32
- ? existingCache.cachePath
33
- : currentCacheInfo.cachePath;
34
- const messagesWithCache = [
15
+ transformed.push({
16
+ role: message.role,
17
+ content: message.content,
18
+ });
19
+ return transformed;
20
+ }
21
+ function transformMessages(messages) {
22
+ const transformed = [];
23
+ for (const message of messages) {
24
+ transformed.push(...transformMessage(message));
25
+ }
26
+ return transformed;
27
+ }
28
+ async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse) {
29
+ const primeMessages = [
30
+ { role: "session", content: cachePathToUse },
31
+ { role: "system", content: systemPromptToUse },
32
+ ];
33
+ const primeResponse = await model.run(primeMessages);
34
+ primeResponse.once("output", () => {
35
+ void primeResponse.cancel();
36
+ });
37
+ await primeResponse.await();
38
+ }
39
+ function prepareMessagesForCache(cachePathToUse, cacheExists, history) {
40
+ if (cacheExists && history.length > 0) {
41
+ const lastMessage = history[history.length - 1];
42
+ const lastTransformedMessages = transformMessage(lastMessage);
43
+ return [
35
44
  { role: "session", content: cachePathToUse },
36
- ...transformedHistory,
45
+ ...lastTransformedMessages,
37
46
  ];
38
- const response = await model.run(messagesWithCache);
39
- for await (const token of response.iterate()) {
40
- yield token;
41
- }
47
+ }
48
+ const historyWithoutSystem = history.filter((msg) => msg.role !== "system");
49
+ const transformedHistoryWithoutSystem = transformMessages(historyWithoutSystem);
50
+ return [
51
+ { role: "session", content: cachePathToUse },
52
+ ...transformedHistoryWithoutSystem,
53
+ ];
54
+ }
55
+ async function* processModelResponse(model, messagesToSend, shouldSaveCache) {
56
+ const response = await model.run(messagesToSend);
57
+ for await (const token of response.iterate()) {
58
+ yield token;
59
+ }
60
+ if (shouldSaveCache) {
42
61
  await model.run([{ role: "session", content: "save" }]);
43
- //If there was an existing cache, we rename it with new hash that includes the current message
44
- if (existingCache !== null &&
45
- existingCache.cachePath !== currentCacheInfo.cachePath) {
46
- await renameCacheFile(existingCache.cachePath, currentCacheInfo.cachePath);
62
+ }
63
+ const responseWithStats = response;
64
+ return {
65
+ timeToFirstToken: responseWithStats.stats?.TTFT ?? 0,
66
+ tokensPerSecond: responseWithStats.stats?.TPS ?? 0,
67
+ cacheTokens: responseWithStats.stats?.CacheTokens ?? 0,
68
+ };
69
+ }
70
+ export async function* completion(params) {
71
+ const { history, modelId, kvCache } = completionParamsSchema.parse(params);
72
+ const transformedHistory = transformMessages(history);
73
+ const model = getModel(modelId);
74
+ if (kvCache) {
75
+ const modelConfig = getModelConfig(modelId);
76
+ const systemPromptFromHistory = extractSystemPrompt(history);
77
+ const configHash = generateConfigHash(modelConfig, systemPromptFromHistory);
78
+ const systemPromptToUse = systemPromptFromHistory ||
79
+ modelConfig.system_prompt ||
80
+ "You are a helpful assistant.";
81
+ let cachePathToUse;
82
+ if (typeof kvCache === "string") {
83
+ cachePathToUse = await getCacheFilePath(modelId, configHash, kvCache);
84
+ const cacheExists = await customCacheExists(modelId, configHash, kvCache);
85
+ if (!cacheExists) {
86
+ await initSystemPromptCache(model, cachePathToUse, systemPromptToUse);
87
+ }
88
+ const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history);
89
+ return yield* processModelResponse(model, messagesToSend, true);
90
+ }
91
+ else {
92
+ // Auto-generate cache key based on conversation history
93
+ const cacheMessages = history.map((msg) => ({
94
+ role: msg.role,
95
+ content: msg.content,
96
+ attachments: msg.attachments ?? undefined,
97
+ }));
98
+ const existingCache = await findMatchingCache(modelId, configHash, cacheMessages);
99
+ const currentCacheInfo = await getCurrentCacheInfo(modelId, configHash, cacheMessages);
100
+ cachePathToUse =
101
+ existingCache !== null
102
+ ? existingCache.cachePath
103
+ : currentCacheInfo.cachePath;
104
+ const cacheExists = existingCache !== null;
105
+ if (!cacheExists) {
106
+ await initSystemPromptCache(model, cachePathToUse, systemPromptToUse);
107
+ }
108
+ const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history);
109
+ const result = yield* processModelResponse(model, messagesToSend, true);
110
+ //If there was an existing cache, we rename it with new hash that includes the current message
111
+ if (existingCache !== null &&
112
+ existingCache.cachePath !== currentCacheInfo.cachePath) {
113
+ await renameCacheFile(existingCache.cachePath, currentCacheInfo.cachePath);
114
+ }
115
+ return result;
47
116
  }
48
- const responseWithStats = response;
49
- return {
50
- timeToFirstToken: responseWithStats.stats?.TTFT ?? 0,
51
- tokensPerSecond: responseWithStats.stats?.TPS ?? 0,
52
- };
53
117
  }
54
118
  else {
55
- const response = await model.run(transformedHistory);
56
- for await (const token of response.iterate()) {
57
- yield token;
58
- }
59
- const responseWithStats = response;
60
- return {
61
- timeToFirstToken: responseWithStats.stats?.TTFT ?? 0,
62
- tokensPerSecond: responseWithStats.stats?.TPS ?? 0,
63
- };
119
+ return yield* processModelResponse(model, transformedHistory, false);
64
120
  }
65
121
  }
@@ -5,15 +5,24 @@ export interface CacheMessage {
5
5
  path: string;
6
6
  }[] | undefined;
7
7
  }
8
+ export declare function extractSystemPrompt(messages: CacheMessage[]): string | null;
9
+ export declare function generateConfigHash(modelConfig: unknown, systemPrompt: string | null): string;
8
10
  export declare function generateCacheKey(messages: CacheMessage[]): string;
9
- export declare function getCacheFilePath(cacheKey: string): string;
10
- export declare function findMatchingCache(currentHistory: CacheMessage[]): Promise<{
11
+ export declare function getCacheFilePath(modelId: string, configHash: string, cacheKey: string): Promise<string>;
12
+ export declare function findMatchingCache(modelId: string, configHash: string, currentHistory: CacheMessage[]): Promise<{
11
13
  cacheKey: string;
12
14
  cachePath: string;
13
15
  } | null>;
14
- export declare function getCurrentCacheInfo(currentHistory: CacheMessage[]): {
16
+ export declare function getCurrentCacheInfo(modelId: string, configHash: string, currentHistory: CacheMessage[]): Promise<{
15
17
  cacheKey: string;
16
18
  cachePath: string;
17
- };
19
+ }>;
18
20
  export declare function renameCacheFile(oldPath: string, newPath: string): Promise<void>;
21
+ export declare function customCacheExists(modelId: string, configHash: string, cacheKey: string): Promise<boolean>;
22
+ export declare function deleteCache(options: {
23
+ all: true;
24
+ } | {
25
+ kvCacheKey: string;
26
+ modelId?: string;
27
+ }): Promise<void>;
19
28
  //# sourceMappingURL=kv-cache-utils.d.ts.map
@@ -2,6 +2,18 @@ import crypto from "bare-crypto";
2
2
  import { promises as fsPromises } from "bare-fs";
3
3
  import path from "bare-path";
4
4
  import { getKVCacheDir } from "../../../utils/index.js";
5
+ export function extractSystemPrompt(messages) {
6
+ const systemMessage = messages.find((msg) => msg.role === "system");
7
+ return systemMessage ? systemMessage.content : null;
8
+ }
9
+ export function generateConfigHash(modelConfig, systemPrompt) {
10
+ const hash = crypto.createHash("sha256");
11
+ const configStr = JSON.stringify({ config: modelConfig, systemPrompt });
12
+ const configBuffer = Buffer.from(configStr, "utf8");
13
+ hash.update(configBuffer);
14
+ const hashString = hash.digest("hex");
15
+ return hashString.substring(0, 16);
16
+ }
5
17
  export function generateCacheKey(messages) {
6
18
  const hash = crypto.createHash("sha256");
7
19
  const historyString = JSON.stringify(messages);
@@ -10,18 +22,28 @@ export function generateCacheKey(messages) {
10
22
  const hashString = hash.digest("hex");
11
23
  return hashString.substring(0, 16);
12
24
  }
13
- export function getCacheFilePath(cacheKey) {
25
+ export async function getCacheFilePath(modelId, configHash, cacheKey) {
14
26
  const cacheDir = getKVCacheDir();
15
- return path.join(cacheDir, `kvcache${cacheKey}.bin`);
27
+ const sessionCacheDir = path.join(cacheDir, cacheKey);
28
+ const modelCacheDir = path.join(sessionCacheDir, modelId);
29
+ try {
30
+ await fsPromises.mkdir(sessionCacheDir, { recursive: true });
31
+ await fsPromises.mkdir(modelCacheDir, { recursive: true });
32
+ }
33
+ catch {
34
+ // Ignore if directories already exist
35
+ }
36
+ return path.join(modelCacheDir, `${configHash}.bin`);
16
37
  }
17
- export async function findMatchingCache(currentHistory) {
38
+ // Used for auto-generated cache key
39
+ export async function findMatchingCache(modelId, configHash, currentHistory) {
18
40
  if (currentHistory.length <= 1) {
19
41
  return null;
20
42
  }
21
43
  // Generate cache key for history minus the last message
22
44
  const previousHistory = currentHistory.slice(0, -1);
23
45
  const cacheKey = generateCacheKey(previousHistory);
24
- const cachePath = getCacheFilePath(cacheKey);
46
+ const cachePath = await getCacheFilePath(modelId, configHash, cacheKey);
25
47
  try {
26
48
  await fsPromises.access(cachePath);
27
49
  return { cacheKey, cachePath };
@@ -30,10 +52,9 @@ export async function findMatchingCache(currentHistory) {
30
52
  return null;
31
53
  }
32
54
  }
33
- export function getCurrentCacheInfo(currentHistory) {
34
- // Generate cache path for the current conversation state
55
+ export async function getCurrentCacheInfo(modelId, configHash, currentHistory) {
35
56
  const cacheKey = generateCacheKey(currentHistory);
36
- const cachePath = getCacheFilePath(cacheKey);
57
+ const cachePath = await getCacheFilePath(modelId, configHash, cacheKey);
37
58
  return { cacheKey, cachePath };
38
59
  }
39
60
  export async function renameCacheFile(oldPath, newPath) {
@@ -44,3 +65,45 @@ export async function renameCacheFile(oldPath, newPath) {
44
65
  console.error("Error renaming cache file:", error instanceof Error ? error.message : String(error));
45
66
  }
46
67
  }
68
+ export async function customCacheExists(modelId, configHash, cacheKey) {
69
+ const cachePath = await getCacheFilePath(modelId, configHash, cacheKey);
70
+ try {
71
+ await fsPromises.access(cachePath);
72
+ return true;
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ }
78
+ export async function deleteCache(options) {
79
+ const cacheDir = getKVCacheDir();
80
+ if ("all" in options && options.all) {
81
+ try {
82
+ await fsPromises.rm(cacheDir, { recursive: true });
83
+ await fsPromises.mkdir(cacheDir, { recursive: true });
84
+ }
85
+ catch (error) {
86
+ console.error("Error deleting all caches:", error instanceof Error ? error.message : String(error));
87
+ }
88
+ }
89
+ else if ("kvCacheKey" in options) {
90
+ const kvCacheDir = path.join(cacheDir, options.kvCacheKey);
91
+ if (options.modelId) {
92
+ const modelCacheDir = path.join(kvCacheDir, options.modelId);
93
+ try {
94
+ await fsPromises.rm(modelCacheDir, { recursive: true });
95
+ }
96
+ catch (error) {
97
+ console.error(`Error deleting model cache ${options.kvCacheKey}/${options.modelId}:`, error instanceof Error ? error.message : String(error));
98
+ }
99
+ }
100
+ else {
101
+ try {
102
+ await fsPromises.rm(kvCacheDir, { recursive: true });
103
+ }
104
+ catch (error) {
105
+ console.error(`Error deleting cache ${options.kvCacheKey}:`, error instanceof Error ? error.message : String(error));
106
+ }
107
+ }
108
+ }
109
+ }
@@ -51,5 +51,5 @@ export async function loadModel(params) {
51
51
  console.log(`${modelType}: Loading model ${modelId}...`);
52
52
  await model.load(false);
53
53
  console.log(`${modelType} model ${modelId} loaded`);
54
- registerModel(modelId, { model, path: modelPath });
54
+ registerModel(modelId, { model, path: modelPath, config: modelConfig });
55
55
  }
@@ -1,9 +1,10 @@
1
+ import type EventEmitter from "events";
1
2
  interface AddonInterface {
2
3
  cancel(jobId?: string): Promise<void>;
3
4
  }
4
5
  export interface AnyModel {
5
6
  load(...args: unknown[]): Promise<void>;
6
- run(input: unknown): Promise<{
7
+ run(input: unknown): Promise<EventEmitter & {
7
8
  onUpdate(callback: (data: string) => void): {
8
9
  await: () => Promise<void>;
9
10
  };
@@ -12,6 +13,7 @@ export interface AnyModel {
12
13
  }>) => void): {
13
14
  await: () => Promise<void>;
14
15
  };
16
+ cancel(): Promise<void>;
15
17
  iterate(): AsyncIterableIterator<string | Array<{
16
18
  text: string;
17
19
  }>>;
@@ -29,6 +31,7 @@ interface LocalOptions {
29
31
  model: AnyModel;
30
32
  path: string;
31
33
  loadedAt: Date;
34
+ config: unknown;
32
35
  }
33
36
  export interface ModelEntry {
34
37
  id: string;
@@ -39,6 +42,7 @@ export interface ModelEntry {
39
42
  export declare function registerModel(id: string, options: {
40
43
  model: AnyModel;
41
44
  path: string;
45
+ config: unknown;
42
46
  } | {
43
47
  topic: string;
44
48
  providerPublicKey: string;
@@ -53,7 +57,9 @@ export declare function getModelInfo(id: string): {
53
57
  id: string;
54
58
  path: string;
55
59
  loadedAt: Date;
60
+ config: unknown;
56
61
  } | null;
62
+ export declare function getModelConfig(id: string): unknown;
57
63
  export declare function clearRegistry(): void;
58
64
  export declare function getRegistryStats(): {
59
65
  totalModels: number;
@@ -26,6 +26,7 @@ export function registerModel(id, options) {
26
26
  model: options.model,
27
27
  path: options.path,
28
28
  loadedAt: new Date(),
29
+ config: options.config,
29
30
  },
30
31
  });
31
32
  console.log(`Local model registered: ${id} -> ${options.path}`);
@@ -69,8 +70,16 @@ export function getModelInfo(id) {
69
70
  id: entry.id,
70
71
  path: entry.local.path,
71
72
  loadedAt: entry.local.loadedAt,
73
+ config: entry.local.config,
72
74
  };
73
75
  }
76
+ export function getModelConfig(id) {
77
+ const entry = modelRegistry.get(id);
78
+ if (!entry || !entry.local) {
79
+ throw new Error(`Model with ID "${id}" not found or is delegated`);
80
+ }
81
+ return entry.local.config;
82
+ }
74
83
  export function clearRegistry() {
75
84
  modelRegistry.clear();
76
85
  console.log("Model registry cleared");
@@ -13,6 +13,7 @@ import { handleLoggingStream } from "./handlers/logging-stream.js";
13
13
  import { cancelHandler } from "./handlers/cancelHandler.js";
14
14
  import { provideHandler } from "./handlers/provideHandler.js";
15
15
  import { handleRag } from "./handlers/rag.js";
16
+ import { handleDeleteCache } from "./handlers/delete-cache.js";
16
17
  import { sendErrorResponse, sendStreamErrorResponse } from "../error-handlers";
17
18
  export async function handleRequest(req) {
18
19
  try {
@@ -209,6 +210,16 @@ export async function handleRequest(req) {
209
210
  }
210
211
  break;
211
212
  }
213
+ case "deleteCache": {
214
+ try {
215
+ const response = await handleDeleteCache(request);
216
+ req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
217
+ }
218
+ catch (error) {
219
+ sendErrorResponse(req, error);
220
+ }
221
+ break;
222
+ }
212
223
  default: {
213
224
  throw new Error(`Unknown request type`);
214
225
  }
@@ -0,0 +1,3 @@
1
+ import type { DeleteCacheRequest, DeleteCacheResponse } from "../../../schemas/index";
2
+ export declare function handleDeleteCache(request: DeleteCacheRequest): Promise<DeleteCacheResponse>;
3
+ //# sourceMappingURL=delete-cache.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { deleteCache as deleteCacheUtil } from "../../bare/addons/llamacpp/kv-cache-utils.js";
2
+ export async function handleDeleteCache(request) {
3
+ try {
4
+ if ("all" in request && request.all) {
5
+ await deleteCacheUtil({ all: true });
6
+ }
7
+ else if ("kvCacheKey" in request) {
8
+ const params = {
9
+ kvCacheKey: request.kvCacheKey,
10
+ };
11
+ if (request.modelId !== undefined) {
12
+ params.modelId = request.modelId;
13
+ }
14
+ await deleteCacheUtil(params);
15
+ }
16
+ return {
17
+ type: "deleteCache",
18
+ success: true,
19
+ };
20
+ }
21
+ catch (error) {
22
+ console.error("Error deleting cache:", error);
23
+ return {
24
+ type: "deleteCache",
25
+ success: false,
26
+ error: error instanceof Error ? error.message : "Unknown error",
27
+ };
28
+ }
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.2.0-dev.1760804157.f3c48d2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -60,7 +60,7 @@
60
60
  "@qvac/langdetect-text": "^0.1.0",
61
61
  "@qvac/logging": "^0.1.0",
62
62
  "@qvac/rag": "^0.1.0",
63
- "@qvac/transcription-whispercpp": "^0.1.4",
63
+ "@qvac/transcription-whispercpp": "^0.1.0",
64
64
  "@qvac/translation-nmtcpp": "^0.1.0",
65
65
  "fast-safe-stringify": "2.1.1",
66
66
  "zod": "^4.0.17"
@@ -1,6 +0,0 @@
1
- export declare function parseHyperdriveUrl(url: string): {
2
- key: string;
3
- path: string;
4
- };
5
- export declare function isValidHyperdriveKey(key: string): boolean;
6
- //# sourceMappingURL=validation.d.ts.map
@@ -1,12 +0,0 @@
1
- // Parse hyperdrive URLs: pear://key/path/to/model.gguf
2
- export function parseHyperdriveUrl(url) {
3
- const match = url.match(/^pear:\/\/([0-9a-fA-F]{64})\/(.+)$/);
4
- if (!match || !match[1] || !match[2]) {
5
- throw new Error(`Invalid hyperdrive URL: "${url}". Expected format: pear://64-char-hex-key/path/to/model.gguf`);
6
- }
7
- return { key: match[1], path: match[2] };
8
- }
9
- // Hyperdrive key validation (32 bytes = 64 hex chars)
10
- export function isValidHyperdriveKey(key) {
11
- return /^[0-9a-fA-F]{64}$/.test(key);
12
- }
@@ -1,4 +0,0 @@
1
- import { Readable } from "bare-stream";
2
- export declare function needsDecoding(filePath: string): boolean;
3
- export declare function decodeAudioToStream(inputPath: string): Promise<Readable>;
4
- //# sourceMappingURL=decoder.d.ts.map
@@ -1,38 +0,0 @@
1
- import fs from "bare-fs";
2
- import path from "bare-path";
3
- import GSTDecoder from "@qvac/decoder-audio";
4
- import { Readable } from "bare-stream";
5
- import { FORMATS_NEEDING_DECODE } from "../../../../constants/audio.js";
6
- export function needsDecoding(filePath) {
7
- const ext = path.extname(filePath).toLowerCase();
8
- return FORMATS_NEEDING_DECODE.includes(ext);
9
- }
10
- export async function decodeAudioToStream(inputPath) {
11
- const decoder = new GSTDecoder({
12
- config: {
13
- audioFormat: "encoded",
14
- },
15
- });
16
- try {
17
- await decoder.load();
18
- const audioStream = fs.createReadStream(inputPath);
19
- const response = await decoder.run(audioStream);
20
- const decodedBuffers = [];
21
- await response
22
- .onUpdate((output) => {
23
- const bytes = new Uint8Array(output.outputArray);
24
- decodedBuffers.push(bytes);
25
- })
26
- .onFinish(() => {
27
- console.log("Audio decoded to buffer");
28
- })
29
- .await();
30
- // Create a stream from the decoded buffers
31
- const combinedBuffer = Buffer.concat(decodedBuffers);
32
- return Readable.from([combinedBuffer]);
33
- }
34
- catch (error) {
35
- console.error("Decoding failed:", error instanceof Error ? error.message : String(error));
36
- throw error;
37
- }
38
- }
@@ -1,2 +0,0 @@
1
- export * from "./audio/decoder";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- export * from "./audio/decoder.js";
@@ -1,2 +0,0 @@
1
- export declare function getCacheDir(): string;
2
- //# sourceMappingURL=cache.d.ts.map
@@ -1,15 +0,0 @@
1
- import fs from "bare-fs";
2
- import path from "bare-path";
3
- import { getEnv } from "../../../worker.js";
4
- export function getCacheDir() {
5
- const homeDir = getEnv().HOME_DIR;
6
- const cacheDir = path.join(homeDir, ".qvac", "models");
7
- // Ensure cache directory exists
8
- try {
9
- fs.mkdirSync(cacheDir, { recursive: true });
10
- }
11
- catch (error) {
12
- console.error("Error creating cache directory:", error instanceof Error ? error.message : String(error));
13
- }
14
- return cacheDir;
15
- }