@jskit-ai/assistant-core 0.1.211 → 0.1.213
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/examples/conversation/package.json +5 -5
- package/package.json +5 -5
- package/src/server/conversation/claudeProcess.js +12 -2
- package/src/server/conversation/claudeTools.js +11 -2
- package/src/server/conversation/claudeTurn.js +185 -15
- package/src/server/conversation/openCodeRuntime.js +51 -4
- package/src/server/conversation/runtime.js +6 -1
- package/test/claudeConversationSession.test.js +88 -0
- package/test/claudeProcess.test.js +74 -0
- package/test/claudeTurn.test.js +435 -0
- package/test/conversationTools.test.js +53 -0
- package/test/openCodeRuntime.test.js +294 -0
|
@@ -349,3 +349,297 @@ test("native output identity is opt-in for every existing OpenCode projection wr
|
|
|
349
349
|
assert.deepEqual(native, unchanged, "The original native history is never rewritten.");
|
|
350
350
|
}
|
|
351
351
|
});
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
// Same original native owner and controlled wire fixture. These receipts are
|
|
355
|
+
// supplied by the original projection writer, not fabricated by its getter.
|
|
356
|
+
async function finalReaderMonitorFixture(t, { publication, checkpoint, recovery = false } = {}) {
|
|
357
|
+
const f = fixture();
|
|
358
|
+
const target = await f.acquire("final-owner");
|
|
359
|
+
target.upstreamSessionId = "native-final-thread";
|
|
360
|
+
const turn = { id: "accepted-input", inputMessageId: "accepted-input", threadId: target.upstreamSessionId,
|
|
361
|
+
active: true, state: "active", eventStartedAt: 1, abortController: new AbortController() };
|
|
362
|
+
const rows = [{ id: turn.id, type: "user", time: { created: 1 } }, {
|
|
363
|
+
id: recovery ? "reasoning-only" : "actual-final", type: "assistant",
|
|
364
|
+
text: recovery ? "" : "Exact accepted final.", time: { created: 2, completed: 3 }
|
|
365
|
+
}];
|
|
366
|
+
const reads = [], writes = [], publications = [], checkpoints = [], prompts = [];
|
|
367
|
+
target.server.client.messages = async (...args) => { reads.push(args); return rows; };
|
|
368
|
+
target.server.client.prompt = async (_id, input) => {
|
|
369
|
+
prompts.push(input);
|
|
370
|
+
rows.push({ id: input.id, type: "user", time: { created: 4 } }, {
|
|
371
|
+
id: "recovered-final", type: "assistant", text: "Exact recovered final.", time: { created: 5, completed: 6 }
|
|
372
|
+
});
|
|
373
|
+
return { id: input.id };
|
|
374
|
+
};
|
|
375
|
+
const projection = {
|
|
376
|
+
messageId: (id, role) => `${id}:${role}`, outputId: (id, role) => `${id}:${role}`,
|
|
377
|
+
readError: () => "", reasoning: async () => {},
|
|
378
|
+
store: {
|
|
379
|
+
async writeConversationAssistantMessage(sessionId, message) {
|
|
380
|
+
const written = { turnId: "original-authored-turn", assistant: { ...message, role: "assistant" },
|
|
381
|
+
messages: [{ ...message, role: "assistant" }] };
|
|
382
|
+
writes.push({ sessionId, message, written }); return written;
|
|
383
|
+
},
|
|
384
|
+
updateConversationStream() {}, completeConversationStreamMessage() {}
|
|
385
|
+
},
|
|
386
|
+
async publishTurn(written) { await publication?.(written); publications.push(written); },
|
|
387
|
+
publishStream: async () => {}
|
|
388
|
+
};
|
|
389
|
+
const observation = { readFailure: () => null, close: async () => {} };
|
|
390
|
+
const start = () => f.runtime.beginMonitor("final-owner", target, turn, {
|
|
391
|
+
observe: () => observation,
|
|
392
|
+
finalResponse: { agent: "selected-agent", model: { providerID: "selected-provider", id: "selected-model" },
|
|
393
|
+
recoveryMessageId: "exact-recovery-input", readError: () => "" },
|
|
394
|
+
projectMessages: (messages, options) => f.runtime.writeConversationProjection("application-session", messages, options, projection),
|
|
395
|
+
async writeRun(current, state) { checkpoints.push({ current, state }); await checkpoint?.(current, state, f.runtime); },
|
|
396
|
+
completeResult: async (_turn, { failure }) => failure,
|
|
397
|
+
onRetired() {}
|
|
398
|
+
});
|
|
399
|
+
t.after(async () => { await f.runtime.release(target); });
|
|
400
|
+
return { ...f, target, turn, rows, reads, writes, publications, checkpoints, prompts, start };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
test("native final projection opt-in returns only its original published receipt without changing default fields", async () => {
|
|
404
|
+
const runtime = createOpenCodeSharedRuntime();
|
|
405
|
+
const originalTurn = { turnId: "authored", assistant: { messageId: "real-final:assistant",
|
|
406
|
+
outputId: "real-final:assistant", role: "assistant", text: "Actual final." } };
|
|
407
|
+
const rows = [{ id: "accepted", type: "user", time: { created: 1 } },
|
|
408
|
+
{ id: "real-final", type: "assistant", text: "Actual final.", time: { created: 2, completed: 3 } },
|
|
409
|
+
{ id: "later-user", type: "user", time: { created: 4 } },
|
|
410
|
+
{ id: "foreign-final", type: "assistant", text: "Unrelated.", time: { created: 5, completed: 6 } }];
|
|
411
|
+
const nativeBefore = structuredClone(rows);
|
|
412
|
+
const publications = [];
|
|
413
|
+
const projection = { messageId: (id, role) => `${id}:${role}`, outputId: (id, role) => `${id}:${role}`,
|
|
414
|
+
readError: () => "", reasoning: async () => {}, store: {
|
|
415
|
+
async writeConversationAssistantMessage(_id, message) {
|
|
416
|
+
assert.equal(message.messageId, "real-final:assistant"); return originalTurn;
|
|
417
|
+
}, completeConversationStreamMessage() {}, updateConversationStream() {}
|
|
418
|
+
}, publishTurn: async turn => { publications.push(turn); }, publishStream: async () => {} };
|
|
419
|
+
assert.deepEqual(await runtime.writeConversationProjection("application", rows, { inputMessageId: "accepted" }, projection),
|
|
420
|
+
{ failure: "", providerApiFailure: false });
|
|
421
|
+
const result = await runtime.writeConversationProjection("application", rows,
|
|
422
|
+
{ inputMessageId: "accepted", captureFinalAssistantResult: true }, projection);
|
|
423
|
+
assert.deepEqual(result.finalAssistantResult, { inputMessageId: "accepted", itemId: "real-final",
|
|
424
|
+
text: "Actual final.", conversationTurn: originalTurn });
|
|
425
|
+
assert.equal(result.finalAssistantResult.conversationTurn, publications.at(-1));
|
|
426
|
+
assert.deepEqual(rows, nativeBefore, "The original native rows are never rewritten.");
|
|
427
|
+
const streaming = await runtime.writeConversationProjection("application", rows,
|
|
428
|
+
{ inputMessageId: "accepted", streaming: true, captureFinalAssistantResult: true }, projection);
|
|
429
|
+
assert.equal(streaming.finalAssistantResult, null, "A partial projection never claims a native final receipt.");
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("retained final reader is exact, readonly and available at the original completed checkpoint after publication", async t => {
|
|
433
|
+
const publishing = Promise.withResolvers(), release = Promise.withResolvers();
|
|
434
|
+
let checkpointResult;
|
|
435
|
+
const f = await finalReaderMonitorFixture(t, {
|
|
436
|
+
async publication() { publishing.resolve(); await release.promise; },
|
|
437
|
+
checkpoint(turn, state, owner) {
|
|
438
|
+
if (state === "completed") checkpointResult = owner.readFinalAssistantResult("final-owner", turn.threadId, turn.id);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
const monitor = f.start();
|
|
442
|
+
await publishing.promise;
|
|
443
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
444
|
+
release.resolve(); await monitor;
|
|
445
|
+
assert.equal(checkpointResult.threadId, f.turn.threadId);
|
|
446
|
+
assert.equal(checkpointResult.turnId, "accepted-input");
|
|
447
|
+
assert.equal(checkpointResult.itemId, "actual-final");
|
|
448
|
+
assert.deepEqual(checkpointResult.conversationTurn, f.writes.at(-1).written);
|
|
449
|
+
assert.equal(f.publications.length, 1);
|
|
450
|
+
assert.equal(f.runtime.readFinalAssistantResult("foreign-owner", f.turn.threadId, f.turn.id), null);
|
|
451
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", "foreign-thread", f.turn.id), null);
|
|
452
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, "actual-final"), null);
|
|
453
|
+
const count = f.reads.length;
|
|
454
|
+
checkpointResult.conversationTurn.assistant.text = "Caller mutation";
|
|
455
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id).text, "Exact accepted final.");
|
|
456
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id).conversationTurn.assistant.text, "Exact accepted final.");
|
|
457
|
+
assert.equal(f.reads.length, count, "Getter performs no history read, observer or model work.");
|
|
458
|
+
f.runtime.turns.delete("final-owner");
|
|
459
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
for (const boundary of ["publication-failure", "confirmed-stop"]) {
|
|
463
|
+
test(`retained final evidence stays unavailable after ${boundary}`, async t => {
|
|
464
|
+
const publishing = Promise.withResolvers(), release = Promise.withResolvers();
|
|
465
|
+
const f = await finalReaderMonitorFixture(t, { async publication() {
|
|
466
|
+
publishing.resolve(); await release.promise;
|
|
467
|
+
if (boundary === "publication-failure") throw new Error("Original publication failed.");
|
|
468
|
+
} });
|
|
469
|
+
const monitor = f.start(); await publishing.promise;
|
|
470
|
+
let stopping;
|
|
471
|
+
if (boundary === "confirmed-stop") {
|
|
472
|
+
stopping = f.runtime.interruptTurn("final-owner", f.target, { writeRun: async () => {} });
|
|
473
|
+
for (let index = 0; index < 10 && !f.turn.interruptAcknowledged; index += 1) await Promise.resolve();
|
|
474
|
+
assert.equal(f.turn.interruptAcknowledged, true);
|
|
475
|
+
}
|
|
476
|
+
release.resolve(); await monitor; await stopping;
|
|
477
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
478
|
+
assert.equal(f.turn.state, boundary === "confirmed-stop" ? "interrupted" : "failed");
|
|
479
|
+
assert.equal(f.prompts.length, 0, "Failure and Stop do not dispatch recovery or repeat native work.");
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
test("empty-answer recovery final retains the accepted outer turn and exact recovered native carrier", async t => {
|
|
484
|
+
const f = await finalReaderMonitorFixture(t, { recovery: true });
|
|
485
|
+
await f.start();
|
|
486
|
+
const result = f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, "accepted-input");
|
|
487
|
+
assert.equal(f.prompts.length, 1);
|
|
488
|
+
assert.equal(f.prompts[0].id, "exact-recovery-input");
|
|
489
|
+
assert.equal(result.turnId, "accepted-input");
|
|
490
|
+
assert.equal(result.inputMessageId, "exact-recovery-input");
|
|
491
|
+
assert.equal(result.itemId, "recovered-final");
|
|
492
|
+
assert.equal(result.text, "Exact recovered final.");
|
|
493
|
+
assert.deepEqual(result.conversationTurn, f.writes.at(-1).written);
|
|
494
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, "exact-recovery-input"), null);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
test("final reader follows the original post-publication admission and current-input fence", async t => {
|
|
499
|
+
const publishing = Promise.withResolvers(), release = Promise.withResolvers();
|
|
500
|
+
let first = true;
|
|
501
|
+
const f = await finalReaderMonitorFixture(t, { async publication() {
|
|
502
|
+
if (first) { first = false; publishing.resolve(); await release.promise; }
|
|
503
|
+
} });
|
|
504
|
+
const monitor = f.start(); await publishing.promise;
|
|
505
|
+
const admission = Promise.withResolvers();
|
|
506
|
+
f.turn.admission = admission;
|
|
507
|
+
f.turn.inputMessageId = "latest-accepted-input";
|
|
508
|
+
f.rows.push({ id: "latest-accepted-input", type: "user", time: { created: 4 } },
|
|
509
|
+
{ id: "latest-native-final", type: "assistant", text: "Latest admitted final.", time: { created: 5, completed: 6 } });
|
|
510
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
511
|
+
admission.resolve(); release.resolve(); await monitor;
|
|
512
|
+
const result = f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, "accepted-input");
|
|
513
|
+
assert.equal(result.inputMessageId, "latest-accepted-input");
|
|
514
|
+
assert.equal(result.itemId, "latest-native-final");
|
|
515
|
+
assert.equal(result.text, "Latest admitted final.");
|
|
516
|
+
assert.deepEqual(result.conversationTurn, f.writes.at(-1).written);
|
|
517
|
+
assert.equal(f.prompts.length, 0, "Following an admitted input never resends it or creates a recovery prompt.");
|
|
518
|
+
f.turn.inputMessageId = "another-input";
|
|
519
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null,
|
|
520
|
+
"A retained receipt cannot stand for a different current input.");
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
test("original release and same-key reacquisition cannot reattach a retained final receipt", async t => {
|
|
525
|
+
const f = await finalReaderMonitorFixture(t);
|
|
526
|
+
await f.start();
|
|
527
|
+
assert.ok(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id));
|
|
528
|
+
const peer = await f.acquire("final-peer");
|
|
529
|
+
await f.runtime.release(f.target, { retainSharedProcess: true });
|
|
530
|
+
assert.equal(f.runtime.turns.get("final-owner"), f.turn,
|
|
531
|
+
"Original release retains the completed turn; getter must enforce the actual target owner.");
|
|
532
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
533
|
+
const replacement = await f.acquire("final-owner");
|
|
534
|
+
replacement.upstreamSessionId = f.turn.threadId;
|
|
535
|
+
t.after(async () => { await f.runtime.release(replacement); await f.runtime.release(peer); });
|
|
536
|
+
assert.notEqual(replacement, f.target);
|
|
537
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null,
|
|
538
|
+
"Even an identical key and native thread cannot reuse the released target's receipt.");
|
|
539
|
+
assert.equal(f.starts.length, 1, "The independent peer and replacement share the original process.");
|
|
540
|
+
assert.equal(f.stops.length, 0);
|
|
541
|
+
assert.equal(peer.abortController.signal.aborted, false);
|
|
542
|
+
assert.equal(f.prompts.length, 0, "Getter performs no model work after release or reacquisition.");
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
test("original shared-server replacement cannot retag the retained target's final receipt", async t => {
|
|
546
|
+
const f = await finalReaderMonitorFixture(t);
|
|
547
|
+
await f.start();
|
|
548
|
+
const result = f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id);
|
|
549
|
+
assert.ok(result);
|
|
550
|
+
assert.equal(Object.hasOwn(result, "target"), false);
|
|
551
|
+
assert.equal(Object.hasOwn(result, "server"), false);
|
|
552
|
+
const count = f.reads.length;
|
|
553
|
+
const peer = await f.acquire("final-peer", { selected: { ...f.connection, fingerprint: "replacement-account" } });
|
|
554
|
+
t.after(async () => { await f.runtime.release(peer); });
|
|
555
|
+
assert.equal(f.runtime.processes.get("final-owner"), f.target,
|
|
556
|
+
"Original ensure replaces the server while retaining target identity.");
|
|
557
|
+
assert.equal(f.target.upstreamSessionId, f.turn.threadId);
|
|
558
|
+
assert.equal(f.target.abortController.signal.aborted, false);
|
|
559
|
+
assert.equal(f.starts.length, 2);
|
|
560
|
+
assert.equal(f.stops.length, 1);
|
|
561
|
+
assert.equal(f.runtime.readFinalAssistantResult("final-owner", f.turn.threadId, f.turn.id), null);
|
|
562
|
+
assert.equal(f.reads.length, count, "A refused read cannot recover history from the replacement process.");
|
|
563
|
+
assert.equal(f.prompts.length, 0);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
test("original message monitor clone retains only its registered target's final receipt", async t => {
|
|
568
|
+
const f = fixture();
|
|
569
|
+
const owned = [];
|
|
570
|
+
t.after(async () => { for (const target of owned) await f.runtime.release(target); });
|
|
571
|
+
let expectedTarget = await f.acquire("cloned-final-owner");
|
|
572
|
+
owned.push(expectedTarget);
|
|
573
|
+
expectedTarget.upstreamSessionId = "cloned-native-thread";
|
|
574
|
+
const originalTarget = expectedTarget;
|
|
575
|
+
const snapshots = [], writes = [], errors = [];
|
|
576
|
+
let modelPrompts = 0;
|
|
577
|
+
function prepareMessages(target, inputId, itemId, text) {
|
|
578
|
+
target.server.client.messages = async () => [{ id: inputId, type: "user", time: { created: 1 } },
|
|
579
|
+
{ id: itemId, type: "assistant", text, time: { created: 2, completed: 3 } }];
|
|
580
|
+
target.server.client.prompt = async () => { modelPrompts += 1; assert.fail("An admitted final read cannot submit model work."); };
|
|
581
|
+
}
|
|
582
|
+
const projection = {
|
|
583
|
+
prepare() { return { fields: {} }; },
|
|
584
|
+
create(snapshot, turn) {
|
|
585
|
+
snapshots.push(snapshot);
|
|
586
|
+
assert.notEqual(snapshot, expectedTarget, "Preserve the ORIGINAL shallow monitor snapshot.");
|
|
587
|
+
assert.equal(snapshot.abortController, expectedTarget.abortController);
|
|
588
|
+
assert.equal(snapshot.server, expectedTarget.server);
|
|
589
|
+
assert.equal(snapshot.upstreamSessionId, expectedTarget.upstreamSessionId);
|
|
590
|
+
return {
|
|
591
|
+
observe: () => ({ readFailure: () => null, close: async () => {} }),
|
|
592
|
+
finalResponse: { readError: () => "" },
|
|
593
|
+
projectMessages: (messages, options) => f.runtime.writeConversationProjection("saved-session", messages, options, {
|
|
594
|
+
messageId: (id, role) => `${id}:${role}`, outputId: (id, role) => `${id}:${role}`,
|
|
595
|
+
readError: () => "", reasoning: async () => {}, store: {
|
|
596
|
+
async writeConversationAssistantMessage(_id, message) {
|
|
597
|
+
const written = { turnId: turn.id, assistant: { ...message, role: "assistant" } };
|
|
598
|
+
writes.push(written); return written;
|
|
599
|
+
}, updateConversationStream() {}, completeConversationStreamMessage() {}
|
|
600
|
+
}, publishTurn: async () => {}, publishStream: async () => {}
|
|
601
|
+
}),
|
|
602
|
+
writeRun: async () => {}, completeResult: async (_turn, { failure }) => failure, onRetired() {}
|
|
603
|
+
};
|
|
604
|
+
},
|
|
605
|
+
onError(error) { errors.push(error); }
|
|
606
|
+
};
|
|
607
|
+
prepareMessages(expectedTarget, "clone-input", "clone-final", "Exact cloned monitor final.");
|
|
608
|
+
await f.runtime.beginMessageMonitor("cloned-final-owner", expectedTarget,
|
|
609
|
+
{ id: "clone-input", eventStartedAt: 1 }, {}, projection);
|
|
610
|
+
const result = f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "clone-input");
|
|
611
|
+
assert.ok(result, "Original beginMessageMonitor must expose the actual published receipt despite its target snapshot.");
|
|
612
|
+
assert.deepEqual(result.conversationTurn, writes.at(-1));
|
|
613
|
+
assert.equal(f.runtime.turns.get("cloned-final-owner").finalAssistantResultTarget, originalTarget);
|
|
614
|
+
assert.notEqual(f.runtime.turns.get("cloned-final-owner").finalAssistantResultTarget, snapshots[0]);
|
|
615
|
+
assert.equal(Object.hasOwn(result, "finalAssistantResultTarget"), false);
|
|
616
|
+
assert.equal(Object.hasOwn(f.runtime.turnSnapshot(f.runtime.turns.get("cloned-final-owner")), "finalAssistantResultTarget"), false);
|
|
617
|
+
const peer = await f.acquire("cloned-final-peer"); owned.push(peer);
|
|
618
|
+
await f.runtime.release(originalTarget, { retainSharedProcess: true });
|
|
619
|
+
assert.equal(f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "clone-input"), null);
|
|
620
|
+
expectedTarget = await f.acquire("cloned-final-owner"); owned.push(expectedTarget);
|
|
621
|
+
expectedTarget.upstreamSessionId = "cloned-native-thread";
|
|
622
|
+
assert.notEqual(expectedTarget, originalTarget);
|
|
623
|
+
assert.equal(f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "clone-input"), null);
|
|
624
|
+
assert.equal(peer.abortController.signal.aborted, false);
|
|
625
|
+
assert.equal(f.starts.length, 1);
|
|
626
|
+
assert.equal(f.stops.length, 0);
|
|
627
|
+
prepareMessages(expectedTarget, "fresh-clone-input", "fresh-clone-final", "Exact new owner final.");
|
|
628
|
+
await f.runtime.beginMessageMonitor("cloned-final-owner", expectedTarget,
|
|
629
|
+
{ id: "fresh-clone-input", eventStartedAt: 1 }, {}, projection);
|
|
630
|
+
const current = f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "fresh-clone-input");
|
|
631
|
+
assert.ok(current, "A newly admitted original cloned monitor uses only its own registered owner.");
|
|
632
|
+
assert.equal(current.itemId, "fresh-clone-final");
|
|
633
|
+
assert.equal(current.text, "Exact new owner final.");
|
|
634
|
+
assert.equal(f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "clone-input"), null);
|
|
635
|
+
const refreshPeer = await f.acquire("cloned-refresh-peer", { selected: { ...f.connection, fingerprint: "refreshed-account" } });
|
|
636
|
+
owned.push(refreshPeer);
|
|
637
|
+
assert.equal(f.runtime.processes.get("cloned-final-owner"), expectedTarget);
|
|
638
|
+
assert.equal(expectedTarget.abortController.signal.aborted, false);
|
|
639
|
+
assert.equal(f.runtime.readFinalAssistantResult("cloned-final-owner", "cloned-native-thread", "fresh-clone-input"), null,
|
|
640
|
+
"Original shared process replacement cannot reattach the cloned monitor's receipt.");
|
|
641
|
+
assert.equal(f.starts.length, 2);
|
|
642
|
+
assert.equal(f.stops.length, 1);
|
|
643
|
+
assert.equal(modelPrompts, 0);
|
|
644
|
+
assert.deepEqual(errors, []);
|
|
645
|
+
});
|