veryfront 0.1.13 → 0.1.14

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 (135) hide show
  1. package/esm/cli/app/data/slug-words.d.ts.map +1 -1
  2. package/esm/cli/app/data/slug-words.js +225 -90
  3. package/esm/cli/app/operations/project-creation.js +4 -3
  4. package/esm/cli/app/shell.js +1 -1
  5. package/esm/cli/app/utils.d.ts +5 -4
  6. package/esm/cli/app/utils.d.ts.map +1 -1
  7. package/esm/cli/app/utils.js +0 -23
  8. package/esm/cli/app/views/dashboard.d.ts +1 -1
  9. package/esm/cli/app/views/dashboard.d.ts.map +1 -1
  10. package/esm/cli/app/views/dashboard.js +22 -4
  11. package/esm/cli/auth/callback-server.d.ts.map +1 -1
  12. package/esm/cli/auth/callback-server.js +3 -2
  13. package/esm/cli/commands/dev/handler.d.ts.map +1 -1
  14. package/esm/cli/commands/dev/handler.js +2 -0
  15. package/esm/cli/commands/init/init-command.d.ts.map +1 -1
  16. package/esm/cli/commands/init/init-command.js +20 -3
  17. package/esm/cli/commands/init/interactive-wizard.d.ts +3 -2
  18. package/esm/cli/commands/init/interactive-wizard.d.ts.map +1 -1
  19. package/esm/cli/commands/init/interactive-wizard.js +55 -27
  20. package/esm/cli/mcp/remote-file-tools.d.ts +0 -6
  21. package/esm/cli/mcp/remote-file-tools.d.ts.map +1 -1
  22. package/esm/cli/mcp/remote-file-tools.js +37 -15
  23. package/esm/cli/shared/reserve-slug.d.ts.map +1 -1
  24. package/esm/cli/shared/reserve-slug.js +8 -3
  25. package/esm/cli/utils/env-prompt.d.ts.map +1 -1
  26. package/esm/cli/utils/env-prompt.js +3 -0
  27. package/esm/deno.d.ts +2 -1
  28. package/esm/deno.js +8 -4
  29. package/esm/src/agent/chat-handler.d.ts +4 -3
  30. package/esm/src/agent/chat-handler.d.ts.map +1 -1
  31. package/esm/src/agent/chat-handler.js +55 -4
  32. package/esm/src/agent/react/index.d.ts +1 -1
  33. package/esm/src/agent/react/index.d.ts.map +1 -1
  34. package/esm/src/agent/react/use-chat/browser-inference/browser-engine.d.ts +18 -0
  35. package/esm/src/agent/react/use-chat/browser-inference/browser-engine.d.ts.map +1 -0
  36. package/esm/src/agent/react/use-chat/browser-inference/browser-engine.js +54 -0
  37. package/esm/src/agent/react/use-chat/browser-inference/types.d.ts +43 -0
  38. package/esm/src/agent/react/use-chat/browser-inference/types.d.ts.map +1 -0
  39. package/esm/src/agent/react/use-chat/browser-inference/types.js +4 -0
  40. package/esm/src/agent/react/use-chat/browser-inference/worker-client.d.ts +23 -0
  41. package/esm/src/agent/react/use-chat/browser-inference/worker-client.d.ts.map +1 -0
  42. package/esm/src/agent/react/use-chat/browser-inference/worker-client.js +67 -0
  43. package/esm/src/agent/react/use-chat/browser-inference/worker-script.d.ts +8 -0
  44. package/esm/src/agent/react/use-chat/browser-inference/worker-script.d.ts.map +1 -0
  45. package/esm/src/agent/react/use-chat/browser-inference/worker-script.js +97 -0
  46. package/esm/src/agent/react/use-chat/index.d.ts +1 -1
  47. package/esm/src/agent/react/use-chat/index.d.ts.map +1 -1
  48. package/esm/src/agent/react/use-chat/types.d.ts +12 -0
  49. package/esm/src/agent/react/use-chat/types.d.ts.map +1 -1
  50. package/esm/src/agent/react/use-chat/use-chat.d.ts.map +1 -1
  51. package/esm/src/agent/react/use-chat/use-chat.js +120 -6
  52. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  53. package/esm/src/agent/runtime/index.js +59 -7
  54. package/esm/src/build/production-build/templates.d.ts +2 -2
  55. package/esm/src/build/production-build/templates.d.ts.map +1 -1
  56. package/esm/src/build/production-build/templates.js +2 -68
  57. package/esm/src/chat/index.d.ts +1 -1
  58. package/esm/src/chat/index.d.ts.map +1 -1
  59. package/esm/src/errors/veryfront-error.d.ts +3 -0
  60. package/esm/src/errors/veryfront-error.d.ts.map +1 -1
  61. package/esm/src/platform/adapters/runtime/deno/adapter.d.ts.map +1 -1
  62. package/esm/src/platform/adapters/runtime/deno/adapter.js +5 -1
  63. package/esm/src/platform/compat/http/deno-server.d.ts.map +1 -1
  64. package/esm/src/platform/compat/http/deno-server.js +3 -2
  65. package/esm/src/provider/index.d.ts +1 -1
  66. package/esm/src/provider/index.d.ts.map +1 -1
  67. package/esm/src/provider/index.js +1 -1
  68. package/esm/src/provider/local/ai-sdk-adapter.d.ts +19 -0
  69. package/esm/src/provider/local/ai-sdk-adapter.d.ts.map +1 -0
  70. package/esm/src/provider/local/ai-sdk-adapter.js +164 -0
  71. package/esm/src/provider/local/env.d.ts +10 -0
  72. package/esm/src/provider/local/env.d.ts.map +1 -0
  73. package/esm/src/provider/local/env.js +23 -0
  74. package/esm/src/provider/local/local-engine.d.ts +61 -0
  75. package/esm/src/provider/local/local-engine.d.ts.map +1 -0
  76. package/esm/src/provider/local/local-engine.js +211 -0
  77. package/esm/src/provider/local/model-catalog.d.ts +30 -0
  78. package/esm/src/provider/local/model-catalog.d.ts.map +1 -0
  79. package/esm/src/provider/local/model-catalog.js +58 -0
  80. package/esm/src/provider/model-registry.d.ts +14 -0
  81. package/esm/src/provider/model-registry.d.ts.map +1 -1
  82. package/esm/src/provider/model-registry.js +58 -2
  83. package/esm/src/proxy/main.js +34 -6
  84. package/esm/src/proxy/server-resolver.d.ts +23 -0
  85. package/esm/src/proxy/server-resolver.d.ts.map +1 -0
  86. package/esm/src/proxy/server-resolver.js +124 -0
  87. package/esm/src/react/components/ai/chat/components/inference-badge.d.ts +8 -0
  88. package/esm/src/react/components/ai/chat/components/inference-badge.d.ts.map +1 -0
  89. package/esm/src/react/components/ai/chat/components/inference-badge.js +36 -0
  90. package/esm/src/react/components/ai/chat/components/upgrade-cta.d.ts +7 -0
  91. package/esm/src/react/components/ai/chat/components/upgrade-cta.d.ts.map +1 -0
  92. package/esm/src/react/components/ai/chat/components/upgrade-cta.js +33 -0
  93. package/esm/src/react/components/ai/chat/index.d.ts +7 -1
  94. package/esm/src/react/components/ai/chat/index.d.ts.map +1 -1
  95. package/esm/src/react/components/ai/chat/index.js +16 -4
  96. package/package.json +5 -1
  97. package/src/cli/app/data/slug-words.ts +225 -90
  98. package/src/cli/app/operations/project-creation.ts +3 -3
  99. package/src/cli/app/shell.ts +1 -1
  100. package/src/cli/app/utils.ts +0 -30
  101. package/src/cli/app/views/dashboard.ts +27 -4
  102. package/src/cli/auth/callback-server.ts +3 -2
  103. package/src/cli/commands/dev/handler.ts +2 -0
  104. package/src/cli/commands/init/init-command.ts +30 -3
  105. package/src/cli/commands/init/interactive-wizard.ts +62 -34
  106. package/src/cli/mcp/remote-file-tools.ts +50 -15
  107. package/src/cli/shared/reserve-slug.ts +9 -2
  108. package/src/cli/utils/env-prompt.ts +3 -0
  109. package/src/deno.js +8 -4
  110. package/src/src/agent/chat-handler.ts +57 -4
  111. package/src/src/agent/react/index.ts +2 -0
  112. package/src/src/agent/react/use-chat/browser-inference/browser-engine.ts +81 -0
  113. package/src/src/agent/react/use-chat/browser-inference/types.ts +52 -0
  114. package/src/src/agent/react/use-chat/browser-inference/worker-client.ts +89 -0
  115. package/src/src/agent/react/use-chat/browser-inference/worker-script.ts +98 -0
  116. package/src/src/agent/react/use-chat/index.ts +2 -0
  117. package/src/src/agent/react/use-chat/types.ts +20 -0
  118. package/src/src/agent/react/use-chat/use-chat.ts +148 -8
  119. package/src/src/agent/runtime/index.ts +72 -6
  120. package/src/src/build/production-build/templates.ts +2 -68
  121. package/src/src/chat/index.ts +2 -0
  122. package/src/src/errors/veryfront-error.ts +2 -1
  123. package/src/src/platform/adapters/runtime/deno/adapter.ts +5 -1
  124. package/src/src/platform/compat/http/deno-server.ts +3 -1
  125. package/src/src/provider/index.ts +1 -0
  126. package/src/src/provider/local/ai-sdk-adapter.ts +207 -0
  127. package/src/src/provider/local/env.ts +26 -0
  128. package/src/src/provider/local/local-engine.ts +288 -0
  129. package/src/src/provider/local/model-catalog.ts +73 -0
  130. package/src/src/provider/model-registry.ts +66 -2
  131. package/src/src/proxy/main.ts +41 -6
  132. package/src/src/proxy/server-resolver.ts +151 -0
  133. package/src/src/react/components/ai/chat/components/inference-badge.tsx +48 -0
  134. package/src/src/react/components/ai/chat/components/upgrade-cta.tsx +56 -0
  135. package/src/src/react/components/ai/chat/index.tsx +43 -6
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Worker ↔ main thread message protocol for browser-side inference.
3
+ */
4
+ export interface WorkerGenerateRequest {
5
+ type: "generate";
6
+ id: string;
7
+ messages: Array<{
8
+ role: string;
9
+ content: string;
10
+ }>;
11
+ options?: {
12
+ maxNewTokens?: number;
13
+ temperature?: number;
14
+ systemPrompt?: string;
15
+ };
16
+ }
17
+ export type WorkerRequest = WorkerGenerateRequest;
18
+ export interface WorkerStatusResponse {
19
+ type: "status";
20
+ status: "loading-runtime" | "downloading-model" | "ready" | "generating";
21
+ }
22
+ export interface WorkerDownloadProgressResponse {
23
+ type: "download-progress";
24
+ progress: number;
25
+ file?: string;
26
+ }
27
+ export interface WorkerTokenResponse {
28
+ type: "token";
29
+ id: string;
30
+ token: string;
31
+ }
32
+ export interface WorkerDoneResponse {
33
+ type: "done";
34
+ id: string;
35
+ text: string;
36
+ }
37
+ export interface WorkerErrorResponse {
38
+ type: "error";
39
+ id: string;
40
+ error: string;
41
+ }
42
+ export type WorkerResponse = WorkerStatusResponse | WorkerDownloadProgressResponse | WorkerTokenResponse | WorkerDoneResponse | WorkerErrorResponse;
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../src/src/agent/react/use-chat/browser-inference/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAElD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,OAAO,GAAG,YAAY,CAAC;CAC1E;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,cAAc,GACtB,oBAAoB,GACpB,8BAA8B,GAC9B,mBAAmB,GACnB,kBAAkB,GAClB,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Worker ↔ main thread message protocol for browser-side inference.
3
+ */
4
+ export {};
@@ -0,0 +1,23 @@
1
+ export interface GenerateCallbacks {
2
+ onStatus?: (status: "loading-runtime" | "downloading-model" | "ready" | "generating") => void;
3
+ onDownloadProgress?: (progress: number, file?: string) => void;
4
+ onToken?: (token: string) => void;
5
+ onDone?: (text: string) => void;
6
+ onError?: (error: string) => void;
7
+ }
8
+ export declare class BrowserInferenceClient {
9
+ private worker;
10
+ private blobUrl;
11
+ static getInstance(): BrowserInferenceClient;
12
+ private ensureWorker;
13
+ generate(id: string, messages: Array<{
14
+ role: string;
15
+ content: string;
16
+ }>, options: {
17
+ maxNewTokens?: number;
18
+ temperature?: number;
19
+ systemPrompt?: string;
20
+ }, callbacks: GenerateCallbacks): void;
21
+ stop(): void;
22
+ }
23
+ //# sourceMappingURL=worker-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-client.d.ts","sourceRoot":"","sources":["../../../../../../src/src/agent/react/use-chat/browser-inference/worker-client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,OAAO,GAAG,YAAY,KAAK,IAAI,CAAC;IAC9F,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAID,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAuB;IAEtC,MAAM,CAAC,WAAW,IAAI,sBAAsB;IAK5C,OAAO,CAAC,YAAY;IAUpB,QAAQ,CACN,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,OAAO,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,EAC/E,SAAS,EAAE,iBAAiB,GAC3B,IAAI;IAgCP,IAAI,IAAI,IAAI;CAUb"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * BrowserInferenceClient — manages Web Worker lifecycle for browser-side inference.
3
+ *
4
+ * Singleton per session. Lazily creates Worker on first generate() call.
5
+ * Uses inline Blob URL approach — no separate build entry point needed.
6
+ */
7
+ import * as dntShim from "../../../../../_dnt.shims.js";
8
+ import { WORKER_SCRIPT } from "./worker-script.js";
9
+ let instance = null;
10
+ export class BrowserInferenceClient {
11
+ worker = null;
12
+ blobUrl = null;
13
+ static getInstance() {
14
+ if (!instance)
15
+ instance = new BrowserInferenceClient();
16
+ return instance;
17
+ }
18
+ ensureWorker() {
19
+ if (this.worker)
20
+ return this.worker;
21
+ const blob = new dntShim.Blob([WORKER_SCRIPT], { type: "application/javascript" });
22
+ this.blobUrl = URL.createObjectURL(blob);
23
+ this.worker = new Worker(this.blobUrl, { type: "module" });
24
+ return this.worker;
25
+ }
26
+ generate(id, messages, options, callbacks) {
27
+ const worker = this.ensureWorker();
28
+ worker.onmessage = (event) => {
29
+ const msg = event.data;
30
+ switch (msg.type) {
31
+ case "status":
32
+ callbacks.onStatus?.(msg.status);
33
+ break;
34
+ case "download-progress":
35
+ callbacks.onDownloadProgress?.(msg.progress, msg.file);
36
+ break;
37
+ case "token":
38
+ if (msg.id === id)
39
+ callbacks.onToken?.(msg.token);
40
+ break;
41
+ case "done":
42
+ if (msg.id === id)
43
+ callbacks.onDone?.(msg.text);
44
+ break;
45
+ case "error":
46
+ if (msg.id === id)
47
+ callbacks.onError?.(msg.error);
48
+ break;
49
+ }
50
+ };
51
+ worker.onerror = (event) => {
52
+ callbacks.onError?.(event.message || "Worker error");
53
+ };
54
+ const request = { type: "generate", id, messages, options };
55
+ worker.postMessage(request);
56
+ }
57
+ stop() {
58
+ if (this.worker) {
59
+ this.worker.terminate();
60
+ this.worker = null;
61
+ }
62
+ if (this.blobUrl) {
63
+ URL.revokeObjectURL(this.blobUrl);
64
+ this.blobUrl = null;
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Inline Worker script as a string.
3
+ *
4
+ * Loaded via Blob URL — no separate build entry point needed.
5
+ * Dynamically imports @huggingface/transformers from CDN inside the Worker.
6
+ */
7
+ export declare const WORKER_SCRIPT = "\nlet pipeline = null;\nlet generating = false;\n\nasync function loadPipeline(callbacks) {\n if (pipeline) return pipeline;\n\n callbacks.onStatus(\"loading-runtime\");\n\n const { pipeline: createPipeline, env } =\n await import(\"https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.4.2\");\n\n env.useBrowserCache = true;\n env.allowLocalModels = false;\n\n callbacks.onStatus(\"downloading-model\");\n\n pipeline = await createPipeline(\n \"text-generation\",\n \"HuggingFaceTB/SmolLM2-135M-Instruct\",\n {\n dtype: \"q4\",\n device: \"wasm\",\n progress_callback: (progress) => {\n if (progress.status === \"progress\" && progress.total) {\n callbacks.onProgress(Math.round((progress.loaded / progress.total) * 100), progress.file);\n }\n },\n },\n );\n\n callbacks.onStatus(\"ready\");\n return pipeline;\n}\n\nself.onmessage = async (event) => {\n const request = event.data;\n if (request.type !== \"generate\") return;\n\n const { id, messages, options } = request;\n\n try {\n const pipe = await loadPipeline({\n onStatus: (status) => self.postMessage({ type: \"status\", status }),\n onProgress: (progress, file) => self.postMessage({ type: \"download-progress\", progress, file }),\n });\n\n self.postMessage({ type: \"status\", status: \"generating\" });\n generating = true;\n\n const chatMessages = [];\n if (options?.systemPrompt) {\n chatMessages.push({ role: \"system\", content: options.systemPrompt });\n }\n chatMessages.push(...messages);\n\n // Helper: generated_text is a plain string for raw prompts but an array\n // of {role, content} message objects when using chat format. Extract the\n // last assistant message's content in either case.\n function extractText(generated) {\n if (typeof generated === \"string\") return generated;\n if (Array.isArray(generated)) {\n const last = generated[generated.length - 1];\n return last?.content ?? \"\";\n }\n return \"\";\n }\n\n const result = await pipe(chatMessages, {\n max_new_tokens: options?.maxNewTokens ?? 512,\n temperature: options?.temperature ?? 0.7,\n do_sample: true,\n return_full_text: false,\n callback_function: (output) => {\n if (!generating) return;\n const text = extractText(output?.[0]?.generated_text);\n if (text) {\n self.postMessage({ type: \"token\", id, token: text });\n }\n },\n });\n\n generating = false;\n const finalText = extractText(result?.[0]?.generated_text);\n self.postMessage({ type: \"done\", id, text: finalText });\n } catch (error) {\n generating = false;\n self.postMessage({ type: \"error\", id, error: error?.message ?? String(error) });\n }\n};\n";
8
+ //# sourceMappingURL=worker-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-script.d.ts","sourceRoot":"","sources":["../../../../../../src/src/agent/react/use-chat/browser-inference/worker-script.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,aAAa,+wFA0FzB,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Inline Worker script as a string.
3
+ *
4
+ * Loaded via Blob URL — no separate build entry point needed.
5
+ * Dynamically imports @huggingface/transformers from CDN inside the Worker.
6
+ */
7
+ export const WORKER_SCRIPT = /* js */ `
8
+ let pipeline = null;
9
+ let generating = false;
10
+
11
+ async function loadPipeline(callbacks) {
12
+ if (pipeline) return pipeline;
13
+
14
+ callbacks.onStatus("loading-runtime");
15
+
16
+ const { pipeline: createPipeline, env } =
17
+ await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.4.2");
18
+
19
+ env.useBrowserCache = true;
20
+ env.allowLocalModels = false;
21
+
22
+ callbacks.onStatus("downloading-model");
23
+
24
+ pipeline = await createPipeline(
25
+ "text-generation",
26
+ "HuggingFaceTB/SmolLM2-135M-Instruct",
27
+ {
28
+ dtype: "q4",
29
+ device: "wasm",
30
+ progress_callback: (progress) => {
31
+ if (progress.status === "progress" && progress.total) {
32
+ callbacks.onProgress(Math.round((progress.loaded / progress.total) * 100), progress.file);
33
+ }
34
+ },
35
+ },
36
+ );
37
+
38
+ callbacks.onStatus("ready");
39
+ return pipeline;
40
+ }
41
+
42
+ self.onmessage = async (event) => {
43
+ const request = event.data;
44
+ if (request.type !== "generate") return;
45
+
46
+ const { id, messages, options } = request;
47
+
48
+ try {
49
+ const pipe = await loadPipeline({
50
+ onStatus: (status) => self.postMessage({ type: "status", status }),
51
+ onProgress: (progress, file) => self.postMessage({ type: "download-progress", progress, file }),
52
+ });
53
+
54
+ self.postMessage({ type: "status", status: "generating" });
55
+ generating = true;
56
+
57
+ const chatMessages = [];
58
+ if (options?.systemPrompt) {
59
+ chatMessages.push({ role: "system", content: options.systemPrompt });
60
+ }
61
+ chatMessages.push(...messages);
62
+
63
+ // Helper: generated_text is a plain string for raw prompts but an array
64
+ // of {role, content} message objects when using chat format. Extract the
65
+ // last assistant message's content in either case.
66
+ function extractText(generated) {
67
+ if (typeof generated === "string") return generated;
68
+ if (Array.isArray(generated)) {
69
+ const last = generated[generated.length - 1];
70
+ return last?.content ?? "";
71
+ }
72
+ return "";
73
+ }
74
+
75
+ const result = await pipe(chatMessages, {
76
+ max_new_tokens: options?.maxNewTokens ?? 512,
77
+ temperature: options?.temperature ?? 0.7,
78
+ do_sample: true,
79
+ return_full_text: false,
80
+ callback_function: (output) => {
81
+ if (!generating) return;
82
+ const text = extractText(output?.[0]?.generated_text);
83
+ if (text) {
84
+ self.postMessage({ type: "token", id, token: text });
85
+ }
86
+ },
87
+ });
88
+
89
+ generating = false;
90
+ const finalText = extractText(result?.[0]?.generated_text);
91
+ self.postMessage({ type: "done", id, text: finalText });
92
+ } catch (error) {
93
+ generating = false;
94
+ self.postMessage({ type: "error", id, error: error?.message ?? String(error) });
95
+ }
96
+ };
97
+ `;
@@ -5,5 +5,5 @@
5
5
  * Build any interface you want.
6
6
  */
7
7
  export { useChat } from "./use-chat.js";
8
- export type { DynamicToolUIPart, OnToolCallArg, ReasoningUIPart, TextUIPart, ToolOutput, ToolResultUIPart, ToolState, ToolUIPart, UIMessage, UIMessagePart, UseChatOptions, UseChatResult, } from "./types.js";
8
+ export type { BrowserInferenceStatus, DynamicToolUIPart, InferenceMode, OnToolCallArg, ReasoningUIPart, TextUIPart, ToolOutput, ToolResultUIPart, ToolState, ToolUIPart, UIMessage, UIMessagePart, UseChatOptions, UseChatResult, } from "./types.js";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC"}
@@ -1,5 +1,9 @@
1
1
  import * as dntShim from "../../../../_dnt.shims.js";
2
2
  export type StreamState = "streaming" | "done";
3
+ /** Where inference is happening */
4
+ export type InferenceMode = "cloud" | "server-local" | "browser";
5
+ /** Browser-side model loading and inference status */
6
+ export type BrowserInferenceStatus = "idle" | "loading-runtime" | "downloading-model" | "ready" | "generating" | "error";
3
7
  export interface TextUIPart {
4
8
  type: "text";
5
9
  text: string;
@@ -68,6 +72,10 @@ export interface UseChatOptions {
68
72
  credentials?: RequestCredentials;
69
73
  /** Override model at runtime (e.g. "openai/gpt-4o", "anthropic/claude-sonnet-4-5-20250929") */
70
74
  model?: string;
75
+ /** System prompt for browser-side inference (server uses agent config) */
76
+ systemPrompt?: string;
77
+ /** Enable/disable browser fallback when server can't provide AI. Default: true */
78
+ browserFallback?: boolean;
71
79
  onResponse?: (response: dntShim.Response) => void;
72
80
  onFinish?: (message: UIMessage) => void;
73
81
  onError?: (error: Error) => void;
@@ -80,6 +88,10 @@ export interface UseChatResult {
80
88
  error: Error | null;
81
89
  /** Current model override (undefined = use agent default) */
82
90
  model: string | undefined;
91
+ /** Where inference is currently happening */
92
+ inferenceMode: InferenceMode;
93
+ /** Browser-side model loading/inference status (null when not using browser fallback) */
94
+ browserStatus: BrowserInferenceStatus | null;
83
95
  setInput: (input: string) => void;
84
96
  /** Change the model for subsequent requests */
85
97
  setModel: (model: string | undefined) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/use-chat.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAyB,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGvF;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CAgN9D"}
1
+ {"version":3,"file":"use-chat.d.ts","sourceRoot":"","sources":["../../../../../src/src/agent/react/use-chat/use-chat.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAMV,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CA+U9D"}
@@ -4,6 +4,11 @@
4
4
  * Complete chat state management with zero UI.
5
5
  * Consumes the veryfront streaming protocol
6
6
  * (message-start/message-finish + step-start/step-end).
7
+ *
8
+ * Supports three inference modes:
9
+ * - cloud: API key present, normal server-side inference
10
+ * - server-local: No API key, server runs local model via ONNX
11
+ * - browser: Server can't run ONNX (compiled binary), falls back to browser Worker
7
12
  */
8
13
  import * as dntShim from "../../../../_dnt.shims.js";
9
14
  import { useCallback, useRef, useState } from "react";
@@ -20,7 +25,13 @@ export function useChat(options) {
20
25
  const [error, setError] = useState(null);
21
26
  const [data, setData] = useState(null);
22
27
  const [model, setModel] = useState(options.model);
28
+ const [inferenceMode, setInferenceMode] = useState("cloud");
29
+ const [browserStatus, setBrowserStatus] = useState(null);
23
30
  const abortControllerRef = useRef(null);
31
+ const browserInferenceActiveRef = useRef(false);
32
+ const browserInferenceRejectRef = useRef(null);
33
+ // System prompt for browser fallback (from 503 response or options)
34
+ const systemPromptRef = useRef(options.systemPrompt ?? "You are a helpful AI assistant.");
24
35
  // Track pending tool outputs for addToolOutput
25
36
  const pendingToolOutputsRef = useRef(new Map());
26
37
  /**
@@ -45,6 +56,57 @@ export function useChat(options) {
45
56
  }),
46
57
  })));
47
58
  }, []);
59
+ /**
60
+ * Run inference in the browser via Web Worker.
61
+ * Lazily imports the browser-inference module to avoid bundling it
62
+ * when server-side inference works fine.
63
+ */
64
+ const doBrowserInference = useCallback(async (allMessages) => {
65
+ browserInferenceActiveRef.current = true;
66
+ try {
67
+ const { runBrowserInference } = await import("./browser-inference/browser-engine.js");
68
+ await new Promise((resolve, reject) => {
69
+ browserInferenceRejectRef.current = reject;
70
+ let hasAddedMessage = false;
71
+ runBrowserInference(allMessages, systemPromptRef.current, {
72
+ onUpdate: (parts, messageId) => {
73
+ if (!hasAddedMessage) {
74
+ hasAddedMessage = true;
75
+ setMessages((prev) => [
76
+ ...prev,
77
+ { id: messageId, role: "assistant", parts },
78
+ ]);
79
+ return;
80
+ }
81
+ setMessages((prev) => prev.map((m) => (m.id === messageId ? { ...m, parts } : m)));
82
+ },
83
+ onMessage: (assistantMessage) => {
84
+ setMessages((prev) => {
85
+ if (!hasAddedMessage)
86
+ return [...prev, assistantMessage];
87
+ return prev.map((m) => m.id === assistantMessage.id ? assistantMessage : m);
88
+ });
89
+ options.onFinish?.(assistantMessage);
90
+ browserInferenceRejectRef.current = null;
91
+ resolve();
92
+ },
93
+ onStatusChange: (status) => {
94
+ setBrowserStatus(status);
95
+ },
96
+ onDownloadProgress: () => {
97
+ // Progress is tracked via onStatusChange("downloading-model")
98
+ },
99
+ onError: (err) => {
100
+ browserInferenceRejectRef.current = null;
101
+ reject(err);
102
+ },
103
+ });
104
+ });
105
+ }
106
+ finally {
107
+ browserInferenceActiveRef.current = false;
108
+ }
109
+ }, [options]);
48
110
  /**
49
111
  * Send a message and stream assistant updates.
50
112
  */
@@ -57,9 +119,15 @@ export function useChat(options) {
57
119
  setMessages((prev) => [...prev, userMessage]);
58
120
  setIsLoading(true);
59
121
  setError(null);
60
- const abortController = new AbortController();
61
- abortControllerRef.current = abortController;
62
122
  try {
123
+ const allMessages = [...messages, userMessage];
124
+ // If already in browser mode, skip fetch entirely
125
+ if (inferenceMode === "browser") {
126
+ await doBrowserInference(allMessages);
127
+ return;
128
+ }
129
+ const abortController = new AbortController();
130
+ abortControllerRef.current = abortController;
63
131
  const response = await dntShim.fetch(options.api, {
64
132
  method: "POST",
65
133
  headers: {
@@ -68,12 +136,30 @@ export function useChat(options) {
68
136
  },
69
137
  credentials: options.credentials,
70
138
  body: JSON.stringify({
71
- messages: [...messages, userMessage],
139
+ messages: allMessages,
72
140
  ...(model ? { model } : {}),
73
141
  ...options.body,
74
142
  }),
75
143
  signal: abortController.signal,
76
144
  });
145
+ // Handle 503 — server can't provide AI, fall back to browser
146
+ if (response.status === 503 && (options.browserFallback ?? true)) {
147
+ try {
148
+ const body = await response.json();
149
+ if (body.code === "NO_AI_AVAILABLE") {
150
+ if (body.systemPrompt) {
151
+ systemPromptRef.current = body.systemPrompt;
152
+ }
153
+ setInferenceMode("browser");
154
+ setBrowserStatus("idle");
155
+ await doBrowserInference(allMessages);
156
+ return;
157
+ }
158
+ }
159
+ catch {
160
+ // If parsing fails, fall through to normal error handling
161
+ }
162
+ }
77
163
  if (!response.ok) {
78
164
  throw toError(createError({
79
165
  type: "agent",
@@ -95,7 +181,18 @@ export function useChat(options) {
95
181
  });
96
182
  options.onFinish?.(assistantMessage);
97
183
  },
98
- onData: setData,
184
+ onData: (eventData) => {
185
+ setData(eventData);
186
+ // Detect inference mode from server metadata
187
+ if (eventData &&
188
+ typeof eventData === "object" &&
189
+ "inferenceMode" in eventData) {
190
+ const mode = eventData.inferenceMode;
191
+ if (mode === "server-local" || mode === "cloud") {
192
+ setInferenceMode(mode);
193
+ }
194
+ }
195
+ },
99
196
  onUpdate: (parts, messageId) => {
100
197
  const id = messageId ?? streamingMessageId;
101
198
  if (messageId && messageId !== currentMessageId) {
@@ -127,7 +224,7 @@ export function useChat(options) {
127
224
  setIsLoading(false);
128
225
  abortControllerRef.current = null;
129
226
  }
130
- }, [messages, model, options]);
227
+ }, [messages, model, options, inferenceMode, doBrowserInference]);
131
228
  /**
132
229
  * Reload last message
133
230
  */
@@ -147,9 +244,24 @@ export function useChat(options) {
147
244
  /**
148
245
  * Stop generation
149
246
  */
150
- const stop = useCallback(() => {
247
+ const stop = useCallback(async () => {
151
248
  abortControllerRef.current?.abort();
152
249
  abortControllerRef.current = null;
250
+ // Also stop browser inference Worker if active
251
+ if (browserInferenceActiveRef.current) {
252
+ // Settle the pending doBrowserInference promise before terminating the Worker
253
+ browserInferenceRejectRef.current?.(new Error("Generation stopped by user"));
254
+ browserInferenceRejectRef.current = null;
255
+ try {
256
+ const { stopBrowserInference } = await import("./browser-inference/browser-engine.js");
257
+ stopBrowserInference();
258
+ }
259
+ catch {
260
+ // Worker module may already be terminated or unavailable
261
+ }
262
+ browserInferenceActiveRef.current = false;
263
+ setBrowserStatus("ready");
264
+ }
153
265
  setIsLoading(false);
154
266
  }, []);
155
267
  /**
@@ -177,6 +289,8 @@ export function useChat(options) {
177
289
  isLoading,
178
290
  error,
179
291
  model,
292
+ inferenceMode,
293
+ browserStatus,
180
294
  setInput,
181
295
  setModel,
182
296
  sendMessage,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAc/D,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AASxB,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAQ3C;;OAEG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IA+BzB;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,EACD,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IA+CtC;;OAEG;YACW,gBAAgB;IAgK9B;;;;OAIG;YACW,yBAAyB;IA0KvC;;OAEG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IAOjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC;IAI5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAIF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAc/D,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AA8BxB,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAQ3C;;OAEG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IA+BzB;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACnC,EACD,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAqEtC;;OAEG;YACW,gBAAgB;IA2K9B;;;;OAIG;YACW,yBAAyB;IAsLvC;;OAEG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IAOjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC;IAI5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAIF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}