arcane-os 0.34.1 → 0.34.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.34.2
4
+
5
+ - Remove temporary `persist:false` Chat cards on completion, failure,
6
+ cancellation, destruction and session replacement. Temporary input is not
7
+ restored into the composer after a rejected request.
8
+ - Track each submission's exact created cards, preserving earlier persistent
9
+ cards and newer submissions even when operation identifiers are reused.
10
+ Persistent transcript and draft behavior remain unchanged; existing saved
11
+ history is not migrated or rewritten.
12
+
3
13
  ## 0.34.1
4
14
 
5
15
  - Honor an optional request-local `model` in `AI.fetchRequest()` and
package/README.md CHANGED
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
19
19
  `arcane/` runtime. Both profiles share the theme, packaging, event, cancellation,
20
20
  and browser run contracts while retaining their selected application layout.
21
21
 
22
- This checkout defines the `0.34.1` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.34.2` SDK contract. Applications pin one exact npm
23
23
  version and lockfile; registry state is deliberately not baked into application
24
24
  artifacts.
25
25
 
@@ -413,6 +413,15 @@ the public result term; `disposition` remains an accepted input spelling.
413
413
  When a submitted turn uses `persist:false`, Chat may show its cards while that
414
414
  one operation is active, then removes them when the operation settles; neither
415
415
  the input nor response remains in the retained transcript or model context.
416
+ This cleanup also applies to failed, cancelled, detached, or replaced-session
417
+ requests. Temporary input is not restored into the composer, and a temporary
418
+ failure does not become an assistant history card. The request still rejects
419
+ normally and keeps its diagnostic/status reporting. Cleanup owns the exact
420
+ operation's nodes so a completion listener can start another turn safely.
421
+ Submission code passes those card references directly when it creates them;
422
+ reusing an operation identifier never selects earlier conversation cards for
423
+ cleanup or timestamp updates.
424
+ Persistent-turn recovery and existing saved history remain unchanged.
416
425
 
417
426
  For streaming sessions, every provisional structural card and the terminal
418
427
  result must preserve the same choice, ordered call position, exact ID, type,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.34.1",
3
+ "version": "0.34.2",
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",
@@ -86,7 +86,7 @@
86
86
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
87
87
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
88
88
  "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
89
- "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
89
+ "test:functional": "node ./bin/arcane-test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/modal.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/twin-cloud.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
90
90
  "test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
91
91
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
92
92
  "check": "node tools/check-source.mjs && npm test",
@@ -3188,15 +3188,12 @@
3188
3188
  ].includes(error?.code);
3189
3189
  }
3190
3190
 
3191
- function restoreRejectedStructuralDraft(messageId,operationId,text){
3191
+ function restoreRejectedStructuralDraft(messageId,requestMessages,text){
3192
3192
  const response=[...chatOutput.children].find(
3193
3193
  candidate=>candidate.id===`message-${messageId}`
3194
3194
  )||null;
3195
- const request=[...chatOutput.children].find(
3196
- candidate=>candidate.dataset.operationId===operationId
3197
- )||null;
3198
3195
  response?.remove();
3199
- request?.remove();
3196
+ for(const request of requestMessages) request.remove();
3200
3197
  const existing=textArea.value;
3201
3198
  if(existing!==text){
3202
3199
  textArea.value=existing
@@ -3206,14 +3203,15 @@
3206
3203
  textArea.style.height='auto';
3207
3204
  textArea.style.height=`${textArea.scrollHeight}px`;
3208
3205
  scrollTranscriptToBottom();
3209
- return Boolean(response||request);
3206
+ return Boolean(response||requestMessages.length);
3210
3207
  }
3211
3208
 
3212
3209
  async function sendMessageThroughBoundSession(
3213
3210
  text,
3214
3211
  context,
3215
3212
  sessionRequest={content:text,role:'user'},
3216
- perTurnRequest=null
3213
+ perTurnRequest=null,
3214
+ requestMessages=[]
3217
3215
  ){
3218
3216
  const session=boundChatSession;
3219
3217
  const bindingGeneration=sessionBindingGeneration;
@@ -3248,12 +3246,21 @@
3248
3246
  const streamedStructuralToolCalls=[];
3249
3247
  const messageId=`session-${++sessionMessageSequence}`;
3250
3248
  const sessionMessageToken=Symbol(messageId);
3249
+ const transientCards=retainTurn?[]:[...requestMessages];
3250
+ function removeTransientSessionCards(){
3251
+ if(!transientCards.length) return;
3252
+ // The submitter supplies only nodes created for this submission.
3253
+ for(const card of transientCards) card.remove();
3254
+ transientCards.length=0;
3255
+ scrollTranscriptToBottom();
3256
+ }
3251
3257
  activeSessionMessageToken=sessionMessageToken;
3252
3258
  sessionMessagePending=true;
3253
3259
  applyAIAvailability(host.aiAvailability);
3254
3260
  setSessionStatus('sending','AI is responding…');
3255
3261
  try{
3256
- receivedMessage(host.aiName, '', messageId);
3262
+ const responseCard=receivedMessage(host.aiName, '', messageId);
3263
+ if(!retainTurn) transientCards.push(responseCard);
3257
3264
  await streamMessage('',messageId,true);
3258
3265
  setMessageProgress(
3259
3266
  messageId,
@@ -3337,9 +3344,6 @@
3337
3344
  result.message.content,
3338
3345
  committedTurn?.response?.timestamp??result.message.timestamp
3339
3346
  );
3340
- const requestMessages=[...chatOutput.children].filter(
3341
- candidate=>candidate.dataset.operationId===context.operationId
3342
- );
3343
3347
  for(const [index,requestMessage] of requestMessages.entries()){
3344
3348
  setTranscriptMessageTimestamp(
3345
3349
  requestMessage,
@@ -3365,10 +3369,8 @@
3365
3369
  }
3366
3370
  setPendingStructuralToolCalls(terminalToolCalls);
3367
3371
  }else{
3368
- for(const requestMessage of requestMessages) requestMessage.remove();
3369
- message.remove();
3372
+ removeTransientSessionCards();
3370
3373
  setPendingStructuralToolCalls(previousPendingToolCalls);
3371
- scrollTranscriptToBottom();
3372
3374
  }
3373
3375
  setSessionStatus(
3374
3376
  pendingStructuralToolMessage?'tool':'ready',
@@ -3417,16 +3419,13 @@
3417
3419
  const response=[...chatOutput.children].find(
3418
3420
  candidate=>candidate.id===`message-${messageId}`
3419
3421
  )||null;
3420
- const requestMessages=[...chatOutput.children].filter(
3421
- candidate=>candidate.dataset.operationId===context.operationId
3422
- );
3423
3422
  response?.remove();
3424
3423
  for(const requestMessage of requestMessages){
3425
3424
  requestMessage.remove();
3426
3425
  }
3427
3426
  scrollTranscriptToBottom();
3428
- }else{
3429
- restoreRejectedStructuralDraft(messageId,context.operationId,text);
3427
+ }else if(retainTurn){
3428
+ restoreRejectedStructuralDraft(messageId,requestMessages,text);
3430
3429
  }
3431
3430
  arcaneLogging.error('Arcane structural tool protocol failure.',error);
3432
3431
  setSessionStatus(
@@ -3436,14 +3435,11 @@
3436
3435
  }else if(!destroyed&&bindingGeneration===sessionBindingGeneration){
3437
3436
  arcaneLogging.error('Arcane chat request failed.',error);
3438
3437
  if(sessionRequestMessages.every(message=>message.role==='tool')){
3439
- const requestMessages=[...chatOutput.children].filter(
3440
- candidate=>candidate.dataset.operationId===context.operationId
3441
- );
3442
3438
  for(const requestMessage of requestMessages){
3443
3439
  requestMessage.remove();
3444
3440
  }
3445
3441
  }
3446
- renderSessionMessageFailure(messageId,error);
3442
+ if(retainTurn) renderSessionMessageFailure(messageId,error);
3447
3443
  setSessionStatus(
3448
3444
  'error',
3449
3445
  visibleErrorMessage(error,'The AI request failed.')
@@ -3471,6 +3467,7 @@
3471
3467
  }
3472
3468
  throw error;
3473
3469
  }finally{
3470
+ removeTransientSessionCards();
3474
3471
  if(activeSessionMessageToken===sessionMessageToken){
3475
3472
  activeSessionMessageToken=null;
3476
3473
  sessionMessagePending=false;
@@ -3625,6 +3622,7 @@
3625
3622
  return false;
3626
3623
  }
3627
3624
  try{
3625
+ const requestMessages=[];
3628
3626
  for(const result of orderedResults){
3629
3627
  const visibleMessage=appendTranscriptMessage(
3630
3628
  'tool',
@@ -3633,12 +3631,14 @@
3633
3631
  );
3634
3632
  visibleMessage.dataset.operationId=operationId;
3635
3633
  visibleMessage.dataset.toolCallId=result.tool_call_id;
3634
+ requestMessages.push(visibleMessage);
3636
3635
  }
3637
3636
  const result=sendMessageThroughBoundSession(
3638
3637
  orderedResults.map(message=>message.content).join('\n'),
3639
3638
  eventContext,
3640
3639
  orderedResults,
3641
- perTurnRequest
3640
+ perTurnRequest,
3641
+ requestMessages
3642
3642
  );
3643
3643
  return observeHostSubmission(result,eventContext,ownership);
3644
3644
  }catch(error){
@@ -3824,6 +3824,7 @@
3824
3824
  return false;
3825
3825
  }
3826
3826
  try{
3827
+ const requestMessages=[];
3827
3828
  if(!eventContext.preserveDraft){
3828
3829
  textArea.value='';
3829
3830
  }
@@ -3834,6 +3835,7 @@
3834
3835
  hostSubmissionGeneration++;
3835
3836
  const visibleMessage=appendTranscriptMessage('user',text,host.name);
3836
3837
  visibleMessage.dataset.operationId=operationId;
3838
+ requestMessages.push(visibleMessage);
3837
3839
  }
3838
3840
  scrollTranscriptToBottom(!eventContext.synthetic);
3839
3841
 
@@ -3854,7 +3856,9 @@
3854
3856
  let result;
3855
3857
  try{
3856
3858
  result=boundChatSession
3857
- ?sendMessageThroughBoundSession(text,eventContext)
3859
+ ?sendMessageThroughBoundSession(
3860
+ text,eventContext,undefined,null,requestMessages
3861
+ )
3858
3862
  :host.sendMessage(text,eventContext);
3859
3863
  }catch(error){
3860
3864
  result=Promise.reject(error);