arcane-os 0.79.1 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- # Native Laya typed decisions
1
+ # Native typed decisions
2
2
 
3
3
  `arcane-os/local-ai/decisions` and `arcane-os/core/decisions` run the selected
4
- Laya FP32 graph through the SDK's existing native ONNX owner. Tokenization runs
4
+ Laya FP32, Laya FP16 or Julia FP32 graph through the SDK's existing native ONNX owner. Tokenization runs
5
5
  in its own Node Worker. A Core service can load and evaluate decisions without
6
6
  a renderer, browser session, WebGPU browser context or chat provider.
7
7
 
@@ -58,7 +58,7 @@ name to `decisions`. It exposes `load`, `evaluate`, `classify` (an alias for
58
58
  | Method | Parameters and result |
59
59
  | --- | --- |
60
60
  | `decisions.status` | Current lifecycle snapshot; does not load anything. |
61
- | `decisions.load` | `{executionTarget?}`, where the target is `{deviceId:string}` or `null`; explicit activation or target replacement, returning the ready lifecycle snapshot. The request signal cancels activation. |
61
+ | `decisions.load` | `{family?, model?, revision?, dtype?, assetProjectionId?, resourcePaths?, executionTarget?}`; explicit activation or model/source/device replacement, returning the ready lifecycle snapshot. The request signal cancels activation. A target is `{deviceId:string}` or `null`. |
62
62
  | `decisions.evaluate` | `{rows, runOptions?}`; returns `{decisions, outputs}`. The request signal cancels the active model operation. |
63
63
  | `decisions.unload` | Releases the activation. Service-lifetime cleanup continues after the caller disconnects. |
64
64
 
@@ -94,11 +94,89 @@ const decisions = createNativeDecisionModel({
94
94
  These direct paths are native filesystem paths. Keep the graph's external data
95
95
  beside it under the exact filename required by the graph. The Core service
96
96
  resolves configured `paths` relative to `appRoot`; it does not copy or remove
97
- caller-owned files. For SDK-prepared files, the default selected upstream is
98
- `onnx-community/laya-typed-decisions-ONNX`, revision `main`, with exactly:
97
+ caller-owned files. Factory defaults remain `family:'laya'`,
98
+ `model:'onnx-community/laya-typed-decisions-ONNX'`, `revision:'main'` and
99
+ `dtype:'fp32'`. SDK upstream preparation selects these exact layouts:
99
100
 
100
- - `onnx/model.onnx` and `onnx/model.onnx_data`;
101
- - `tokenizer.json` and `tokenizer_config.json`.
101
+ | Family and dtype | Graph | Complete external data |
102
+ | --- | --- | --- |
103
+ | `laya`, `fp32` | `onnx/model.onnx` | `onnx/model.onnx_data` |
104
+ | `laya`, `fp16` | `onnx/model_fp16.onnx` | `onnx/model_fp16.onnx_data` |
105
+ | `julia`, `fp32` | `model.onnx` | `model.onnx.data` |
106
+
107
+ Each selection uses `tokenizer.json` and `tokenizer_config.json` from its own
108
+ selected repository. Julia's public repository is `SupersonicLabs/Julia-1-ONNX`.
109
+
110
+ ## Load complete files already stored in DBOPFS
111
+
112
+ Use the existing [model-assets projection](model-assets.md) for complete files
113
+ already obtained through the application's DBOPFS model store. Pass every
114
+ original member, including `onnx/model.onnx_data`, to `prepareCoreModelAssets`.
115
+ The original relative paths and complete content remain unchanged:
116
+
117
+ ```js
118
+ import {prepareCoreModelAssets} from 'arcane-os/ai/core-model-assets';
119
+
120
+ const projection = await prepareCoreModelAssets({
121
+ client,
122
+ workingDirectory: selectedWorkingDirectory,
123
+ members: [
124
+ {path: 'onnx/model.onnx', file: storedGraph},
125
+ {path: 'onnx/model.onnx_data', file: storedGraphData},
126
+ {path: 'tokenizer.json', file: storedTokenizer},
127
+ {path: 'tokenizer_config.json', file: storedTokenizerConfig}
128
+ ],
129
+ signal
130
+ });
131
+ try {
132
+ await client.invoke('decisions.load', {
133
+ assetProjectionId: projection.id,
134
+ resourcePaths: {
135
+ model: 'onnx/model.onnx',
136
+ tokenizer: 'tokenizer.json',
137
+ tokenizerConfig: 'tokenizer_config.json'
138
+ },
139
+ executionTarget: {deviceId: 'cpu'}
140
+ }, {signal, timeoutMs: 0});
141
+ } finally {
142
+ // The native activation owns a separate retain handle after loading.
143
+ await projection.release();
144
+ }
145
+ ```
146
+
147
+ Here the four `stored*` values are the complete original Blob/File members
148
+ from the application's existing store. This projects those files; it performs
149
+ no model download. The decision service must already be registered as above.
150
+ After loading, invoke `decisions.evaluate` with the complete `rows`, then
151
+ `decisions.unload` when that native activation is no longer needed.
152
+
153
+ Direct model and service calls accept
154
+ `load({family, model, revision, dtype, assetProjectionId, resourcePaths, executionTarget, signal})`; their
155
+ factory configuration accepts the same source selection. A direct model needs
156
+ the existing `modelAssets` owner when selecting a projection. `resourcePaths`
157
+ maps all three roles (`model`, `tokenizer`, `tokenizerConfig`) to exact
158
+ `member.path` values in a ready projection. Additional companion members stay
159
+ in its retained directory; the graph finds its external data under the exact
160
+ relative filename it references. The SDK does not rename or reconstruct them.
161
+
162
+ A supplied projection is retained and used directly. It takes precedence over
163
+ configured `paths` and upstream settings and never invokes upstream preparation
164
+ or retries with downloaded files. Missing, unfinished or released projections,
165
+ and missing mapped resources, report their actual failure.
166
+
167
+ Omitted or `undefined` source fields retain the selected source and mappings.
168
+ `assetProjectionId: null` returns to the factory's configured `paths`, or its
169
+ existing upstream preparation when no paths were configured. Selecting another
170
+ projection or changing any resource mapping replaces the activation even when
171
+ the execution target stays the same. Equal family, model, revision, dtype,
172
+ source, mapping and device selections
173
+ coalesce. The incoming retain is acquired before the prior activation retires,
174
+ so device replacement can reuse a projection after the caller has released its
175
+ preparation ownership. Superseded pending retains are released as their cleanup
176
+ settles. Unload ends the native use; if no preparation or other use remains,
177
+ create a fresh projection from the stored originals before loading again.
178
+
179
+ ## Existing upstream preparation
102
180
 
103
181
  `model` selects the upstream Hugging Face repository and `revision` its
104
182
  revision. Native preparation performs normal upstream fetches only during
@@ -108,8 +186,12 @@ model store. The approved `@huggingface/tokenizers@0.2.0` dependency reads the
108
186
  selected tokenizer files in its Worker. No Transformers or second ONNX runtime
109
187
  is loaded by this API.
110
188
 
111
- This graph selection requires `dtype:'fp32'`, which is also the default; another
112
- dtype reports the incompatible selection rather than substituting a graph.
189
+ Native graph selections support Laya `fp32` and `fp16`, and Julia `fp32`.
190
+ Other family/precision combinations report an unsupported selection. Laya FP16
191
+ uses the published mixed-precision graph, which retains selected operations
192
+ and outputs in FP32; it does not claim every graph operation uses FP16. Julia
193
+ uses its typed five-input ONNX graph and raw option logits, without the upstream
194
+ display-rounded `predict()` wrapper or invented action outputs.
113
195
  `sessionOptions` and `runOptions` pass to the existing native ONNX API unchanged.
114
196
  With no `executionTarget` selection, `executionPreference` defaults to `gpu`
115
197
  here: actual advertised native GPU provider creation is attempted, followed by
@@ -119,6 +201,49 @@ continues to default to CPU. Accepted provider configuration is not evidence
119
201
  that GPU nodes executed. Full provider-attempt diagnostics remain in
120
202
  `execution`; see [native ONNX sessions](local-ai.md#native-onnx-sessions).
121
203
 
204
+ ## Select an activation's model
205
+
206
+ Both factories and each direct/Core `load` accept `family`, `model`, `revision`
207
+ and `dtype`. The same service persists while its selected activation changes:
208
+
209
+ ```js
210
+ await client.invoke('decisions.load', {
211
+ family: 'julia',
212
+ model: 'SupersonicLabs/Julia-1-ONNX',
213
+ revision: 'main',
214
+ dtype: 'fp32',
215
+ assetProjectionId: juliaProjection.id,
216
+ resourcePaths: {
217
+ model: 'model.onnx',
218
+ tokenizer: 'tokenizer.json',
219
+ tokenizerConfig: 'tokenizer_config.json'
220
+ }
221
+ }, {signal, timeoutMs: 0});
222
+ ```
223
+
224
+ Here `juliaProjection` is the caller's ready projection containing Julia's
225
+ complete graph, `model.onnx.data` and its own tokenizer files. The caller may
226
+ release its preparation ownership after loading, as in the projection example.
227
+ For upstream preparation without configured paths, select the same four model
228
+ fields with `assetProjectionId: null`.
229
+
230
+ Omitting a model field, or supplying `undefined`, retains its most recent
231
+ selection, initially the factory default. The selection survives unload for a
232
+ later explicit load. Changing any field replaces the activation; equal complete
233
+ selections share it. Supply the complete new model selection when changing
234
+ family, including its matching projection/mapping or configured native files.
235
+ Changing `family` alone does not infer a repository, change precision, replace
236
+ configured files, or rewrite a projection. Metadata describes the caller's
237
+ selection; the SDK does not inspect weights to establish checkpoint identity.
238
+ Configured `paths` and a selected projection keep their existing precedence
239
+ over upstream preparation.
240
+
241
+ Top-level `current().family`, `model`, `revision` and `dtype` follow the
242
+ activation being loaded, used or retired. While replacement waits for prior
243
+ cleanup, those fields and `execution` still describe the prior activation;
244
+ `pendingActivation` carries the requested successor separately. The new
245
+ selection takes ownership when its activation begins.
246
+
122
247
  ## Select an activation's execution device
123
248
 
124
249
  Both factories accept `executionTarget: {deviceId:string}` or `null` in their
@@ -158,15 +283,17 @@ resolution, accepted configuration and actual execution evidence. An unknown
158
283
  `observedTarget` remains `null`; successful configuration alone does not establish
159
284
  which device executed graph nodes.
160
285
 
161
- `pendingActivation` is separately `null` or `{executionTarget}` while a load or
162
- replacement is pending; its `executionTarget` property is omitted at JSON
163
- transport when the selection is `undefined`. A pending target never overwrites the previous
286
+ `pendingActivation` is separately `null` or a selection containing `family`,
287
+ `model`, `revision`, `dtype` and `executionTarget` while a load or replacement
288
+ is pending; its `executionTarget` property is omitted at JSON
289
+ transport when the selection is `undefined`. A projected selection also includes
290
+ `assetProjectionId` and its complete `resourcePaths` mapping. A pending target never overwrites the previous
164
291
  activation's `execution` record. The old record remains attributable to the
165
292
  retiring activation until its cleanup completes, then the new activation owns
166
293
  its own record. A request is not a claim that the requested device is running.
167
294
 
168
- Concurrent loads for the same target share their pending activation. A
169
- different target supersedes the earlier pending request, which rejects with
295
+ Concurrent loads for the same family, model, revision, dtype, source, resource mapping and target share their
296
+ pending activation. A different selection supersedes the earlier pending request, which rejects with
170
297
  cancellation instead of returning another target's ready result. Replacement
171
298
  joins this model's actual tokenizer/native cleanup before creating its
172
299
  successor. Independent model owners retain their independent workers and
@@ -209,7 +336,8 @@ progress includes model preparation, tokenization and evaluation; downloaded
209
336
  members report files, not byte progress. Complete technical errors belong in
210
337
  developer diagnostics, while the application owns its user-facing status.
211
338
 
212
- Concurrent callers selecting the same target share one explicit activation.
339
+ Concurrent callers selecting the same family, model, revision, dtype, source,
340
+ mapping and target share one explicit activation.
213
341
  Cancelling a load or evaluation cancels that activation and its outstanding operations, because the
214
342
  native session and tokenizer have one owner. Use separately owned models when
215
343
  independent cancellation is required. The construction `signal` governs the
@@ -219,7 +347,8 @@ cleanup; `dispose()` is terminal. Readiness is revoked as disposal begins.
219
347
  Retained model files remain owned until the ONNX and tokenizer Workers really
220
348
  exit. A rejected load, inference or termination request alone does not permit
221
349
  file deletion. Cleanup joins active operations and native output delivery,
222
- preserves cleanup errors, then releases only its working projection. It never
350
+ preserves cleanup errors, then releases its native-use handle. Preparation
351
+ ownership of a supplied projection remains with its caller. It never
223
352
  deletes supplied `paths`. A failed ordinary row does not destroy a healthy
224
353
  loaded session or cancel sibling evaluations. The ONNX owner's `stopping:true`
225
354
  retires decision readiness immediately on terminal Worker failure or shutdown,
@@ -232,5 +361,6 @@ availability. Android requires the host's supported native adaptation. Static
232
361
  source review and synthetic authored fixtures are not model execution or a
233
362
  claim of tested platform, precision or accelerator behavior.
234
363
 
235
- Upstream selection: [Laya FP32 model files](https://huggingface.co/onnx-community/laya-typed-decisions-ONNX/tree/main),
364
+ Upstream selection: [Laya model files](https://huggingface.co/onnx-community/laya-typed-decisions-ONNX/tree/main),
365
+ [Julia-1 model files](https://huggingface.co/SupersonicLabs/Julia-1-ONNX/tree/main),
236
366
  [Tokenizer package](https://www.npmjs.com/package/@huggingface/tokenizers).
@@ -69,7 +69,7 @@ runtime layouts.
69
69
  | `arcane-os/core/local-ai` | Native llama.cpp, Ollama and ONNX Core service, model readiness, complete responses and owned lifecycle. See [local AI through Core](local-ai.md). |
70
70
  | `arcane-os/local-ai` | Official runtime installation and native artifact bundling for selected llama.cpp/Ollama/ONNX/image requirements and NeMo libraries. |
71
71
  | `arcane-os/local-ai/onnx` | Retained native ONNX worker sessions with explicit graph loading and complete tensor inference. |
72
- | `arcane-os/local-ai/decisions` | Explicit native Laya FP32 decisions using the existing ONNX owner and a tokenizer Worker. |
72
+ | `arcane-os/local-ai/decisions` | Explicit native Laya FP32/FP16 and Julia FP32 decisions using the existing ONNX owner and a tokenizer Worker. |
73
73
  | `arcane-os/core/decisions` | Renderer-independent typed-decision service composed with existing local-AI and model-assets owners. |
74
74
  | `arcane-os/ai/core-onnx` | Optional browser access to system ONNX through an existing Core connection. |
75
75
  | `arcane-os/local-ai/image` | Retained native stable-diffusion.cpp context, complete PNG generation and owned worker lifetime. |
@@ -186,7 +186,7 @@ The remaining data-only subpaths are eight JSON Schemas and package metadata.
186
186
  | `acceptWebSocket()` | function | `arcane-os`, `arcane-os/websocket` | WebSocket protocol | Node; browser-native client interoperability |
187
187
  | `WS` | class | `arcane-os`, `arcane-os/websocket-client` | Shared WebSocket clients | Node and native-WebSocket browser hosts |
188
188
  | `createBrowserDecisionModel()` | function | `arcane-os/ai/browser-decisions` | Browser typed decisions | Browser module Workers and the caller-selected inference backend |
189
- | `createNativeDecisionModel()` | function | `arcane-os/local-ai/decisions` | Native typed decisions | Node with an existing native ONNX owner and selected Laya FP32 files |
189
+ | `createNativeDecisionModel()` | function | `arcane-os/local-ai/decisions` | Native typed decisions | Node with an existing native ONNX owner and selected Laya FP32/FP16 or Julia FP32 files |
190
190
  | `createNativeDecisionService()` | function | `arcane-os/core/decisions` | Native typed decisions | Node Core with existing local-AI and model-assets services |
191
191
  | `createNativeDecisionService default export` | function | `arcane-os/core/decisions` | Native typed decisions | Same native decision service factory |
192
192
  | `fetchRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud requests | Node and Browser; remote HTTPS provider |
@@ -9505,23 +9505,35 @@ native installation eligibility and URL-bar promotion.
9505
9505
 
9506
9506
  ### Overview
9507
9507
 
9508
- Runs explicitly selected Laya FP32 option scoring through an existing native
9508
+ Runs explicitly selected Laya FP32/FP16 or Julia FP32 option scoring through an existing native
9509
9509
  ONNX owner, with tokenization in a Node Worker. It creates no second inference
9510
9510
  engine and starts no model download at construction.
9511
9511
 
9512
9512
  ### Signature and result
9513
9513
 
9514
9514
  ```text
9515
- createNativeDecisionModel({onnx,modelAssets,workingDirectory,paths,model='onnx-community/laya-typed-decisions-ONNX',revision='main',dtype='fp32',sessionOptions,executionPreference='gpu',signal}={})
9515
+ createNativeDecisionModel({onnx,modelAssets,workingDirectory,paths,assetProjectionId,resourcePaths,family='laya',model='onnx-community/laya-typed-decisions-ONNX',revision='main',dtype='fp32',sessionOptions,executionPreference='gpu',executionTarget,signal}={})
9516
9516
  ```
9517
9517
 
9518
9518
  Import from `arcane-os/local-ai/decisions`. Supply the existing `onnx` owner and
9519
9519
  either `modelAssets` plus `workingDirectory`, or native `paths` for the model,
9520
- tokenizer and tokenizer configuration. The selected graph requires FP32. The
9520
+ tokenizer and tokenizer configuration, or a ready `assetProjectionId` with
9521
+ `resourcePaths` for those three roles. Supported selections are Laya `fp32`,
9522
+ Laya `fp16` and Julia `fp32`; constructor defaults remain Laya FP32. The
9521
9523
  handle exposes `load`, `evaluate`, `classify`, `current`, `status`, `subscribe`,
9522
9524
  `unload` and terminal `dispose`; `classify` aliases `evaluate` and `status`
9523
9525
  aliases `current`.
9524
9526
 
9527
+ `load({family,model,revision,dtype,assetProjectionId,resourcePaths,executionTarget,signal})`
9528
+ selects each activation. Omitted or `undefined` fields retain their prior
9529
+ selection. A changed model field, source, mapping or device replaces the
9530
+ activation after actual cleanup; equal complete selections coalesce. Supply
9531
+ all matching model fields and files when changing family: metadata does not
9532
+ infer a repository or rewrite a supplied projection. Top-level model metadata
9533
+ continues to describe the retiring activation while `pendingActivation` records
9534
+ its successor. See [model selection](native-decisions.md#select-an-activations-model)
9535
+ for exact upstream graph/companion layouts and retained projection ownership.
9536
+
9525
9537
  `evaluate(rows,{signal,runOptions})` preserves each complete `state`, `question`,
9526
9538
  `options` and optional `type` separately. It returns `{decisions,outputs}` with
9527
9539
  original rows, typed values, raw logits, unrounded probabilities and every
@@ -9574,7 +9586,11 @@ reacquires `getONNXRuntime()` after any recovery. Native members are `load`,
9574
9586
  `start(context)`.
9575
9587
 
9576
9588
  RPC exposes `decisions.status`, `decisions.load`, `decisions.evaluate` and
9577
- `decisions.unload`. Evaluation accepts `{rows,runOptions?}` and returns complete
9589
+ `decisions.unload`. Load accepts optional `family`, `model`, `revision`, `dtype`,
9590
+ `assetProjectionId`, `resourcePaths` and `executionTarget`, with the same
9591
+ per-activation selection and omission behavior as direct native load; the Core
9592
+ request signal owns cancellation. The service persists across model changes.
9593
+ Evaluation accepts `{rows,runOptions?}` and returns complete
9578
9594
  `{decisions,outputs}` using the existing tensor codec at the JSON boundary.
9579
9595
  `decisions.state` and replaying `subscribe(listener,{emitCurrent:true,signal})`
9580
9596
  report lifecycle. Unload is accepted service-lifetime cleanup; host shutdown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.79.1",
3
+ "version": "0.81.0",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -5018,6 +5018,7 @@ class AI {
5018
5018
  model,
5019
5019
  structuredOutput=false,
5020
5020
  localOnly=false,
5021
+ speech=true,
5021
5022
  onChunk=function ignoreStreamChunk(){},
5022
5023
  toolText,
5023
5024
  onToolText,
@@ -5062,6 +5063,9 @@ class AI {
5062
5063
  if(localOnly!==true&&localOnly!==false){
5063
5064
  throw new TypeError('AI localOnly must be a boolean.');
5064
5065
  }
5066
+ if(speech!==true&&speech!==false){
5067
+ throw new TypeError('AI speech must be a boolean.');
5068
+ }
5065
5069
  if(localOnly&&!this.#hasLocalRoute('llm',this.llmService)){
5066
5070
  const error=new Error(
5067
5071
  'This AI request requires a configured local model.'
@@ -5163,7 +5167,7 @@ class AI {
5163
5167
  if(signal?.aborted){
5164
5168
  throw normalizeAIRequestAbort();
5165
5169
  }
5166
- this.#finishStreamingSpeech();
5170
+ if(speech)this.#finishStreamingSpeech();
5167
5171
  return result;
5168
5172
  }catch(error){
5169
5173
  if(handle){
@@ -5171,7 +5175,7 @@ class AI {
5171
5175
  function retainProviderStreamCleanupFailure() {}
5172
5176
  );
5173
5177
  }
5174
- this.stopAudio();
5178
+ if(speech)this.stopAudio();
5175
5179
  throw isAIRequestAbort(error,signal)
5176
5180
  ?normalizeAIRequestAbort(error)
5177
5181
  :error;
@@ -5223,10 +5227,10 @@ class AI {
5223
5227
  if(signal?.aborted){
5224
5228
  throw normalizeAIRequestAbort();
5225
5229
  }
5226
- this.#finishStreamingSpeech();
5230
+ if(speech)this.#finishStreamingSpeech();
5227
5231
  return result;
5228
5232
  }catch(error){
5229
- this.stopAudio();
5233
+ if(speech)this.stopAudio();
5230
5234
  throw isAIRequestAbort(error,signal)
5231
5235
  ?normalizeAIRequestAbort(error)
5232
5236
  :error;
@@ -6026,7 +6030,8 @@ class AI {
6026
6030
  }
6027
6031
  throw error;
6028
6032
  }finally{
6029
- if(!speechTurnCompleted){
6033
+ // Provider transports leave speech lifecycle to their public caller.
6034
+ if(finishSpeech&&!speechTurnCompleted){
6030
6035
  this.stopAudio();
6031
6036
  }
6032
6037
  }
@@ -124,6 +124,7 @@ namespace Arcane.Core.Hosts.Windows
124
124
  private bool started;
125
125
  private bool documentReady;
126
126
  private bool deliveryScheduled;
127
+ private bool browserProcessExited;
127
128
  private bool closing;
128
129
  private bool closeAllowed;
129
130
 
@@ -551,11 +552,26 @@ namespace Arcane.Core.Hosts.Windows
551
552
  {
552
553
  error = new AggregateException("Reading WebView2 process-failure diagnostics failed.", error, diagnosticError);
553
554
  }
554
- // Only loss of the browser or top-level renderer ends this bridge.
555
+ if (kind == CoreWebView2ProcessFailedKind.BrowserProcessExited)
556
+ {
557
+ // WebView2 has closed this browser. Complete the owned host
558
+ // lifetime without trying to notify its vanished document.
559
+ browserProcessExited = true;
560
+ lock (stateLock)
561
+ {
562
+ if (transportFailure == null) transportFailure = error;
563
+ }
564
+ Report(error);
565
+ ready.TrySetException(error);
566
+ if (bridge != null) bridge.Stop(error);
567
+ if (activeBridge != null) activeBridge.Stop(error);
568
+ BeginClose();
569
+ return;
570
+ }
571
+ // Loss of the top-level renderer ends its bridge.
555
572
  // GPU/utility/plugin helpers recover independently; subframe loss,
556
573
  // unresponsiveness and unspecified failures remain full diagnostics.
557
- if (kind == CoreWebView2ProcessFailedKind.BrowserProcessExited
558
- || kind == CoreWebView2ProcessFailedKind.RenderProcessExited) CoreFailed(error);
574
+ if (kind == CoreWebView2ProcessFailedKind.RenderProcessExited) CoreFailed(error);
559
575
  else Report(error);
560
576
  }
561
577
 
@@ -665,7 +681,7 @@ namespace Arcane.Core.Hosts.Windows
665
681
 
666
682
  private void NotifyTransportFailure()
667
683
  {
668
- if (!documentReady || webView.CoreWebView2 == null || transportFailure == null || closing) return;
684
+ if (closing || browserProcessExited || !documentReady || webView.CoreWebView2 == null || transportFailure == null) return;
669
685
  if (failureNotifiedGeneration == generation) return;
670
686
  failureNotifiedGeneration = generation;
671
687
  Task failureNotification = NotifyTransportFailureAsync(transportFailure);
@@ -761,7 +777,7 @@ namespace Arcane.Core.Hosts.Windows
761
777
  ready.TrySetCanceled();
762
778
  try
763
779
  {
764
- if (webView.CoreWebView2 != null)
780
+ if (!browserProcessExited && webView.CoreWebView2 != null)
765
781
  {
766
782
  webView.CoreWebView2.RemoveHostObjectFromScript("arcaneBridge");
767
783
  if (injectedScript != null) webView.CoreWebView2.RemoveScriptToExecuteOnDocumentCreated(injectedScript);