leehack commited on
Commit
b91addd
·
verified ·
1 Parent(s): ed97be8

chore: deploy Laya Tetris e924bd4

Browse files
deploy-sha.txt CHANGED
@@ -1 +1 @@
1
- f15c22bdacf4671f19f38a34ebd32db8e20e5cb0
 
1
+ e924bd457a151ec2d5b5f9ae345ff0f80bc440ed
flutter_bootstrap.js CHANGED
@@ -42,6 +42,6 @@ _flutter.buildConfig = {"engineRevision":"5d531788691ec3404cac0cee66ead4007b1773
42
 
43
  _flutter.loader.load({
44
  serviceWorkerSettings: {
45
- serviceWorkerVersion: "1386553303" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
46
  }
47
  });
 
42
 
43
  _flutter.loader.load({
44
  serviceWorkerSettings: {
45
+ serviceWorkerVersion: "2165122740" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
46
  }
47
  });
webgpu_bridge/llama_webgpu_bridge.d.ts CHANGED
@@ -200,9 +200,12 @@ export interface CompletionOptions {
200
  topP?: number;
201
  /** Min-P threshold from 0 to 1, applied after top-p; 0, the default, disables it. A value outside that range rejects. */
202
  minP?: number;
 
203
  penalty?: number;
204
- /** Subtracted once from the logit of each token among this completion's last 64 tokens; prompt tokens do not count. 0, the default, disables it. A value that is not finite as a 32-bit float rejects. */
205
  presencePenalty?: number;
 
 
206
  grammar?: string;
207
  seed?: number;
208
  /** Caps the tokens generated inside each reasoning block; text-only prompts. */
@@ -231,6 +234,8 @@ export interface CompletionCapabilities {
231
  minP: boolean;
232
  /** `CompletionOptions.thinkingBudget` is applied. */
233
  thinkingBudget: boolean;
 
 
234
  /** Each speculative strategy the loaded models can run now: `draft-mtp` needs a model loaded with `loadMtp` that has MTP layers, and the other `draft-*` strategies a matching `loadDraftModel` draft. */
235
  speculativeDecoding: Record<SpeculativeDecodingStrategy, boolean>;
236
  }
@@ -366,6 +371,17 @@ export interface DecisionOutput {
366
  actLogits: Float32Array;
367
  }
368
 
 
 
 
 
 
 
 
 
 
 
 
369
  export interface LoraAdapterCapabilities {
370
  apiVersion: number;
371
  supported: boolean;
 
200
  topP?: number;
201
  /** Min-P threshold from 0 to 1, applied after top-p; 0, the default, disables it. A value outside that range rejects. */
202
  minP?: number;
203
+ /** Repetition penalty over the last 64 tokens of the prompt and this completion; the prompt counts only for a text prompt without a `grammar` (an empty string included) and with `penaltyPromptTokens` not false. Defaults to 1.1; 1 disables it. */
204
  penalty?: number;
205
+ /** Subtracted once from the logit of each token in the same 64-token window as `penalty`. 0, the default, disables it. A value that is not finite as a 32-bit float rejects. */
206
  presencePenalty?: number;
207
+ /** `false` keeps a text prompt out of the `penalty` and `presencePenalty` window, as a `grammar` does. For a caller that drops a grammar native llamadart would keep, such as llamadart dropping a lazy tool-call grammar on WebGPU, so its output matches native, which does not count the prompt with a lazy grammar. Omitted or null means true; any other non-boolean rejects. */
208
+ penaltyPromptTokens?: boolean | null;
209
  grammar?: string;
210
  seed?: number;
211
  /** Caps the tokens generated inside each reasoning block; text-only prompts. */
 
234
  minP: boolean;
235
  /** `CompletionOptions.thinkingBudget` is applied. */
236
  thinkingBudget: boolean;
237
+ /** The penalties count the prompt, and `CompletionOptions.penaltyPromptTokens` is applied. A core without it never counts the prompt, so `penaltyPromptTokens: false` holds there too. */
238
+ penaltyPromptTokens: boolean;
239
  /** Each speculative strategy the loaded models can run now: `draft-mtp` needs a model loaded with `loadMtp` that has MTP layers, and the other `draft-*` strategies a matching `loadDraftModel` draft. */
240
  speculativeDecoding: Record<SpeculativeDecodingStrategy, boolean>;
241
  }
 
371
  actLogits: Float32Array;
372
  }
373
 
374
+ /**
375
+ * The `code` of every `getDecisionCapabilities`, `loadDecisionHead`,
376
+ * `runDecision` and `freeDecisionHead` rejection; docs/api.md lists what each
377
+ * means. The error keeps its type, name and message, so branch on `code`
378
+ * rather than on the message.
379
+ */
380
+ export type DecisionErrorCode =
381
+ | 'head-lost' | 'no-model' | 'disposed' | 'cancelled' | 'busy' | 'context'
382
+ | 'invalid-argument' | 'unsupported' | 'model' | 'inference' | 'invalid-state'
383
+ | 'runtime';
384
+
385
  export interface LoraAdapterCapabilities {
386
  apiVersion: number;
387
  supported: boolean;
webgpu_bridge/llama_webgpu_bridge.js CHANGED
@@ -132,6 +132,80 @@ function embeddingCoreError(rc, version = embeddingAssetVersion()) {
132
  return new EmbeddingError(code, message);
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  // js/src/internal/completion_options.ts
136
  var SPECULATIVE_DECODING_STRATEGIES = Object.freeze([
137
  "draft-simple",
@@ -154,6 +228,7 @@ var NO_COMPLETION_CAPABILITIES = Object.freeze({
154
  presencePenalty: false,
155
  minP: false,
156
  thinkingBudget: false,
 
157
  speculativeDecoding: Object.freeze(speculativeFlags(() => false))
158
  });
159
  var MAX_NGRAM_SIZE = 65535;
@@ -173,7 +248,7 @@ function tag(budget, name) {
173
  if (typeof value !== "string" || value.trim().length === 0) {
174
  throw new TypeError(`CompletionOptions.thinkingBudget.${name} must be a non-empty string.`);
175
  }
176
- return value;
177
  }
178
  function thinkingBudget(value, hasMediaParts) {
179
  if (value == null) {
@@ -195,6 +270,7 @@ function thinkingBudget(value, hasMediaParts) {
195
  if (typeof forcedMessage !== "string") {
196
  throw new TypeError("CompletionOptions.thinkingBudget.forcedMessage must be a string.");
197
  }
 
198
  if (hasMediaParts) {
199
  throw new Error("CompletionOptions.thinkingBudget supports text-only prompts; remove the media parts.");
200
  }
@@ -345,13 +421,26 @@ function speculativeDecoding(value, conflicts) {
345
  ngramCacheDynamic
346
  };
347
  }
 
 
 
 
 
 
 
 
 
348
  function resolveCompletionSamplingOptions(options) {
349
  const hasMediaParts = Array.isArray(options?.parts) && options.parts.length > 0;
 
 
 
350
  const budget = thinkingBudget(options?.thinkingBudget, hasMediaParts);
351
  return {
352
  minP: optionalNumber(options?.minP, "minP", (value) => value >= 0 && value <= 1, " from 0 to 1") ?? 0,
353
  presencePenalty: optionalNumber(options?.presencePenalty, "presencePenalty", () => true, "") ?? 0,
354
  thinkingBudget: budget,
 
355
  speculative: speculativeDecoding(options?.speculativeDecoding, {
356
  hasMediaParts,
357
  hasGrammar: typeof options?.grammar === "string" && options.grammar.length > 0,
@@ -371,6 +460,7 @@ function completionCapabilitiesFrom(raw) {
371
  presencePenalty: parsed?.presencePenalty === true,
372
  minP: parsed?.minP === true,
373
  thinkingBudget: parsed?.thinkingBudget === true,
 
374
  speculativeDecoding: speculativeFlags((strategy) => speculative?.[strategy] === true)
375
  };
376
  }
@@ -391,6 +481,9 @@ function requireCompletionCapabilities(sampling, capabilities) {
391
  // js/src/internal/constants.ts
392
  var defaultModelCacheName = "llamadart-webgpu-model-cache-v1";
393
  var BRIDGE_DISPOSED_MESSAGE = "Bridge has been disposed.";
 
 
 
394
  var GENERATION_ALREADY_ACTIVE_RC = -7;
395
  var GENERATION_ALREADY_ACTIVE_MESSAGE = "Generation is already active on this bridge runtime.";
396
  var INVALID_GRAMMAR_ERROR_TEXT = "Failed to initialize sampler chain (invalid grammar)";
@@ -452,23 +545,73 @@ function isInt32(value) {
452
  // js/src/internal/decision.ts
453
  var DECISION_API_VERSION = 1;
454
  var DECISION_WORKER_TIMEOUT_PER_SEQUENCE_MS = 60 * 1e3;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  function decisionHandleFrom(handle) {
456
  if (!isInt32(handle) || handle <= 0) {
457
- throw new TypeError(`Decision head handle must be a positive integer, got ${String(handle)}.`);
458
  }
459
  return handle;
460
  }
461
  function decisionIntegerList(value, label) {
462
  const isList = Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
463
  if (!isList) {
464
- throw new TypeError(`${label} must be an array or typed array of integers.`);
465
  }
466
  const list = value;
467
  const out = new Int32Array(list.length);
468
  for (let index = 0; index < list.length; index += 1) {
469
  const item = list[index];
470
  if (!isInt32(item)) {
471
- throw new TypeError(`${label}[${index}] is ${String(item)}; expected a 32-bit integer.`);
472
  }
473
  out[index] = item;
474
  }
@@ -476,18 +619,18 @@ function decisionIntegerList(value, label) {
476
  }
477
  function normalizeDecisionSequences(sequences) {
478
  if (!Array.isArray(sequences)) {
479
- throw new TypeError("Decision sequences must be an array.");
480
  }
481
  return sequences.map((sequence, index) => {
482
  const label = `Decision sequence ${index}`;
483
  if (!sequence || typeof sequence !== "object") {
484
- throw new TypeError(`${label} must be an object with tokens, markers and questionType.`);
485
  }
486
  const tokens = decisionIntegerList(sequence.tokens, `${label} tokens`);
487
  const markers = decisionIntegerList(sequence.markers, `${label} markers`);
488
  const questionType = sequence.questionType;
489
  if (!isInt32(questionType)) {
490
- throw new TypeError(
491
  `${label} questionType is ${String(questionType)}; expected 0 (choice), 1 (score) or 2 (noul).`
492
  );
493
  }
@@ -518,7 +661,7 @@ function encodeDecisionSequences(sequences) {
518
  return bytes;
519
  }
520
  function decodeDecisionOutputs(bytes, count) {
521
- const malformed = () => new Error("Decision output from the WebGPU core is malformed.");
522
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
523
  let offset = 0;
524
  const floats = (length) => {
@@ -1160,74 +1303,6 @@ function scoredTokensFrom(entries) {
1160
  }));
1161
  }
1162
 
1163
- // js/src/internal/text.ts
1164
- function buildPromptFromMessages(messages, addAssistant) {
1165
- const lines = [];
1166
- for (const msg of messages || []) {
1167
- const role = String(msg?.role ?? "user");
1168
- const content = String(msg?.content ?? "");
1169
- lines.push(`${role}: ${content}`);
1170
- }
1171
- if (addAssistant) {
1172
- lines.push("assistant: ");
1173
- }
1174
- return lines.join("\n");
1175
- }
1176
- function looksLikeCorruptedGeneration(text) {
1177
- if (typeof text !== "string" || text.length === 0) {
1178
- return false;
1179
- }
1180
- const normalized = text.trim();
1181
- if (normalized.length === 0) {
1182
- return false;
1183
- }
1184
- const unusedTokens = text.match(/<unused\d+>/g) || [];
1185
- if (unusedTokens.length >= 4) {
1186
- return true;
1187
- }
1188
- const tokenLikeTags = text.match(/<[^>]{1,40}>/g) || [];
1189
- if (tokenLikeTags.length >= 8) {
1190
- return true;
1191
- }
1192
- const compact = text.replace(/\s+/g, "");
1193
- if (compact.length === 0) {
1194
- return false;
1195
- }
1196
- const tagRun = compact.match(/(?:<[^>]{2,32}>){6,}/);
1197
- if (tagRun) {
1198
- return true;
1199
- }
1200
- const alphaNum = (normalized.match(/[A-Za-z0-9]/g) || []).length;
1201
- const printable = (normalized.match(/[\x20-\x7E]/g) || []).length;
1202
- const angleBrackets = (normalized.match(/[<>]/g) || []).length;
1203
- const alphaNumRatio = alphaNum / normalized.length;
1204
- const printableRatio = printable / normalized.length;
1205
- const bracketRatio = angleBrackets / normalized.length;
1206
- if (normalized.length >= 24 && printableRatio > 0.95 && alphaNumRatio < 0.18) {
1207
- return true;
1208
- }
1209
- if (normalized.length >= 24 && bracketRatio > 0.25) {
1210
- return true;
1211
- }
1212
- return false;
1213
- }
1214
- function trimUnstableUtf8Tail(text) {
1215
- if (typeof text !== "string" || text.length === 0) {
1216
- return "";
1217
- }
1218
- let end = text.length;
1219
- while (end > 0 && text.charCodeAt(end - 1) === 65533) {
1220
- end -= 1;
1221
- }
1222
- if (end > 0) {
1223
- const tail = text.charCodeAt(end - 1);
1224
- if (tail >= 55296 && tail <= 56319) {
1225
- end -= 1;
1226
- }
1227
- }
1228
- return end === text.length ? text : text.slice(0, end);
1229
- }
1230
-
1231
  // js/src/runtime.ts
1232
  var textEncoder = new TextEncoder();
1233
  var LlamaWebGpuBridgeRuntime = class {
@@ -3658,29 +3733,30 @@ var LlamaWebGpuBridgeRuntime = class {
3658
  }
3659
  async loadDecisionHead(source, options = {}) {
3660
  if (!this._core || this._modelBytes <= 0) {
3661
- throw new Error("No model loaded. Call loadModelFromUrl first.");
3662
  }
3663
  const configJson = options?.configJson ?? null;
3664
  if (configJson !== null && typeof configJson !== "string") {
3665
- throw new TypeError("Decision head configJson must be a string.");
3666
  }
3667
  let bytes = null;
3668
  if (typeof source === "string") {
3669
  if (source.length === 0) {
3670
- throw new Error("Decision head URL is empty.");
3671
  }
3672
  } else {
3673
  bytes = bufferSourceBytes(source);
3674
  if (!bytes) {
3675
- throw new TypeError("Decision head source must be a URL string, an ArrayBuffer or a typed array.");
3676
  }
3677
  if (bytes.byteLength === 0) {
3678
- throw new Error("Decision head bytes are empty.");
3679
  }
3680
  }
3681
  const capabilities = this.getDecisionCapabilities();
3682
  if (capabilities.supported !== true) {
3683
- throw new Error(
 
3684
  capabilities.reason || "The loaded model does not support decision heads."
3685
  );
3686
  }
@@ -3694,8 +3770,12 @@ var LlamaWebGpuBridgeRuntime = class {
3694
  if (bytes) {
3695
  core.FS.writeFile(headPath, bytes);
3696
  } else {
3697
- label = basenameFromUrl(source).slice(0, 256);
3698
- await this._stageDecisionHeadFromUrl(source, headPath, options?.onProgress);
 
 
 
 
3699
  }
3700
  if (configPath !== null) {
3701
  core.FS.writeFile(configPath, textEncoder.encode(configJson));
@@ -3710,7 +3790,10 @@ var LlamaWebGpuBridgeRuntime = class {
3710
  )
3711
  );
3712
  if (handle <= 0) {
3713
- throw new Error(this._coreErrorMessage("Failed to load decision head", handle));
 
 
 
3714
  }
3715
  const raw = core.ccall(
3716
  "llamadart_webgpu_decision_head_info_json",
@@ -3728,7 +3811,7 @@ var LlamaWebGpuBridgeRuntime = class {
3728
  const nativeHandle = decisionHandleFrom(handle);
3729
  const input = encodeDecisionSequences(sequences);
3730
  if (!this._core || this._modelBytes <= 0) {
3731
- throw new Error("No model loaded. Call loadModelFromUrl first.");
3732
  }
3733
  const core = this._core;
3734
  this._ensureDecisionDir();
@@ -3747,7 +3830,10 @@ var LlamaWebGpuBridgeRuntime = class {
3747
  )
3748
  );
3749
  if (count < 0) {
3750
- throw new Error(this._coreErrorMessage("Decision run failed", count));
 
 
 
3751
  }
3752
  return decodeDecisionOutputs(core.FS.readFile(outputPath), count);
3753
  } finally {
@@ -4188,6 +4274,11 @@ var LlamaWebGpuBridgeRuntime = class {
4188
  }
4189
  const sampling = resolveCompletionSamplingOptions(options);
4190
  requireCompletionCapabilities(sampling, this.getCompletionCapabilities());
 
 
 
 
 
4191
  this._abortRequested = false;
4192
  const startedAt = performance.now();
4193
  let firstTokenAt = null;
@@ -4205,7 +4296,7 @@ var LlamaWebGpuBridgeRuntime = class {
4205
  const topK = Number.isFinite(options.topK) ? Number(options.topK) : 40;
4206
  const topP = Number.isFinite(options.topP) ? Number(options.topP) : 0.95;
4207
  const penalty = Number.isFinite(options.penalty) ? Number(options.penalty) : 1.1;
4208
- const grammar = typeof options.grammar === "string" && options.grammar.length > 0 ? options.grammar : null;
4209
  const seed = Number.isInteger(options.seed) ? Number(options.seed) : Math.floor(Math.random() * 4294967295);
4210
  await this._stageMultimodalParts(options.parts, options);
4211
  let generationStarted = false;
@@ -4216,10 +4307,10 @@ var LlamaWebGpuBridgeRuntime = class {
4216
  }
4217
  const beginRc = Number(
4218
  await this._core.ccall(
4219
- "llamadart_webgpu_begin_generation",
4220
  "number",
4221
  [
4222
- "string",
4223
  "number",
4224
  "number",
4225
  "number",
@@ -4231,10 +4322,11 @@ var LlamaWebGpuBridgeRuntime = class {
4231
  "number",
4232
  "string",
4233
  "string",
4234
- "string"
 
4235
  ],
4236
  [
4237
- String(prompt),
4238
  temp,
4239
  topK,
4240
  topP,
@@ -4246,7 +4338,8 @@ var LlamaWebGpuBridgeRuntime = class {
4246
  sampling.thinkingBudget?.maxTokens ?? 0,
4247
  sampling.thinkingBudget?.startTag ?? null,
4248
  sampling.thinkingBudget?.endTag ?? null,
4249
- sampling.thinkingBudget?.forcedMessage ?? null
 
4250
  ],
4251
  { async: true }
4252
  )
@@ -4400,12 +4493,13 @@ var LlamaWebGpuBridgeRuntime = class {
4400
  if (this._modelBytes <= 0) {
4401
  throw new Error("No model loaded. Call loadModelFromUrl first.");
4402
  }
 
4403
  const rc = Number(
4404
  await this._core.ccall(
4405
- "llamadart_webgpu_tokenize_to_json",
4406
  "number",
4407
- ["string", "number"],
4408
- [String(text), _addSpecial ? 1 : 0],
4409
  { async: true }
4410
  )
4411
  );
@@ -4532,6 +4626,21 @@ var LlamaWebGpuBridgeRuntime = class {
4532
  }
4533
  return this._core.ccall("llamadart_webgpu_last_detokenized", "string", [], []) || "";
4534
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4535
  // Core text as raw bytes: a 'string' ccall hand-decodes 16 bytes or fewer
4536
  // and turns an incomplete or invalid UTF-8 sequence into wrong but valid
4537
  // code points instead of U+FFFD.
@@ -4596,12 +4705,13 @@ var LlamaWebGpuBridgeRuntime = class {
4596
  throw new Error("No model loaded. Call loadModelFromUrl first.");
4597
  }
4598
  const normalize = options?.normalize !== false;
 
4599
  const rc = Number(
4600
  await this._core.ccall(
4601
- "llamadart_webgpu_embed_to_json",
4602
  "number",
4603
- ["string", "number"],
4604
- [String(text), normalize ? 1 : 0],
4605
  { async: true }
4606
  )
4607
  );
@@ -4644,12 +4754,17 @@ var LlamaWebGpuBridgeRuntime = class {
4644
  throw new TypeError(`Next-token topK is ${String(topK)}; expected a 32-bit integer.`);
4645
  }
4646
  const reusePromptPrefix = options?.reusePromptPrefix !== false;
 
 
 
 
 
4647
  const rc = Number(
4648
  await this._core.ccall(
4649
- "llamadart_webgpu_score_next_token_to_json",
4650
  "number",
4651
- ["string", "string", "number", "number"],
4652
- [prompt, JSON.stringify(candidates), topK, reusePromptPrefix ? 1 : 0],
4653
  { async: true }
4654
  )
4655
  );
@@ -4951,6 +5066,9 @@ var BridgeWorkerProxy = class {
4951
  if (type === "error") {
4952
  const errorMessage = String(message.message || "Worker request failed");
4953
  const workerError = message.embeddingErrorCode ? new EmbeddingError(message.embeddingErrorCode, errorMessage) : new Error(errorMessage);
 
 
 
4954
  if (message.state && typeof message.state === "object") {
4955
  workerError.state = message.state;
4956
  }
@@ -5365,7 +5483,7 @@ var LlamaWebGpuBridge = class {
5365
  const abortError = () => createAbortError(abortMessage);
5366
  const lifecycleState = this._lifecycleState || (this._disposed ? "disposed" : "open");
5367
  if (!allowDisposed && (this._disposed || lifecycleState !== "open")) {
5368
- return Promise.reject(new Error(BRIDGE_DISPOSED_MESSAGE));
5369
  }
5370
  if (signal?.aborted) {
5371
  return Promise.reject(abortError());
@@ -5421,7 +5539,7 @@ var LlamaWebGpuBridge = class {
5421
  }
5422
  if (!allowDisposed && (this._disposed || this._lifecycleState === "disposing")) {
5423
  operation.state = "disposed";
5424
- throw new Error(BRIDGE_DISPOSED_MESSAGE);
5425
  }
5426
  started = true;
5427
  removeDisposalWaiter?.();
@@ -5492,7 +5610,7 @@ var LlamaWebGpuBridge = class {
5492
  removeDisposalWaiter = this._addDisposalWaiter(() => {
5493
  if (!started) {
5494
  operation.state = "disposed";
5495
- reject(new Error(BRIDGE_DISPOSED_MESSAGE));
5496
  }
5497
  });
5498
  }
@@ -5530,10 +5648,10 @@ var LlamaWebGpuBridge = class {
5530
  */
5531
  _throwIfDisposed() {
5532
  if (this._lifecycleState === "disposed") {
5533
- throw new Error(BRIDGE_DISPOSED_MESSAGE);
5534
  }
5535
  if ((this._disposed || this._lifecycleState === "disposing") && !this._isSettleFirstOwner()) {
5536
- throw new Error(BRIDGE_DISPOSED_MESSAGE);
5537
  }
5538
  }
5539
  _notifyDisposalWaiters() {
@@ -5822,7 +5940,9 @@ var LlamaWebGpuBridge = class {
5822
  * still holds that model, but the fresh worker would answer every request
5823
  * with "No model loaded" or without the adapters. Reload them first, and
5824
  * again on the next call if this fails. A failure here reaches the caller's
5825
- * own worker-error handling.
 
 
5826
  */
5827
  async _restoreWorkerModelIfMissing() {
5828
  if (!this._workerProxy || this._workerModelMissing !== true || !hasModelSource(this._loadedModelUrl)) {
@@ -5989,7 +6109,7 @@ var LlamaWebGpuBridge = class {
5989
  await this._ensureRuntimeDraftModel();
5990
  } catch (error) {
5991
  if (this._disposed || this._lifecycleState === "disposing") {
5992
- throw new Error(BRIDGE_DISPOSED_MESSAGE);
5993
  }
5994
  if (error?.name === "AbortError") {
5995
  throw error;
@@ -6894,6 +7014,12 @@ var LlamaWebGpuBridge = class {
6894
  }
6895
  }
6896
  async synthesizeSpeech(options = {}) {
 
 
 
 
 
 
6897
  return this._runExclusive(
6898
  () => this._synthesizeSpeechUnlocked(options),
6899
  {
@@ -6979,7 +7105,8 @@ var LlamaWebGpuBridge = class {
6979
  return this._workerProxy || this._runtime || null;
6980
  }
6981
  _staleDecisionHeadError(handle) {
6982
- return new Error(
 
6983
  `Decision head ${handle} is not loaded; it was freed, its model was unloaded, or the bridge runtime restarted. Load the decision head again.`
6984
  );
6985
  }
@@ -6996,9 +7123,20 @@ var LlamaWebGpuBridge = class {
6996
  }
6997
  return entry;
6998
  }
 
 
 
 
 
 
 
 
 
 
 
6999
  _requireDecisionRuntime() {
7000
  if (!this._runtime) {
7001
- throw new Error("No model loaded. Call loadModelFromUrl first.");
7002
  }
7003
  return this._runtime;
7004
  }
@@ -7016,13 +7154,16 @@ var LlamaWebGpuBridge = class {
7016
  return this._runExclusive(
7017
  () => this._getDecisionCapabilitiesUnlocked(),
7018
  { kind: "decision-capabilities" }
7019
- );
 
 
7020
  }
7021
  async _getDecisionCapabilitiesUnlocked() {
7022
  if (!this._workerProxy) {
7023
  return this._runtime ? this._runtime.getDecisionCapabilities() : { apiVersion: DECISION_API_VERSION, supported: false, reason: "WebGPU core is not initialized" };
7024
  }
7025
  try {
 
7026
  return await this._callWorker("getDecisionCapabilities", []);
7027
  } catch (error) {
7028
  this._throwIfOperationCancelled(error, "Decision capability probe was cancelled.");
@@ -7037,7 +7178,9 @@ var LlamaWebGpuBridge = class {
7037
  return this._runExclusive(
7038
  () => this._loadDecisionHeadUnlocked(source, options),
7039
  { kind: "decision-head-load" }
7040
- );
 
 
7041
  }
7042
  async _loadDecisionHeadUnlocked(source, options = {}) {
7043
  const loadInRuntime = async () => {
@@ -7090,7 +7233,9 @@ var LlamaWebGpuBridge = class {
7090
  return this._runExclusive(
7091
  () => this._runDecisionUnlocked(handle, sequences),
7092
  { kind: "decision-run" }
7093
- );
 
 
7094
  }
7095
  async _runDecisionUnlocked(handle, sequences) {
7096
  const entry = this._resolveDecisionHead(handle);
@@ -7102,6 +7247,7 @@ var LlamaWebGpuBridge = class {
7102
  return this._requireDecisionRuntime().runDecision(entry.handle, normalized);
7103
  }
7104
  try {
 
7105
  return await this._callWorker("runDecision", [entry.handle, normalized]);
7106
  } catch (error) {
7107
  this._throwIfOperationCancelled(error, "Decision run was cancelled.");
@@ -7110,7 +7256,8 @@ var LlamaWebGpuBridge = class {
7110
  }
7111
  this._decisionHeadMap().delete(handle);
7112
  await this._recoverWorkerOnMainThread(error);
7113
- throw new Error(
 
7114
  `Decision head ${handle} was lost when the bridge worker failed (${serializeWorkerError(error)}). Load the decision head again.`
7115
  );
7116
  }
@@ -7119,7 +7266,9 @@ var LlamaWebGpuBridge = class {
7119
  return this._runExclusive(
7120
  () => this._freeDecisionHeadUnlocked(handle),
7121
  { kind: "decision-head-free" }
7122
- );
 
 
7123
  }
7124
  async _freeDecisionHeadUnlocked(handle) {
7125
  const entry = this._resolveDecisionHead(handle);
@@ -7819,11 +7968,13 @@ function installBridgeWorkerHost() {
7819
  } catch (_) {
7820
  state = void 0;
7821
  }
 
7822
  self.postMessage({
7823
  type: "error",
7824
  id,
7825
  message: serializeWorkerError(error),
7826
  ...error instanceof EmbeddingError ? { embeddingErrorCode: error.code } : {},
 
7827
  state
7828
  });
7829
  };
 
132
  return new EmbeddingError(code, message);
133
  }
134
 
135
+ // js/src/internal/text.ts
136
+ function withoutNul(value, name) {
137
+ if (value.includes("\0")) {
138
+ throw new TypeError(`${name} contains U+0000, which the core cannot read.`);
139
+ }
140
+ return value;
141
+ }
142
+ function buildPromptFromMessages(messages, addAssistant) {
143
+ const lines = [];
144
+ for (const msg of messages || []) {
145
+ const role = String(msg?.role ?? "user");
146
+ const content = String(msg?.content ?? "");
147
+ lines.push(`${role}: ${content}`);
148
+ }
149
+ if (addAssistant) {
150
+ lines.push("assistant: ");
151
+ }
152
+ return lines.join("\n");
153
+ }
154
+ function looksLikeCorruptedGeneration(text) {
155
+ if (typeof text !== "string" || text.length === 0) {
156
+ return false;
157
+ }
158
+ const normalized = text.trim();
159
+ if (normalized.length === 0) {
160
+ return false;
161
+ }
162
+ const unusedTokens = text.match(/<unused\d+>/g) || [];
163
+ if (unusedTokens.length >= 4) {
164
+ return true;
165
+ }
166
+ const tokenLikeTags = text.match(/<[^>]{1,40}>/g) || [];
167
+ if (tokenLikeTags.length >= 8) {
168
+ return true;
169
+ }
170
+ const compact = text.replace(/\s+/g, "");
171
+ if (compact.length === 0) {
172
+ return false;
173
+ }
174
+ const tagRun = compact.match(/(?:<[^>]{2,32}>){6,}/);
175
+ if (tagRun) {
176
+ return true;
177
+ }
178
+ const alphaNum = (normalized.match(/[A-Za-z0-9]/g) || []).length;
179
+ const printable = (normalized.match(/[\x20-\x7E]/g) || []).length;
180
+ const angleBrackets = (normalized.match(/[<>]/g) || []).length;
181
+ const alphaNumRatio = alphaNum / normalized.length;
182
+ const printableRatio = printable / normalized.length;
183
+ const bracketRatio = angleBrackets / normalized.length;
184
+ if (normalized.length >= 24 && printableRatio > 0.95 && alphaNumRatio < 0.18) {
185
+ return true;
186
+ }
187
+ if (normalized.length >= 24 && bracketRatio > 0.25) {
188
+ return true;
189
+ }
190
+ return false;
191
+ }
192
+ function trimUnstableUtf8Tail(text) {
193
+ if (typeof text !== "string" || text.length === 0) {
194
+ return "";
195
+ }
196
+ let end = text.length;
197
+ while (end > 0 && text.charCodeAt(end - 1) === 65533) {
198
+ end -= 1;
199
+ }
200
+ if (end > 0) {
201
+ const tail = text.charCodeAt(end - 1);
202
+ if (tail >= 55296 && tail <= 56319) {
203
+ end -= 1;
204
+ }
205
+ }
206
+ return end === text.length ? text : text.slice(0, end);
207
+ }
208
+
209
  // js/src/internal/completion_options.ts
210
  var SPECULATIVE_DECODING_STRATEGIES = Object.freeze([
211
  "draft-simple",
 
228
  presencePenalty: false,
229
  minP: false,
230
  thinkingBudget: false,
231
+ penaltyPromptTokens: false,
232
  speculativeDecoding: Object.freeze(speculativeFlags(() => false))
233
  });
234
  var MAX_NGRAM_SIZE = 65535;
 
248
  if (typeof value !== "string" || value.trim().length === 0) {
249
  throw new TypeError(`CompletionOptions.thinkingBudget.${name} must be a non-empty string.`);
250
  }
251
+ return withoutNul(value, `CompletionOptions.thinkingBudget.${name}`);
252
  }
253
  function thinkingBudget(value, hasMediaParts) {
254
  if (value == null) {
 
270
  if (typeof forcedMessage !== "string") {
271
  throw new TypeError("CompletionOptions.thinkingBudget.forcedMessage must be a string.");
272
  }
273
+ withoutNul(forcedMessage, "CompletionOptions.thinkingBudget.forcedMessage");
274
  if (hasMediaParts) {
275
  throw new Error("CompletionOptions.thinkingBudget supports text-only prompts; remove the media parts.");
276
  }
 
421
  ngramCacheDynamic
422
  };
423
  }
424
+ function penaltyPromptTokens(value) {
425
+ if (value == null) {
426
+ return true;
427
+ }
428
+ if (typeof value !== "boolean") {
429
+ throw new TypeError(`CompletionOptions.penaltyPromptTokens must be a boolean; got ${String(value)}.`);
430
+ }
431
+ return value;
432
+ }
433
  function resolveCompletionSamplingOptions(options) {
434
  const hasMediaParts = Array.isArray(options?.parts) && options.parts.length > 0;
435
+ if (typeof options?.grammar === "string") {
436
+ withoutNul(options.grammar, "CompletionOptions.grammar");
437
+ }
438
  const budget = thinkingBudget(options?.thinkingBudget, hasMediaParts);
439
  return {
440
  minP: optionalNumber(options?.minP, "minP", (value) => value >= 0 && value <= 1, " from 0 to 1") ?? 0,
441
  presencePenalty: optionalNumber(options?.presencePenalty, "presencePenalty", () => true, "") ?? 0,
442
  thinkingBudget: budget,
443
+ penaltyPromptTokens: penaltyPromptTokens(options?.penaltyPromptTokens),
444
  speculative: speculativeDecoding(options?.speculativeDecoding, {
445
  hasMediaParts,
446
  hasGrammar: typeof options?.grammar === "string" && options.grammar.length > 0,
 
460
  presencePenalty: parsed?.presencePenalty === true,
461
  minP: parsed?.minP === true,
462
  thinkingBudget: parsed?.thinkingBudget === true,
463
+ penaltyPromptTokens: parsed?.penaltyPromptTokens === true,
464
  speculativeDecoding: speculativeFlags((strategy) => speculative?.[strategy] === true)
465
  };
466
  }
 
481
  // js/src/internal/constants.ts
482
  var defaultModelCacheName = "llamadart-webgpu-model-cache-v1";
483
  var BRIDGE_DISPOSED_MESSAGE = "Bridge has been disposed.";
484
+ function bridgeDisposedError() {
485
+ return Object.assign(new Error(BRIDGE_DISPOSED_MESSAGE), { code: "disposed" });
486
+ }
487
  var GENERATION_ALREADY_ACTIVE_RC = -7;
488
  var GENERATION_ALREADY_ACTIVE_MESSAGE = "Generation is already active on this bridge runtime.";
489
  var INVALID_GRAMMAR_ERROR_TEXT = "Failed to initialize sampler chain (invalid grammar)";
 
545
  // js/src/internal/decision.ts
546
  var DECISION_API_VERSION = 1;
547
  var DECISION_WORKER_TIMEOUT_PER_SEQUENCE_MS = 60 * 1e3;
548
+ var DECISION_ERROR_CODES = /* @__PURE__ */ new Set([
549
+ "head-lost",
550
+ "no-model",
551
+ "disposed",
552
+ "cancelled",
553
+ "busy",
554
+ "context",
555
+ "invalid-argument",
556
+ "unsupported",
557
+ "model",
558
+ "inference",
559
+ "invalid-state",
560
+ "runtime"
561
+ ]);
562
+ var CORE_STATUS_CODES = {
563
+ [-1]: "invalid-argument",
564
+ [-2]: "unsupported",
565
+ [-3]: "invalid-state",
566
+ [-4]: "model",
567
+ [-5]: "context",
568
+ [-6]: "inference",
569
+ [-7]: "busy",
570
+ [-8]: "head-lost",
571
+ [-9]: "no-model"
572
+ };
573
+ function isDecisionErrorCode(value) {
574
+ return DECISION_ERROR_CODES.has(value);
575
+ }
576
+ function decisionErrorCodeOf(error) {
577
+ const code = error && typeof error === "object" ? error.code : void 0;
578
+ return isDecisionErrorCode(code) ? code : null;
579
+ }
580
+ function withDecisionErrorCode(error, code) {
581
+ Object.defineProperty(error, "code", {
582
+ value: code,
583
+ writable: true,
584
+ enumerable: true,
585
+ configurable: true
586
+ });
587
+ return error;
588
+ }
589
+ function decisionError(code, message) {
590
+ return withDecisionErrorCode(new Error(message), code);
591
+ }
592
+ function decisionCoreStatusCode(status) {
593
+ return CORE_STATUS_CODES[status] ?? "runtime";
594
+ }
595
+ function invalidDecisionArgument(message) {
596
+ return withDecisionErrorCode(new TypeError(message), "invalid-argument");
597
+ }
598
  function decisionHandleFrom(handle) {
599
  if (!isInt32(handle) || handle <= 0) {
600
+ throw invalidDecisionArgument(`Decision head handle must be a positive integer, got ${String(handle)}.`);
601
  }
602
  return handle;
603
  }
604
  function decisionIntegerList(value, label) {
605
  const isList = Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
606
  if (!isList) {
607
+ throw invalidDecisionArgument(`${label} must be an array or typed array of integers.`);
608
  }
609
  const list = value;
610
  const out = new Int32Array(list.length);
611
  for (let index = 0; index < list.length; index += 1) {
612
  const item = list[index];
613
  if (!isInt32(item)) {
614
+ throw invalidDecisionArgument(`${label}[${index}] is ${String(item)}; expected a 32-bit integer.`);
615
  }
616
  out[index] = item;
617
  }
 
619
  }
620
  function normalizeDecisionSequences(sequences) {
621
  if (!Array.isArray(sequences)) {
622
+ throw invalidDecisionArgument("Decision sequences must be an array.");
623
  }
624
  return sequences.map((sequence, index) => {
625
  const label = `Decision sequence ${index}`;
626
  if (!sequence || typeof sequence !== "object") {
627
+ throw invalidDecisionArgument(`${label} must be an object with tokens, markers and questionType.`);
628
  }
629
  const tokens = decisionIntegerList(sequence.tokens, `${label} tokens`);
630
  const markers = decisionIntegerList(sequence.markers, `${label} markers`);
631
  const questionType = sequence.questionType;
632
  if (!isInt32(questionType)) {
633
+ throw invalidDecisionArgument(
634
  `${label} questionType is ${String(questionType)}; expected 0 (choice), 1 (score) or 2 (noul).`
635
  );
636
  }
 
661
  return bytes;
662
  }
663
  function decodeDecisionOutputs(bytes, count) {
664
+ const malformed = () => decisionError("inference", "Decision output from the WebGPU core is malformed.");
665
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
666
  let offset = 0;
667
  const floats = (length) => {
 
1303
  }));
1304
  }
1305
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1306
  // js/src/runtime.ts
1307
  var textEncoder = new TextEncoder();
1308
  var LlamaWebGpuBridgeRuntime = class {
 
3733
  }
3734
  async loadDecisionHead(source, options = {}) {
3735
  if (!this._core || this._modelBytes <= 0) {
3736
+ throw decisionError("no-model", "No model loaded. Call loadModelFromUrl first.");
3737
  }
3738
  const configJson = options?.configJson ?? null;
3739
  if (configJson !== null && typeof configJson !== "string") {
3740
+ throw invalidDecisionArgument("Decision head configJson must be a string.");
3741
  }
3742
  let bytes = null;
3743
  if (typeof source === "string") {
3744
  if (source.length === 0) {
3745
+ throw decisionError("invalid-argument", "Decision head URL is empty.");
3746
  }
3747
  } else {
3748
  bytes = bufferSourceBytes(source);
3749
  if (!bytes) {
3750
+ throw invalidDecisionArgument("Decision head source must be a URL string, an ArrayBuffer or a typed array.");
3751
  }
3752
  if (bytes.byteLength === 0) {
3753
+ throw decisionError("invalid-argument", "Decision head bytes are empty.");
3754
  }
3755
  }
3756
  const capabilities = this.getDecisionCapabilities();
3757
  if (capabilities.supported !== true) {
3758
+ throw decisionError(
3759
+ "unsupported",
3760
  capabilities.reason || "The loaded model does not support decision heads."
3761
  );
3762
  }
 
3770
  if (bytes) {
3771
  core.FS.writeFile(headPath, bytes);
3772
  } else {
3773
+ label = basenameFromUrl(source).replaceAll("\0", "%00").slice(0, 256);
3774
+ try {
3775
+ await this._stageDecisionHeadFromUrl(source, headPath, options?.onProgress);
3776
+ } catch (error) {
3777
+ throw error && typeof error === "object" ? withDecisionErrorCode(error, "model") : error;
3778
+ }
3779
  }
3780
  if (configPath !== null) {
3781
  core.FS.writeFile(configPath, textEncoder.encode(configJson));
 
3790
  )
3791
  );
3792
  if (handle <= 0) {
3793
+ throw decisionError(
3794
+ decisionCoreStatusCode(handle),
3795
+ this._coreErrorMessage("Failed to load decision head", handle)
3796
+ );
3797
  }
3798
  const raw = core.ccall(
3799
  "llamadart_webgpu_decision_head_info_json",
 
3811
  const nativeHandle = decisionHandleFrom(handle);
3812
  const input = encodeDecisionSequences(sequences);
3813
  if (!this._core || this._modelBytes <= 0) {
3814
+ throw decisionError("no-model", "No model loaded. Call loadModelFromUrl first.");
3815
  }
3816
  const core = this._core;
3817
  this._ensureDecisionDir();
 
3830
  )
3831
  );
3832
  if (count < 0) {
3833
+ throw decisionError(
3834
+ decisionCoreStatusCode(count),
3835
+ this._coreErrorMessage("Decision run failed", count)
3836
+ );
3837
  }
3838
  return decodeDecisionOutputs(core.FS.readFile(outputPath), count);
3839
  } finally {
 
4274
  }
4275
  const sampling = resolveCompletionSamplingOptions(options);
4276
  requireCompletionCapabilities(sampling, this.getCompletionCapabilities());
4277
+ const input = this._coreText(
4278
+ String(prompt),
4279
+ "llamadart_webgpu_begin_generation_bytes",
4280
+ "llamadart_webgpu_begin_generation"
4281
+ );
4282
  this._abortRequested = false;
4283
  const startedAt = performance.now();
4284
  let firstTokenAt = null;
 
4296
  const topK = Number.isFinite(options.topK) ? Number(options.topK) : 40;
4297
  const topP = Number.isFinite(options.topP) ? Number(options.topP) : 0.95;
4298
  const penalty = Number.isFinite(options.penalty) ? Number(options.penalty) : 1.1;
4299
+ const grammar = typeof options.grammar === "string" ? options.grammar : null;
4300
  const seed = Number.isInteger(options.seed) ? Number(options.seed) : Math.floor(Math.random() * 4294967295);
4301
  await this._stageMultimodalParts(options.parts, options);
4302
  let generationStarted = false;
 
4307
  }
4308
  const beginRc = Number(
4309
  await this._core.ccall(
4310
+ input.exportName,
4311
  "number",
4312
  [
4313
+ ...input.argTypes,
4314
  "number",
4315
  "number",
4316
  "number",
 
4322
  "number",
4323
  "string",
4324
  "string",
4325
+ "string",
4326
+ "number"
4327
  ],
4328
  [
4329
+ ...input.args,
4330
  temp,
4331
  topK,
4332
  topP,
 
4338
  sampling.thinkingBudget?.maxTokens ?? 0,
4339
  sampling.thinkingBudget?.startTag ?? null,
4340
  sampling.thinkingBudget?.endTag ?? null,
4341
+ sampling.thinkingBudget?.forcedMessage ?? null,
4342
+ sampling.penaltyPromptTokens ? 0 : 1
4343
  ],
4344
  { async: true }
4345
  )
 
4493
  if (this._modelBytes <= 0) {
4494
  throw new Error("No model loaded. Call loadModelFromUrl first.");
4495
  }
4496
+ const input = this._coreText(String(text), "llamadart_webgpu_tokenize_bytes_to_json", "llamadart_webgpu_tokenize_to_json");
4497
  const rc = Number(
4498
  await this._core.ccall(
4499
+ input.exportName,
4500
  "number",
4501
+ [...input.argTypes, "number"],
4502
+ [...input.args, _addSpecial ? 1 : 0],
4503
  { async: true }
4504
  )
4505
  );
 
4626
  }
4627
  return this._core.ccall("llamadart_webgpu_last_detokenized", "string", [], []) || "";
4628
  }
4629
+ // A 'string' ccall argument reaches the core as a C string, which ends at the
4630
+ // first U+0000, so text goes as UTF-8 bytes and a length when the core can
4631
+ // take them. An older core would silently drop the rest of the text.
4632
+ _coreText(text, bytesExport, stringExport) {
4633
+ if (typeof this._core[`_${bytesExport}`] === "function") {
4634
+ const bytes = textEncoder.encode(text);
4635
+ return { exportName: bytesExport, argTypes: ["array", "number"], args: [bytes, bytes.length] };
4636
+ }
4637
+ if (text.includes("\0")) {
4638
+ throw new Error(
4639
+ `Text contains U+0000, which this core cannot read: it lacks ${bytesExport}. Use the core from the same bridge release.`
4640
+ );
4641
+ }
4642
+ return { exportName: stringExport, argTypes: ["string"], args: [text] };
4643
+ }
4644
  // Core text as raw bytes: a 'string' ccall hand-decodes 16 bytes or fewer
4645
  // and turns an incomplete or invalid UTF-8 sequence into wrong but valid
4646
  // code points instead of U+FFFD.
 
4705
  throw new Error("No model loaded. Call loadModelFromUrl first.");
4706
  }
4707
  const normalize = options?.normalize !== false;
4708
+ const input = this._coreText(String(text), "llamadart_webgpu_embed_bytes_to_json", "llamadart_webgpu_embed_to_json");
4709
  const rc = Number(
4710
  await this._core.ccall(
4711
+ input.exportName,
4712
  "number",
4713
+ [...input.argTypes, "number"],
4714
+ [...input.args, normalize ? 1 : 0],
4715
  { async: true }
4716
  )
4717
  );
 
4754
  throw new TypeError(`Next-token topK is ${String(topK)}; expected a 32-bit integer.`);
4755
  }
4756
  const reusePromptPrefix = options?.reusePromptPrefix !== false;
4757
+ const input = this._coreText(
4758
+ prompt,
4759
+ "llamadart_webgpu_score_next_token_bytes_to_json",
4760
+ "llamadart_webgpu_score_next_token_to_json"
4761
+ );
4762
  const rc = Number(
4763
  await this._core.ccall(
4764
+ input.exportName,
4765
  "number",
4766
+ [...input.argTypes, "string", "number", "number"],
4767
+ [...input.args, JSON.stringify(candidates), topK, reusePromptPrefix ? 1 : 0],
4768
  { async: true }
4769
  )
4770
  );
 
5066
  if (type === "error") {
5067
  const errorMessage = String(message.message || "Worker request failed");
5068
  const workerError = message.embeddingErrorCode ? new EmbeddingError(message.embeddingErrorCode, errorMessage) : new Error(errorMessage);
5069
+ if (isDecisionErrorCode(message.decisionErrorCode)) {
5070
+ withDecisionErrorCode(workerError, message.decisionErrorCode);
5071
+ }
5072
  if (message.state && typeof message.state === "object") {
5073
  workerError.state = message.state;
5074
  }
 
5483
  const abortError = () => createAbortError(abortMessage);
5484
  const lifecycleState = this._lifecycleState || (this._disposed ? "disposed" : "open");
5485
  if (!allowDisposed && (this._disposed || lifecycleState !== "open")) {
5486
+ return Promise.reject(bridgeDisposedError());
5487
  }
5488
  if (signal?.aborted) {
5489
  return Promise.reject(abortError());
 
5539
  }
5540
  if (!allowDisposed && (this._disposed || this._lifecycleState === "disposing")) {
5541
  operation.state = "disposed";
5542
+ throw bridgeDisposedError();
5543
  }
5544
  started = true;
5545
  removeDisposalWaiter?.();
 
5610
  removeDisposalWaiter = this._addDisposalWaiter(() => {
5611
  if (!started) {
5612
  operation.state = "disposed";
5613
+ reject(bridgeDisposedError());
5614
  }
5615
  });
5616
  }
 
5648
  */
5649
  _throwIfDisposed() {
5650
  if (this._lifecycleState === "disposed") {
5651
+ throw bridgeDisposedError();
5652
  }
5653
  if ((this._disposed || this._lifecycleState === "disposing") && !this._isSettleFirstOwner()) {
5654
+ throw bridgeDisposedError();
5655
  }
5656
  }
5657
  _notifyDisposalWaiters() {
 
5940
  * still holds that model, but the fresh worker would answer every request
5941
  * with "No model loaded" or without the adapters. Reload them first, and
5942
  * again on the next call if this fails. A failure here reaches the caller's
5943
+ * own worker-error handling. Frees and unloads skip it: the core accepts
5944
+ * them without a model, and the facade forgets what they release, so the
5945
+ * next restore skips it too. The chat template never reads the model.
5946
  */
5947
  async _restoreWorkerModelIfMissing() {
5948
  if (!this._workerProxy || this._workerModelMissing !== true || !hasModelSource(this._loadedModelUrl)) {
 
6109
  await this._ensureRuntimeDraftModel();
6110
  } catch (error) {
6111
  if (this._disposed || this._lifecycleState === "disposing") {
6112
+ throw bridgeDisposedError();
6113
  }
6114
  if (error?.name === "AbortError") {
6115
  throw error;
 
7014
  }
7015
  }
7016
  async synthesizeSpeech(options = {}) {
7017
+ for (const field of ["text", "language"]) {
7018
+ const value = options?.[field];
7019
+ if (typeof value === "string") {
7020
+ withoutNul(value, `TextToSpeechOptions.${field}`);
7021
+ }
7022
+ }
7023
  return this._runExclusive(
7024
  () => this._synthesizeSpeechUnlocked(options),
7025
  {
 
7105
  return this._workerProxy || this._runtime || null;
7106
  }
7107
  _staleDecisionHeadError(handle) {
7108
+ return decisionError(
7109
+ "head-lost",
7110
  `Decision head ${handle} is not loaded; it was freed, its model was unloaded, or the bridge runtime restarted. Load the decision head again.`
7111
  );
7112
  }
 
7123
  }
7124
  return entry;
7125
  }
7126
+ // Gives every decision API rejection a DecisionErrorCode.
7127
+ _decisionRejection(error) {
7128
+ if (decisionErrorCodeOf(error)) {
7129
+ return error;
7130
+ }
7131
+ if (!error || typeof error !== "object") {
7132
+ return decisionError("runtime", serializeWorkerError(error));
7133
+ }
7134
+ const cancelled = error.name === "AbortError" && !this._isWorkerTimeoutError(error);
7135
+ return withDecisionErrorCode(error, cancelled ? "cancelled" : "runtime");
7136
+ }
7137
  _requireDecisionRuntime() {
7138
  if (!this._runtime) {
7139
+ throw decisionError("no-model", "No model loaded. Call loadModelFromUrl first.");
7140
  }
7141
  return this._runtime;
7142
  }
 
7154
  return this._runExclusive(
7155
  () => this._getDecisionCapabilitiesUnlocked(),
7156
  { kind: "decision-capabilities" }
7157
+ ).catch((error) => {
7158
+ throw this._decisionRejection(error);
7159
+ });
7160
  }
7161
  async _getDecisionCapabilitiesUnlocked() {
7162
  if (!this._workerProxy) {
7163
  return this._runtime ? this._runtime.getDecisionCapabilities() : { apiVersion: DECISION_API_VERSION, supported: false, reason: "WebGPU core is not initialized" };
7164
  }
7165
  try {
7166
+ await this._restoreWorkerModelIfMissing();
7167
  return await this._callWorker("getDecisionCapabilities", []);
7168
  } catch (error) {
7169
  this._throwIfOperationCancelled(error, "Decision capability probe was cancelled.");
 
7178
  return this._runExclusive(
7179
  () => this._loadDecisionHeadUnlocked(source, options),
7180
  { kind: "decision-head-load" }
7181
+ ).catch((error) => {
7182
+ throw this._decisionRejection(error);
7183
+ });
7184
  }
7185
  async _loadDecisionHeadUnlocked(source, options = {}) {
7186
  const loadInRuntime = async () => {
 
7233
  return this._runExclusive(
7234
  () => this._runDecisionUnlocked(handle, sequences),
7235
  { kind: "decision-run" }
7236
+ ).catch((error) => {
7237
+ throw this._decisionRejection(error);
7238
+ });
7239
  }
7240
  async _runDecisionUnlocked(handle, sequences) {
7241
  const entry = this._resolveDecisionHead(handle);
 
7247
  return this._requireDecisionRuntime().runDecision(entry.handle, normalized);
7248
  }
7249
  try {
7250
+ await this._restoreWorkerModelIfMissing();
7251
  return await this._callWorker("runDecision", [entry.handle, normalized]);
7252
  } catch (error) {
7253
  this._throwIfOperationCancelled(error, "Decision run was cancelled.");
 
7256
  }
7257
  this._decisionHeadMap().delete(handle);
7258
  await this._recoverWorkerOnMainThread(error);
7259
+ throw decisionError(
7260
+ "head-lost",
7261
  `Decision head ${handle} was lost when the bridge worker failed (${serializeWorkerError(error)}). Load the decision head again.`
7262
  );
7263
  }
 
7266
  return this._runExclusive(
7267
  () => this._freeDecisionHeadUnlocked(handle),
7268
  { kind: "decision-head-free" }
7269
+ ).catch((error) => {
7270
+ throw this._decisionRejection(error);
7271
+ });
7272
  }
7273
  async _freeDecisionHeadUnlocked(handle) {
7274
  const entry = this._resolveDecisionHead(handle);
 
7968
  } catch (_) {
7969
  state = void 0;
7970
  }
7971
+ const decisionErrorCode = decisionErrorCodeOf(error);
7972
  self.postMessage({
7973
  type: "error",
7974
  id,
7975
  message: serializeWorkerError(error),
7976
  ...error instanceof EmbeddingError ? { embeddingErrorCode: error.code } : {},
7977
+ ...decisionErrorCode ? { decisionErrorCode } : {},
7978
  state
7979
  });
7980
  };
webgpu_bridge/llama_webgpu_core.js CHANGED
The diff for this file is too large to render. See raw diff
 
webgpu_bridge/llama_webgpu_core.wasm CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:c760eadf57fe0d5bf3446d4102c2c5aad1612de7f055ea2bf491344a2b2db0e7
3
- size 10195623
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fc0202a996634fdfcdbc64337a743c5d35c94dffb6b1ca3805a63ab4b8da8e25
3
+ size 10197951
webgpu_bridge/llama_webgpu_core_mem64.js CHANGED
The diff for this file is too large to render. See raw diff
 
webgpu_bridge/llama_webgpu_core_mem64.wasm CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:c2a1c6858a84abe89b3187eb3e86306e8404a5e03b69145277c6f0851a640b9c
3
- size 10479436
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ba9f7ffd045e39940bc84e0a7a1f98d3e5ecb5209f6b41fe41e502f05f7d781
3
+ size 10481919
webgpu_bridge/manifest.json CHANGED
@@ -1,37 +1,37 @@
1
  {
2
  "artifacts": {
3
  "llama_webgpu_bridge.d.ts": {
4
- "sha256": "9c7b6f67077a99a2aabc74f7490a7b23666a83f9db6277fa129ca4298ffdc157",
5
- "size_bytes": 19006
6
  },
7
  "llama_webgpu_bridge.js": {
8
- "sha256": "984e42a2e3d470ac74d922effc0402ba6e4d940027f2b8b088213b0ce0aaa10c",
9
- "size_bytes": 299873
10
  },
11
  "llama_webgpu_bridge_worker.js": {
12
  "sha256": "47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca",
13
  "size_bytes": 257
14
  },
15
  "llama_webgpu_core.js": {
16
- "sha256": "05d04252ae79a75ce43ce912d92334c6438b84de83eaeafe2ef9a6d4a88ce036",
17
- "size_bytes": 121922
18
  },
19
  "llama_webgpu_core.wasm": {
20
- "sha256": "c760eadf57fe0d5bf3446d4102c2c5aad1612de7f055ea2bf491344a2b2db0e7",
21
- "size_bytes": 10195623
22
  },
23
  "llama_webgpu_core_mem64.js": {
24
- "sha256": "842aa0debd2cd99eb5d53c15c5762e2f05e025eb11641b65eddcb086f4bd743c",
25
- "size_bytes": 143487
26
  },
27
  "llama_webgpu_core_mem64.wasm": {
28
- "sha256": "c2a1c6858a84abe89b3187eb3e86306e8404a5e03b69145277c6f0851a640b9c",
29
- "size_bytes": 10479436
30
  }
31
  },
32
  "assets_repository": "leehack/llama-web-bridge-assets",
33
- "bridge_assets_tag": "v0.1.71",
34
- "bridge_commit": "24b1b5f14ea6c20e001b18af42c4568b7dbba025",
35
  "bridge_repository": "leehack/llama-web-bridge",
36
  "capabilities": {
37
  "memory64": true,
@@ -62,43 +62,43 @@
62
  "emscripten_version": "6.0.8",
63
  "files": {
64
  "llama_webgpu_bridge.d.ts": {
65
- "sha256": "9c7b6f67077a99a2aabc74f7490a7b23666a83f9db6277fa129ca4298ffdc157",
66
- "size_bytes": 19006
67
  },
68
  "llama_webgpu_bridge.js": {
69
- "sha256": "984e42a2e3d470ac74d922effc0402ba6e4d940027f2b8b088213b0ce0aaa10c",
70
- "size_bytes": 299873
71
  },
72
  "llama_webgpu_bridge_worker.js": {
73
  "sha256": "47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca",
74
  "size_bytes": 257
75
  },
76
  "llama_webgpu_core.js": {
77
- "sha256": "05d04252ae79a75ce43ce912d92334c6438b84de83eaeafe2ef9a6d4a88ce036",
78
- "size_bytes": 121922
79
  },
80
  "llama_webgpu_core.wasm": {
81
- "sha256": "c760eadf57fe0d5bf3446d4102c2c5aad1612de7f055ea2bf491344a2b2db0e7",
82
- "size_bytes": 10195623
83
  },
84
  "llama_webgpu_core_mem64.js": {
85
- "sha256": "842aa0debd2cd99eb5d53c15c5762e2f05e025eb11641b65eddcb086f4bd743c",
86
- "size_bytes": 143487
87
  },
88
  "llama_webgpu_core_mem64.wasm": {
89
- "sha256": "c2a1c6858a84abe89b3187eb3e86306e8404a5e03b69145277c6f0851a640b9c",
90
- "size_bytes": 10479436
91
  }
92
  },
93
- "github_run_id": "39963902003",
94
- "github_run_url": "https://github.com/leehack/llama-web-bridge/actions/runs/39963902003",
95
  "llama_cpp_commit": "620d2225cc436ab0b001e3200e590e3b286ef9ab",
96
  "llama_cpp_tag": "v0.7.0",
97
  "native_commit": "298314bd0ff4650363e0e63b81399d5618869a63",
98
  "native_manifest_sha256": "92b9f1ea6d3ec3dd826122ffde3cf21b2b22036c368e826d86e927284c6908f4",
99
  "native_release_tag": "v0.7.0-2",
100
  "native_repository": "leehack/llamadart-native",
101
- "orchestrator_correlation_id": "auto-stable-v0.7.0-2-92b9f1ea6d3ec3dd-build-24b1b5f14ea6c20e",
102
  "qualification_gates": {
103
  "multimodal": "passed",
104
  "speech_to_text": "required-automated-qualification",
@@ -107,9 +107,9 @@
107
  },
108
  "release_channel": "stable",
109
  "release_rebuild": 0,
110
- "release_tag": "v0.1.71",
111
  "schema_version": 2,
112
- "source_commit": "24b1b5f14ea6c20e001b18af42c4568b7dbba025",
113
  "source_repository": "leehack/llama-web-bridge",
114
  "unproven_capabilities": {
115
  "hardware_gpu_acceleration": "unavailable-on-hosted-runners",
 
1
  {
2
  "artifacts": {
3
  "llama_webgpu_bridge.d.ts": {
4
+ "sha256": "a9ad3fe96e3282fcf6142e9e70dbfb356c6c17fbc167c4048b17085730b55eb0",
5
+ "size_bytes": 20335
6
  },
7
  "llama_webgpu_bridge.js": {
8
+ "sha256": "181b234f2adce4c6432c52cf3bb9cfbd09edf7adc7dfcca39dde128a1023566a",
9
+ "size_bytes": 305344
10
  },
11
  "llama_webgpu_bridge_worker.js": {
12
  "sha256": "47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca",
13
  "size_bytes": 257
14
  },
15
  "llama_webgpu_core.js": {
16
+ "sha256": "fc4ee380143faed3449da4071f14272b448fcf68e87e59ced89adc1e87f40a72",
17
+ "size_bytes": 122541
18
  },
19
  "llama_webgpu_core.wasm": {
20
+ "sha256": "fc0202a996634fdfcdbc64337a743c5d35c94dffb6b1ca3805a63ab4b8da8e25",
21
+ "size_bytes": 10197951
22
  },
23
  "llama_webgpu_core_mem64.js": {
24
+ "sha256": "a2a1b07d466e37db6950c0bc2036567fc08de862d1c75408947c15ec409b65f4",
25
+ "size_bytes": 144106
26
  },
27
  "llama_webgpu_core_mem64.wasm": {
28
+ "sha256": "2ba9f7ffd045e39940bc84e0a7a1f98d3e5ecb5209f6b41fe41e502f05f7d781",
29
+ "size_bytes": 10481919
30
  }
31
  },
32
  "assets_repository": "leehack/llama-web-bridge-assets",
33
+ "bridge_assets_tag": "v0.1.72",
34
+ "bridge_commit": "22fd92f359c2dcdf56f50688f23043553731f143",
35
  "bridge_repository": "leehack/llama-web-bridge",
36
  "capabilities": {
37
  "memory64": true,
 
62
  "emscripten_version": "6.0.8",
63
  "files": {
64
  "llama_webgpu_bridge.d.ts": {
65
+ "sha256": "a9ad3fe96e3282fcf6142e9e70dbfb356c6c17fbc167c4048b17085730b55eb0",
66
+ "size_bytes": 20335
67
  },
68
  "llama_webgpu_bridge.js": {
69
+ "sha256": "181b234f2adce4c6432c52cf3bb9cfbd09edf7adc7dfcca39dde128a1023566a",
70
+ "size_bytes": 305344
71
  },
72
  "llama_webgpu_bridge_worker.js": {
73
  "sha256": "47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca",
74
  "size_bytes": 257
75
  },
76
  "llama_webgpu_core.js": {
77
+ "sha256": "fc4ee380143faed3449da4071f14272b448fcf68e87e59ced89adc1e87f40a72",
78
+ "size_bytes": 122541
79
  },
80
  "llama_webgpu_core.wasm": {
81
+ "sha256": "fc0202a996634fdfcdbc64337a743c5d35c94dffb6b1ca3805a63ab4b8da8e25",
82
+ "size_bytes": 10197951
83
  },
84
  "llama_webgpu_core_mem64.js": {
85
+ "sha256": "a2a1b07d466e37db6950c0bc2036567fc08de862d1c75408947c15ec409b65f4",
86
+ "size_bytes": 144106
87
  },
88
  "llama_webgpu_core_mem64.wasm": {
89
+ "sha256": "2ba9f7ffd045e39940bc84e0a7a1f98d3e5ecb5209f6b41fe41e502f05f7d781",
90
+ "size_bytes": 10481919
91
  }
92
  },
93
+ "github_run_id": "40023375407",
94
+ "github_run_url": "https://github.com/leehack/llama-web-bridge/actions/runs/40023375407",
95
  "llama_cpp_commit": "620d2225cc436ab0b001e3200e590e3b286ef9ab",
96
  "llama_cpp_tag": "v0.7.0",
97
  "native_commit": "298314bd0ff4650363e0e63b81399d5618869a63",
98
  "native_manifest_sha256": "92b9f1ea6d3ec3dd826122ffde3cf21b2b22036c368e826d86e927284c6908f4",
99
  "native_release_tag": "v0.7.0-2",
100
  "native_repository": "leehack/llamadart-native",
101
+ "orchestrator_correlation_id": "auto-stable-v0.7.0-2-92b9f1ea6d3ec3dd-build-22fd92f359c2dcdf",
102
  "qualification_gates": {
103
  "multimodal": "passed",
104
  "speech_to_text": "required-automated-qualification",
 
107
  },
108
  "release_channel": "stable",
109
  "release_rebuild": 0,
110
+ "release_tag": "v0.1.72",
111
  "schema_version": 2,
112
+ "source_commit": "22fd92f359c2dcdf56f50688f23043553731f143",
113
  "source_repository": "leehack/llama-web-bridge",
114
  "unproven_capabilities": {
115
  "hardware_gpu_acceleration": "unavailable-on-hosted-runners",
webgpu_bridge/sha256sums.txt CHANGED
@@ -1,7 +1,7 @@
1
- 984e42a2e3d470ac74d922effc0402ba6e4d940027f2b8b088213b0ce0aaa10c llama_webgpu_bridge.js
2
- 05d04252ae79a75ce43ce912d92334c6438b84de83eaeafe2ef9a6d4a88ce036 llama_webgpu_core.js
3
- c760eadf57fe0d5bf3446d4102c2c5aad1612de7f055ea2bf491344a2b2db0e7 llama_webgpu_core.wasm
4
  47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca llama_webgpu_bridge_worker.js
5
- 9c7b6f67077a99a2aabc74f7490a7b23666a83f9db6277fa129ca4298ffdc157 llama_webgpu_bridge.d.ts
6
- 842aa0debd2cd99eb5d53c15c5762e2f05e025eb11641b65eddcb086f4bd743c llama_webgpu_core_mem64.js
7
- c2a1c6858a84abe89b3187eb3e86306e8404a5e03b69145277c6f0851a640b9c llama_webgpu_core_mem64.wasm
 
1
+ 181b234f2adce4c6432c52cf3bb9cfbd09edf7adc7dfcca39dde128a1023566a llama_webgpu_bridge.js
2
+ fc4ee380143faed3449da4071f14272b448fcf68e87e59ced89adc1e87f40a72 llama_webgpu_core.js
3
+ fc0202a996634fdfcdbc64337a743c5d35c94dffb6b1ca3805a63ab4b8da8e25 llama_webgpu_core.wasm
4
  47bbfa0fe897e708455b9497e9aa41d2e94489c329300c33b12936fb3169deca llama_webgpu_bridge_worker.js
5
+ a9ad3fe96e3282fcf6142e9e70dbfb356c6c17fbc167c4048b17085730b55eb0 llama_webgpu_bridge.d.ts
6
+ a2a1b07d466e37db6950c0bc2036567fc08de862d1c75408947c15ec409b65f4 llama_webgpu_core_mem64.js
7
+ 2ba9f7ffd045e39940bc84e0a7a1f98d3e5ecb5209f6b41fe41e502f05f7d781 llama_webgpu_core_mem64.wasm